structdyn 0.5.1__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.
Files changed (63) hide show
  1. docs/source/conf.py +37 -0
  2. examples/__init__.py +0 -0
  3. examples/mdf/__init__.py +0 -0
  4. examples/mdf/eg1_mdf.py +21 -0
  5. examples/mdf/eg2_mdf.py +26 -0
  6. examples/mdf/eg_cdm.py +19 -0
  7. examples/mdf/eg_damping_mat.py +14 -0
  8. examples/mdf/eg_newmark.py +18 -0
  9. examples/mdf/eg_newmark_gm.py +32 -0
  10. examples/sdf/__init__.py +0 -0
  11. examples/sdf/eg_analytical.py +18 -0
  12. examples/sdf/eg_cdm.py +23 -0
  13. examples/sdf/eg_el_centro.py +21 -0
  14. examples/sdf/eg_ground_motion.py +24 -0
  15. examples/sdf/eg_interpolation.py +21 -0
  16. examples/sdf/eg_newmark.py +19 -0
  17. examples/sdf/eg_newmark_non_linear.py +19 -0
  18. examples/sdf/eg_res_spec_el_centro.py +19 -0
  19. structdyn/__init__.py +23 -0
  20. structdyn/ground_motions/__init__.py +3 -0
  21. structdyn/ground_motions/data/elcentro_chopra.csv +1561 -0
  22. structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC-UP.AT2 +1080 -0
  23. structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC180-hor1.AT2 +1079 -0
  24. structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC270-hor2.AT2 +1074 -0
  25. structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS-UP.AT2 +1604 -0
  26. structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS000-hor1.AT2 +1604 -0
  27. structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS090-hor2.AT2 +1604 -0
  28. structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL-UP.AT2 +204 -0
  29. structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL090-hor1.AT2 +204 -0
  30. structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL360-hor2.AT2 +204 -0
  31. structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PUL164-hor1.AT2 +839 -0
  32. structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PUL254-hor2.AT2 +839 -0
  33. structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PULDWN-up.AT2 +839 -0
  34. structdyn/ground_motions/ground_motion.py +174 -0
  35. structdyn/mdf/__init__.py +2 -0
  36. structdyn/mdf/analytical_methods/__init__.py +1 -0
  37. structdyn/mdf/analytical_methods/modal_analysis.py +213 -0
  38. structdyn/mdf/analytical_methods/modal_superposition.py +0 -0
  39. structdyn/mdf/mdf.py +216 -0
  40. structdyn/mdf/mdf_helpers/__init__.py +1 -0
  41. structdyn/mdf/mdf_helpers/builders.py +45 -0
  42. structdyn/mdf/numerical_methods/__init__.py +1 -0
  43. structdyn/mdf/numerical_methods/central_difference.py +231 -0
  44. structdyn/mdf/numerical_methods/newmark_beta.py +258 -0
  45. structdyn/sdf/__init__.py +0 -0
  46. structdyn/sdf/analytical_methods/__init__.py +0 -0
  47. structdyn/sdf/analytical_methods/analytical_response.py +161 -0
  48. structdyn/sdf/numerical_methods/__init__.py +1 -0
  49. structdyn/sdf/numerical_methods/central_difference.py +123 -0
  50. structdyn/sdf/numerical_methods/interpolation.py +140 -0
  51. structdyn/sdf/numerical_methods/newmark_beta.py +311 -0
  52. structdyn/sdf/response_spectrum.py +99 -0
  53. structdyn/sdf/sdf.py +127 -0
  54. structdyn/utils/__init__.py +1 -0
  55. structdyn/utils/helpers.py +118 -0
  56. structdyn-0.5.1.dist-info/METADATA +237 -0
  57. structdyn-0.5.1.dist-info/RECORD +63 -0
  58. structdyn-0.5.1.dist-info/WHEEL +5 -0
  59. structdyn-0.5.1.dist-info/licenses/LICENSE +21 -0
  60. structdyn-0.5.1.dist-info/top_level.txt +4 -0
  61. trash/eg_fdef.py +37 -0
  62. trash/gm_helper.py +69 -0
  63. trash/setup.py +21 -0
docs/source/conf.py ADDED
@@ -0,0 +1,37 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # For the full list of built-in configuration values, see the documentation:
4
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
5
+
6
+ # -- Project information -----------------------------------------------------
7
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8
+ import os
9
+ import sys
10
+
11
+ sys.path.insert(0, os.path.abspath("../../"))
12
+
13
+ project = "structdyn"
14
+ copyright = "2026, Abinash Mandal"
15
+ author = "Abinash Mandal"
16
+ release = "0.1.0"
17
+
18
+ # -- General configuration ---------------------------------------------------
19
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
20
+
21
+ extensions = [
22
+ "sphinx.ext.autodoc",
23
+ "sphinx.ext.napoleon", # for NumPy-style docstrings
24
+ "sphinx.ext.viewcode",
25
+ ]
26
+
27
+
28
+ templates_path = ["_templates"]
29
+ exclude_patterns = []
30
+
31
+
32
+ # -- Options for HTML output -------------------------------------------------
33
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
34
+
35
+ html_theme = "sphinx_rtd_theme"
36
+
37
+ html_static_path = ["_static"]
examples/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,21 @@
1
+ # Example 10.4; Chopra A. K., Dynamics of structure, 5th edn
2
+ import numpy as np
3
+ from structdyn.mdf.mdf import MDF
4
+
5
+ # Define mdf system: 2-story shear building
6
+ masses = [2, 1]
7
+ stiffness = [2, 1]
8
+ mdf = MDF.from_shear_building(masses, stiffness)
9
+ # print(mdf.M, mdf.K)
10
+
11
+ # Modal analysis
12
+ omega, phi = mdf.modal.modal_analysis(
13
+ dof_normalize=-1
14
+ ) # -1 means: mode shape normalized based on roof dof
15
+
16
+ print("Natural Frequencies (rad/s):", omega) # omegas = [0.70710678 1.41421356]
17
+ print("Mode shapes:", phi)
18
+
19
+ # u = np.array([1, 1])
20
+ # qn = mdf.modal.modal_coordinates(u)
21
+ # print("Modal coordinates:", qn)
@@ -0,0 +1,26 @@
1
+ # Example 10.9; Chopra A. K., Dynamics of structure, 5th edn
2
+ import numpy as np
3
+ from structdyn.mdf.mdf import MDF
4
+ import matplotlib.pyplot as plt
5
+
6
+ # Define mdf mdf: 2-story shear building
7
+ masses = [2, 1]
8
+ stiffness = [2, 1]
9
+ mdf = MDF.from_shear_building(masses, stiffness)
10
+
11
+ # Modal analysis
12
+ omega, phi = mdf.modal.modal_analysis(
13
+ dof_normalize=-1
14
+ ) # -1 means: mode shape normalized based on roof dof
15
+
16
+ # Initial conditions
17
+ u0 = [0.5, 1]
18
+ v0 = [0, 0]
19
+ time = np.arange(0, 20, 0.01)
20
+
21
+ # Run analysis
22
+ response = mdf.modal.free_vibration_response(u0, v0, time)
23
+ print(response["u1"].abs().max()) # result = 0.49999999999999994
24
+
25
+ response.plot(x="time", y="u1")
26
+ plt.show()
examples/mdf/eg_cdm.py ADDED
@@ -0,0 +1,19 @@
1
+ import numpy as np
2
+ from structdyn.mdf.mdf import MDF
3
+ import matplotlib.pyplot as plt
4
+
5
+ # Define MDF system
6
+ masses = [2 * 45594, 45594]
7
+ stiffness = [2 * 18 * 10**5, 18 * 10**5]
8
+ mdf = MDF.from_shear_building(masses, stiffness)
9
+
10
+ # Define external load
11
+ dt = 0.01
12
+ time = np.arange(0, 1.01, dt)
13
+ load = 50 * np.sin(np.pi * time / 0.6) * 1000
14
+ load[time >= 0.6] = 0
15
+ load = np.column_stack((load, np.zeros_like(load)))
16
+
17
+ res = mdf.find_response(time, load)
18
+ print(res)
19
+ print(res.shape)
@@ -0,0 +1,14 @@
1
+ # Example 11.4; Chopra A. K., Dynamics of structure, 5th edn
2
+ from structdyn.mdf.mdf import MDF
3
+
4
+ # Define MDF system
5
+ masses = [2e5, 2e5, 1e5]
6
+ stiffness = [1e8, 1e8, 1e8]
7
+ mdf = MDF.from_shear_building(masses, stiffness)
8
+
9
+ # Create damping matrix based on modal damping ratios; zeta
10
+ mdf.set_modal_damping(zeta=[0.05, 0.05, 0.05])
11
+
12
+ # Damping matrix
13
+ print(mdf.C)
14
+ print(mdf.C.flatten()[-1]) # result = 287983.44117400126
@@ -0,0 +1,18 @@
1
+ import numpy as np
2
+ from structdyn.mdf.mdf import MDF
3
+ import matplotlib.pyplot as plt
4
+
5
+ # Define MDF system
6
+ masses = [2 * 45594, 45594]
7
+ stiffness = [2 * 18 * 10**5, 18 * 10**5]
8
+ mdf = MDF.from_shear_building(masses, stiffness)
9
+
10
+ # Define external load
11
+ dt = 0.01
12
+ time = np.arange(0, 1.01, dt)
13
+ load = 50 * np.sin(np.pi * time / 0.6) * 1000
14
+ load[time >= 0.6] = 0
15
+ load = np.column_stack((load, np.zeros_like(load)))
16
+
17
+ res = mdf.find_response(time, load, method="newmark_beta")
18
+ print(res)
@@ -0,0 +1,32 @@
1
+ # Example 16.1; Chopra A. K., Dynamics of structure, 5th edn
2
+ import numpy as np
3
+ from structdyn.mdf.mdf import MDF
4
+ import matplotlib.pyplot as plt
5
+ from structdyn.ground_motions.ground_motion import GroundMotion
6
+
7
+ # Define MDF system
8
+ masses = np.ones(5) * 0.2591 * 1e5
9
+ stiffness = np.ones(5) * 100 * 1e5
10
+ mdf = MDF.from_shear_building(masses, stiffness)
11
+ mdf.set_modal_damping(zeta=np.ones(5) * 0.05) # set damping matrix
12
+
13
+ # Define ground motion as given in the same example
14
+ time = np.arange(0, 2.01, 0.1)
15
+ acc = (1.93 / 9.81) * np.sin(2 * np.pi * time)
16
+ acc[time > 1.0] = 0
17
+ gm = GroundMotion.from_arrays(acc, 0.1)
18
+
19
+ # Influence vector
20
+ inf_vec = np.ones(5)
21
+
22
+ # Run analysis
23
+ response = mdf.find_response_ground_motion(
24
+ gm, inf_vec, method="newmark_beta", use_modal=True, n_modes=2
25
+ )
26
+ # Note we can get more accurate results by considering more modes. Also if we remove use_modal, then direct integration of coupled equations would give more accurate results.
27
+ print(response)
28
+ print(response["u5"][20]) # result = 0.05888401249961952
29
+
30
+ # Plot response
31
+ # res.plot(x="time", y="u5")
32
+ # plt.show()
File without changes
@@ -0,0 +1,18 @@
1
+ from structdyn import SDF
2
+ import matplotlib.pyplot as plt
3
+ from structdyn.sdf.analytical_methods.analytical_response import AnalyticalResponse
4
+
5
+ # Create SDF object
6
+ sdf = SDF(m=1.0, k=100.0, ji=0.05)
7
+ analytical = AnalyticalResponse(sdf) # analytical solver
8
+
9
+ # Free vibration
10
+ df_free = analytical.free_vibration(u0=0.01, v0=0.0)
11
+ # print(df_free)
12
+ df_free.plot(x="time", y="displacement")
13
+ plt.show()
14
+
15
+ # Harmonic sine forcing
16
+ df_harm = analytical.harmonic_response(p0=10.0, w=5.0, excitation="sine")
17
+ df_harm.plot(x="time", y="displacement")
18
+ plt.show()
examples/sdf/eg_cdm.py ADDED
@@ -0,0 +1,23 @@
1
+ # Example 5.2; Chopra A. K., Dynamics of structure, 5th edn
2
+ from structdyn import SDF
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+
6
+ # Define external load
7
+ dt = 0.1
8
+ time_steps = np.arange(0, 1.01, dt)
9
+ load_values = 50 * np.sin(np.pi * time_steps / 0.6) * 1000
10
+ load_values[time_steps >= 0.6] = 0
11
+
12
+ # Create SDF object
13
+ sdf = SDF(45594, 18 * 10**5, 0.05)
14
+ # sdf = SDF(45594, 18 * 10**5, 0.05, fd="elastoplastic", uy=0.02, fy=36000) #for non-linear analysis
15
+
16
+ # Analysis
17
+ responses = sdf.find_response(
18
+ time_steps,
19
+ load_values,
20
+ method="central_difference",
21
+ )
22
+ print(responses)
23
+ print(responses["displacement"][10]) # result is -0.03812718853606678
@@ -0,0 +1,21 @@
1
+ # Section 6.4 (& Figure 6.4.1a); Chopra A. K., Dynamics of structure, 5th edn
2
+ from structdyn import SDF
3
+ import numpy as np
4
+ from structdyn.ground_motions.ground_motion import GroundMotion
5
+ from structdyn.utils.helpers import elcentro_chopra
6
+
7
+ # Define el centro ground motion from Chopra's book- Appendix 6
8
+ elc = elcentro_chopra()
9
+ gm = GroundMotion.from_arrays(elc["acc (g)"], 0.02)
10
+
11
+ # Create SDF object
12
+ m = 1
13
+ ji = 0.02
14
+ t_n = 0.5
15
+ w_n = 2 * np.pi / t_n
16
+ k = w_n**2 * m
17
+ sdf = SDF(m, k, ji)
18
+
19
+ # Analysis
20
+ results = sdf.find_response_ground_motion(gm, method="interpolation")
21
+ print(results["displacement"].abs().max()) # result is 0.0679400697200714
@@ -0,0 +1,24 @@
1
+ import numpy as np
2
+ from structdyn.ground_motions.ground_motion import GroundMotion
3
+ from structdyn.utils.helpers import elcentro_chopra
4
+ from pathlib import Path
5
+
6
+ # Method 1: directly from Chopra's book- Appendix 6
7
+ elc = elcentro_chopra()
8
+ gm = GroundMotion.from_arrays(elc["acc (g)"], 0.02)
9
+ print(gm.to_dataframe())
10
+
11
+ # Method 2: from numpy arrays
12
+ dt = 0.01
13
+ time = np.arange(0, 2.01, dt)
14
+ acc = (1.93 / 9.81) * np.sin(2 * np.pi * time)
15
+ gm = GroundMotion.from_arrays(acc, dt)
16
+ print(gm.to_dataframe())
17
+
18
+ # Method 3: from event (in-built PEER database)
19
+ gm = GroundMotion.from_event("northridge_sylmar_1994", component="hor1")
20
+ print(gm.to_dataframe())
21
+
22
+ # Method 4: from .at2 file (PEER database format)
23
+ # file_path = "path to your file"
24
+ # gm = GroundMotion.from_at2(file_path)
@@ -0,0 +1,21 @@
1
+ # Example 5.1; Chopra A. K., Dynamics of structure, 5th edn
2
+ from structdyn import SDF
3
+ import numpy as np
4
+
5
+ # Define external load
6
+ dt = 0.1
7
+ time_steps = np.arange(0, 1.01, dt)
8
+ load_values = 50 * np.sin(np.pi * time_steps / 0.6) * 1000
9
+ load_values[time_steps >= 0.6] = 0
10
+
11
+ # Create SDF object
12
+ sdf = SDF(45594, 18 * 10**5, 0.05)
13
+
14
+ # Run analysis
15
+ responses = sdf.find_response(
16
+ time_steps,
17
+ load_values,
18
+ method="interpolation",
19
+ )
20
+ print(responses)
21
+ print(responses["displacement"][10]) # result is -0.034534260954800985
@@ -0,0 +1,19 @@
1
+ # Example 5.4; Chopra A. K., Dynamics of structure, 5th edn
2
+ from structdyn import SDF
3
+ import numpy as np
4
+
5
+ # Define external load
6
+ dt = 0.1
7
+ time_steps = np.arange(0, 1.01, dt)
8
+ load_values = 50 * np.sin(np.pi * time_steps / 0.6) * 1000
9
+ load_values[time_steps >= 0.6] = 0
10
+
11
+ # Create SDF object
12
+ sdf = SDF(45594, 18 * 10**5, 0.05)
13
+
14
+ # Analysis
15
+ responses = sdf.find_response(
16
+ time_steps, load_values, method="newmark_beta", acc_type="linear"
17
+ )
18
+ print(responses)
19
+ print(responses["displacement"][10]) # result is -0.03391195470077432
@@ -0,0 +1,19 @@
1
+ # Example 5.5; Chopra A. K., Dynamics of structure, 5th edn
2
+ from structdyn import SDF
3
+ import numpy as np
4
+
5
+ # Define external load
6
+ dt = 0.1
7
+ time_steps = np.arange(0, 1.01, dt)
8
+ load_values = 50 * np.sin(np.pi * time_steps / 0.6) * 1000
9
+ load_values[time_steps >= 0.6] = 0
10
+
11
+ # Create SDF object
12
+ sdf = SDF(45594, 18 * 10**5, 0.05, fd="elastoplastic", uy=0.02, fy=36000)
13
+
14
+ # Analysis
15
+ responses = sdf.find_response(
16
+ time_steps, load_values, method="newmark_beta", acc_type="average"
17
+ )
18
+ print(responses)
19
+ print(responses["displacement"][10]) # result is 0.03606328101158249
@@ -0,0 +1,19 @@
1
+ # Section 6.4 (& Figure 6.6.2); Chopra A. K., Dynamics of structure, 5th edn
2
+ import numpy as np
3
+ from structdyn.ground_motions.ground_motion import GroundMotion
4
+ from structdyn.sdf.response_spectrum import ResponseSpectrum
5
+ from structdyn.utils.helpers import elcentro_chopra
6
+
7
+ # Define el centro ground motion from Chopra's book- Appendix 6
8
+ elc = elcentro_chopra()
9
+ gm = GroundMotion.from_arrays(elc["acc (g)"], 0.02)
10
+
11
+ # Define the period range of interest
12
+ periods = np.arange(0, 5.01, 0.1)
13
+
14
+ # Create response spectrum object
15
+ rs = ResponseSpectrum(periods, 0.02, gm)
16
+
17
+ # Analysis
18
+ spectra = rs.compute()
19
+ print(spectra["Sd"][20]) # result is 0.1896749378231744
structdyn/__init__.py ADDED
@@ -0,0 +1,23 @@
1
+ """
2
+ structdyn: A Python library for solving structural dynamics problems numerically.
3
+
4
+ Author: Abinash Mandal
5
+
6
+ """
7
+
8
+ from .sdf.sdf import SDF
9
+ from .sdf.numerical_methods.central_difference import CentralDifference
10
+ from .sdf.numerical_methods.interpolation import Interpolation
11
+ from .sdf.numerical_methods.newmark_beta import NewmarkBeta
12
+ from .utils.helpers import plot_displacement, elcentro_chopra
13
+ from .sdf.analytical_methods.analytical_response import AnalyticalResponse
14
+
15
+ __all__ = [
16
+ "SDF",
17
+ "CentralDifference",
18
+ "Interpolation",
19
+ "NewmarkBeta",
20
+ "AnalyticalResponse",
21
+ "plot_displacement",
22
+ "elcentro_chopra",
23
+ ]
@@ -0,0 +1,3 @@
1
+ from .ground_motion import GroundMotion
2
+
3
+ __all__ = ["GroundMotion"]