structdyn 0.5.1__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 (71) hide show
  1. structdyn-0.5.1/LICENSE +21 -0
  2. structdyn-0.5.1/MANIFEST.in +3 -0
  3. structdyn-0.5.1/PKG-INFO +237 -0
  4. structdyn-0.5.1/README.md +220 -0
  5. structdyn-0.5.1/docs/source/conf.py +37 -0
  6. structdyn-0.5.1/examples/__init__.py +0 -0
  7. structdyn-0.5.1/examples/mdf/__init__.py +0 -0
  8. structdyn-0.5.1/examples/mdf/eg1_mdf.py +21 -0
  9. structdyn-0.5.1/examples/mdf/eg2_mdf.py +26 -0
  10. structdyn-0.5.1/examples/mdf/eg_cdm.py +19 -0
  11. structdyn-0.5.1/examples/mdf/eg_damping_mat.py +14 -0
  12. structdyn-0.5.1/examples/mdf/eg_newmark.py +18 -0
  13. structdyn-0.5.1/examples/mdf/eg_newmark_gm.py +32 -0
  14. structdyn-0.5.1/examples/sdf/__init__.py +0 -0
  15. structdyn-0.5.1/examples/sdf/eg_analytical.py +18 -0
  16. structdyn-0.5.1/examples/sdf/eg_cdm.py +23 -0
  17. structdyn-0.5.1/examples/sdf/eg_el_centro.py +21 -0
  18. structdyn-0.5.1/examples/sdf/eg_ground_motion.py +24 -0
  19. structdyn-0.5.1/examples/sdf/eg_interpolation.py +21 -0
  20. structdyn-0.5.1/examples/sdf/eg_newmark.py +19 -0
  21. structdyn-0.5.1/examples/sdf/eg_newmark_non_linear.py +19 -0
  22. structdyn-0.5.1/examples/sdf/eg_res_spec_el_centro.py +19 -0
  23. structdyn-0.5.1/pyproject.toml +27 -0
  24. structdyn-0.5.1/setup.cfg +4 -0
  25. structdyn-0.5.1/structdyn/__init__.py +23 -0
  26. structdyn-0.5.1/structdyn/ground_motions/__init__.py +3 -0
  27. structdyn-0.5.1/structdyn/ground_motions/data/elcentro_chopra.csv +1561 -0
  28. structdyn-0.5.1/structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC-UP.AT2 +1080 -0
  29. structdyn-0.5.1/structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC180-hor1.AT2 +1079 -0
  30. structdyn-0.5.1/structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC270-hor2.AT2 +1074 -0
  31. structdyn-0.5.1/structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS-UP.AT2 +1604 -0
  32. structdyn-0.5.1/structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS000-hor1.AT2 +1604 -0
  33. structdyn-0.5.1/structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS090-hor2.AT2 +1604 -0
  34. structdyn-0.5.1/structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL-UP.AT2 +204 -0
  35. structdyn-0.5.1/structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL090-hor1.AT2 +204 -0
  36. structdyn-0.5.1/structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL360-hor2.AT2 +204 -0
  37. structdyn-0.5.1/structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PUL164-hor1.AT2 +839 -0
  38. structdyn-0.5.1/structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PUL254-hor2.AT2 +839 -0
  39. structdyn-0.5.1/structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PULDWN-up.AT2 +839 -0
  40. structdyn-0.5.1/structdyn/ground_motions/ground_motion.py +174 -0
  41. structdyn-0.5.1/structdyn/mdf/__init__.py +2 -0
  42. structdyn-0.5.1/structdyn/mdf/analytical_methods/__init__.py +1 -0
  43. structdyn-0.5.1/structdyn/mdf/analytical_methods/modal_analysis.py +213 -0
  44. structdyn-0.5.1/structdyn/mdf/analytical_methods/modal_superposition.py +0 -0
  45. structdyn-0.5.1/structdyn/mdf/mdf.py +216 -0
  46. structdyn-0.5.1/structdyn/mdf/mdf_helpers/__init__.py +1 -0
  47. structdyn-0.5.1/structdyn/mdf/mdf_helpers/builders.py +45 -0
  48. structdyn-0.5.1/structdyn/mdf/numerical_methods/__init__.py +1 -0
  49. structdyn-0.5.1/structdyn/mdf/numerical_methods/central_difference.py +231 -0
  50. structdyn-0.5.1/structdyn/mdf/numerical_methods/newmark_beta.py +258 -0
  51. structdyn-0.5.1/structdyn/sdf/__init__.py +0 -0
  52. structdyn-0.5.1/structdyn/sdf/analytical_methods/__init__.py +0 -0
  53. structdyn-0.5.1/structdyn/sdf/analytical_methods/analytical_response.py +161 -0
  54. structdyn-0.5.1/structdyn/sdf/numerical_methods/__init__.py +1 -0
  55. structdyn-0.5.1/structdyn/sdf/numerical_methods/central_difference.py +123 -0
  56. structdyn-0.5.1/structdyn/sdf/numerical_methods/interpolation.py +140 -0
  57. structdyn-0.5.1/structdyn/sdf/numerical_methods/newmark_beta.py +311 -0
  58. structdyn-0.5.1/structdyn/sdf/response_spectrum.py +99 -0
  59. structdyn-0.5.1/structdyn/sdf/sdf.py +127 -0
  60. structdyn-0.5.1/structdyn/utils/__init__.py +1 -0
  61. structdyn-0.5.1/structdyn/utils/helpers.py +118 -0
  62. structdyn-0.5.1/structdyn.egg-info/PKG-INFO +237 -0
  63. structdyn-0.5.1/structdyn.egg-info/SOURCES.txt +69 -0
  64. structdyn-0.5.1/structdyn.egg-info/dependency_links.txt +1 -0
  65. structdyn-0.5.1/structdyn.egg-info/requires.txt +10 -0
  66. structdyn-0.5.1/structdyn.egg-info/top_level.txt +6 -0
  67. structdyn-0.5.1/tests/test_mdf.py +92 -0
  68. structdyn-0.5.1/tests/test_sdf.py +134 -0
  69. structdyn-0.5.1/trash/eg_fdef.py +37 -0
  70. structdyn-0.5.1/trash/gm_helper.py +69 -0
  71. structdyn-0.5.1/trash/setup.py +21 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abinash Mandal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ recursive-include structdyn/ground_motions/data *.AT2
2
+ recursive-include structdyn/ground_motions/data *.csv
3
+
@@ -0,0 +1,237 @@
1
+ Metadata-Version: 2.4
2
+ Name: structdyn
3
+ Version: 0.5.1
4
+ Summary: StructDyn: An open-source Python library for structural dynamics analysis
5
+ Author-email: Abinash Mandal <abinashmandal33486@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: numpy
10
+ Requires-Dist: matplotlib
11
+ Requires-Dist: pandas
12
+ Requires-Dist: scipy
13
+ Requires-Dist: importlib-resources; python_version < "3.9"
14
+ Provides-Extra: test
15
+ Requires-Dist: pytest; extra == "test"
16
+ Dynamic: license-file
17
+
18
+ # Structural Dynamics Library (`structdyn`)
19
+
20
+ A Python library for structural dynamics analysis.
21
+
22
+ [![Documentation Status](https://readthedocs.org/projects/structdyn/badge/?version=latest)](https://structdyn.readthedocs.io/en/latest/)
23
+
24
+
25
+ ## Citing `structdyn`
26
+
27
+ If you use `structdyn` in your research or work, please cite it as follows:
28
+
29
+ > Mandal, A. (2026). structdyn: A Python library for structural dynamics analysis (Version 0.5.0) [Computer software]. https://github.com/learnstructure/structdyn.git
30
+
31
+ Here is the citation in BibTeX format:
32
+
33
+ ```bibtex
34
+ @software{Mandal_structdyn_2026,
35
+ author = {Mandal, Abinash},
36
+ title = {{structdyn: A Python library for structural dynamics analysis}},
37
+ version = {0.5.0},
38
+ year = {2026},
39
+ publisher = {GitHub},
40
+ journal = {GitHub repository},
41
+ url = {https://github.com/learnstructure/structdyn.git}
42
+ }
43
+ ```
44
+
45
+ ## Features
46
+
47
+ * **Single-Degree-of-Freedom (SDF) Systems:**
48
+ * Define linear and nonlinear SDF systems.
49
+ * Analyze free and forced vibrations.
50
+ * Calculate responses using analytical and numerical methods.
51
+ * **Multi-Degree-of-Freedom (MDF) Systems:**
52
+ * Define MDF systems with custom mass and stiffness matrices.
53
+ * Perform modal analysis to determine natural frequencies and mode shapes.
54
+ * Analyze the dynamic response using modal superposition.
55
+ * **Ground Motion Analysis:**
56
+ * Load and scale ground motion records.
57
+ * Generate response spectra.
58
+ * Analyze the response of structures to earthquake excitations.
59
+ * **Numerical Methods:**
60
+ * A suite of numerical solvers, including:
61
+ * Central Difference Method
62
+ * Newmark-Beta Method
63
+ * Linear Interpolation Method
64
+ * **Material Models:**
65
+ * Elastic-perfectly plastic material model for nonlinear analysis.
66
+
67
+
68
+ ## Installation
69
+
70
+ Install the package using pip:
71
+
72
+ ```bash
73
+ pip install git+https://github.com/learnstructure/structdyn.git
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ Here's a quick example of how to use `structdyn` to solve a simple SDF system:
79
+
80
+ ```python
81
+ import numpy as np
82
+ from structdyn.sdf.sdf import SDF
83
+
84
+ # 1. Define the structure
85
+ m = 45594 # mass (kg)
86
+ k = 18e5 # stiffness (N/m)
87
+ ji = 0.05 # damping ratio
88
+ sdf = SDF(m, k, ji)
89
+
90
+ # 2. Define the dynamic loading
91
+ dt = 0.1
92
+ time = np.arange(0, 10.01, dt)
93
+ load = np.zeros_like(time)
94
+ load[time <= 2] = 1000 * np.sin(np.pi * time[time <= 2])
95
+
96
+ # 3. Solve the equation of motion
97
+ # Available methods: 'newmark_beta', 'central_difference', 'interpolation'
98
+ results = sdf.find_response(time, load, method="newmark_beta")
99
+
100
+ # 4. Print the results
101
+ print(results)
102
+ ```
103
+
104
+ ## Examples
105
+
106
+ To run the examples provided in the `examples` directory, clone the repository and run the desired example file:
107
+
108
+ ```bash
109
+ git clone https://github.com/learnstructure/structdyn.git
110
+ cd structdyn
111
+ pip install -e .
112
+ python -m examples.sdf.eg_newmark
113
+ ```
114
+
115
+ ### Analytical Methods
116
+
117
+ `structdyn` can also solve for the response of an SDF system analytically for certain cases.
118
+
119
+ #### Free Vibration
120
+
121
+ ```python
122
+ from structdyn import SDF
123
+ from structdyn.sdf.analytical_methods.analytical_response import AnalyticalResponse
124
+
125
+ sdf = SDF(m=1.0, k=100.0, ji=0.05)
126
+
127
+ analytical = AnalyticalResponse(sdf)
128
+
129
+ # Free vibration response
130
+ df_free = analytical.free_vibration(u0=0.01, v0=0.0)
131
+ print(df_free)
132
+ ```
133
+
134
+ #### Harmonic Forcing
135
+
136
+ ```python
137
+ from structdyn import SDF
138
+ from structdyn.sdf.analytical_methods.analytical_response import AnalyticalResponse
139
+
140
+ sdf = SDF(m=1.0, k=100.0, ji=0.05)
141
+
142
+ analytical = AnalyticalResponse(sdf)
143
+
144
+ # Harmonic sine forcing response
145
+ df_harm = analytical.harmonic_response(p0=10.0, w=5.0, excitation="sine")
146
+ print(df_harm)
147
+ ```
148
+
149
+ ### Ground Motion Analysis
150
+
151
+ `structdyn` can be used to analyze the response of a structure to ground motion. The library includes several ground motion records, which can be loaded as follows:
152
+
153
+ ```python
154
+ from structdyn.sdf.sdf import SDF
155
+ from structdyn.ground_motions.ground_motion import GroundMotion
156
+
157
+ # Load the El Centro ground motion record
158
+ gm = GroundMotion.from_event("el_centro_1940", component="RSN6_IMPVALL.I_I-ELC180")
159
+
160
+ # Define an SDF system
161
+ sdf = SDF(45594, 18 * 10**5, 0.05)
162
+
163
+ # Solve for the response of the SDF system to the ground motion
164
+ results = sdf.find_response_ground_motion(gm, method='central_difference')
165
+
166
+ # Print the results
167
+ print(results)
168
+ ```
169
+
170
+ ### Nonlinear Analysis
171
+
172
+ `structdyn` supports nonlinear analysis using the `fd` parameter of the `SDF` class. Currently, the only available nonlinear model is the elastic-perfectly plastic model.
173
+
174
+ ```python
175
+ import numpy as np
176
+ from structdyn.sdf.sdf import SDF
177
+
178
+ # Define an elastic-perfectly plastic SDF system
179
+ sdf_epp = SDF(m=45594, k=18e5, ji=0.05, fd="elastoplastic", f_y=200000)
180
+
181
+ # Define the dynamic loading
182
+ dt = 0.1
183
+ time = np.arange(0, 10.01, dt)
184
+ load = np.zeros_like(time)
185
+ load[time <= 2] = 1000 * np.sin(np.pi * time[time <= 2])
186
+
187
+
188
+ # Solve for the response of the nonlinear system
189
+ results_epp = sdf_epp.find_response(time, load)
190
+
191
+ # Print the results
192
+ print(results_epp)
193
+ ```
194
+
195
+ ### Response Spectrum Analysis
196
+
197
+ `structdyn` can be used to compute the response spectrum of a ground motion.
198
+
199
+ ```python
200
+ import numpy as np
201
+ from structdyn.ground_motions.ground_motion import GroundMotion
202
+ from structdyn.sdf.response_spectrum import ResponseSpectrum
203
+
204
+ # Load the El Centro ground motion record
205
+ gm = GroundMotion.from_event("el_centro_1940", component="RSN6_IMPVALL.I_I-ELC180")
206
+
207
+ # Define the periods for which to compute the response spectrum
208
+ periods = np.arange(0, 5.01, 0.1)
209
+
210
+ # Create a ResponseSpectrum object
211
+ rs = ResponseSpectrum(periods, 0.02, gm)
212
+
213
+ # Compute the response spectrum
214
+ results = rs.compute()
215
+
216
+ # Print the results
217
+ print(results)
218
+ ```
219
+
220
+ ## Running Tests
221
+
222
+ To run the tests, you will need to install `pytest`. You can then run the tests from the root directory of the project:
223
+
224
+ ```bash
225
+ pip install pytest
226
+ pytest
227
+ ```
228
+
229
+ ## Contributing
230
+
231
+ Contributions are welcome! If you would like to contribute to the project, please follow these steps:
232
+
233
+ 1. Fork the repository.
234
+ 2. Create a new branch for your feature or bug fix.
235
+ 3. Make your changes and add tests.
236
+ 4. Run the tests to ensure that everything is working correctly.
237
+ 5. Submit a pull request.
@@ -0,0 +1,220 @@
1
+ # Structural Dynamics Library (`structdyn`)
2
+
3
+ A Python library for structural dynamics analysis.
4
+
5
+ [![Documentation Status](https://readthedocs.org/projects/structdyn/badge/?version=latest)](https://structdyn.readthedocs.io/en/latest/)
6
+
7
+
8
+ ## Citing `structdyn`
9
+
10
+ If you use `structdyn` in your research or work, please cite it as follows:
11
+
12
+ > Mandal, A. (2026). structdyn: A Python library for structural dynamics analysis (Version 0.5.0) [Computer software]. https://github.com/learnstructure/structdyn.git
13
+
14
+ Here is the citation in BibTeX format:
15
+
16
+ ```bibtex
17
+ @software{Mandal_structdyn_2026,
18
+ author = {Mandal, Abinash},
19
+ title = {{structdyn: A Python library for structural dynamics analysis}},
20
+ version = {0.5.0},
21
+ year = {2026},
22
+ publisher = {GitHub},
23
+ journal = {GitHub repository},
24
+ url = {https://github.com/learnstructure/structdyn.git}
25
+ }
26
+ ```
27
+
28
+ ## Features
29
+
30
+ * **Single-Degree-of-Freedom (SDF) Systems:**
31
+ * Define linear and nonlinear SDF systems.
32
+ * Analyze free and forced vibrations.
33
+ * Calculate responses using analytical and numerical methods.
34
+ * **Multi-Degree-of-Freedom (MDF) Systems:**
35
+ * Define MDF systems with custom mass and stiffness matrices.
36
+ * Perform modal analysis to determine natural frequencies and mode shapes.
37
+ * Analyze the dynamic response using modal superposition.
38
+ * **Ground Motion Analysis:**
39
+ * Load and scale ground motion records.
40
+ * Generate response spectra.
41
+ * Analyze the response of structures to earthquake excitations.
42
+ * **Numerical Methods:**
43
+ * A suite of numerical solvers, including:
44
+ * Central Difference Method
45
+ * Newmark-Beta Method
46
+ * Linear Interpolation Method
47
+ * **Material Models:**
48
+ * Elastic-perfectly plastic material model for nonlinear analysis.
49
+
50
+
51
+ ## Installation
52
+
53
+ Install the package using pip:
54
+
55
+ ```bash
56
+ pip install git+https://github.com/learnstructure/structdyn.git
57
+ ```
58
+
59
+ ## Usage
60
+
61
+ Here's a quick example of how to use `structdyn` to solve a simple SDF system:
62
+
63
+ ```python
64
+ import numpy as np
65
+ from structdyn.sdf.sdf import SDF
66
+
67
+ # 1. Define the structure
68
+ m = 45594 # mass (kg)
69
+ k = 18e5 # stiffness (N/m)
70
+ ji = 0.05 # damping ratio
71
+ sdf = SDF(m, k, ji)
72
+
73
+ # 2. Define the dynamic loading
74
+ dt = 0.1
75
+ time = np.arange(0, 10.01, dt)
76
+ load = np.zeros_like(time)
77
+ load[time <= 2] = 1000 * np.sin(np.pi * time[time <= 2])
78
+
79
+ # 3. Solve the equation of motion
80
+ # Available methods: 'newmark_beta', 'central_difference', 'interpolation'
81
+ results = sdf.find_response(time, load, method="newmark_beta")
82
+
83
+ # 4. Print the results
84
+ print(results)
85
+ ```
86
+
87
+ ## Examples
88
+
89
+ To run the examples provided in the `examples` directory, clone the repository and run the desired example file:
90
+
91
+ ```bash
92
+ git clone https://github.com/learnstructure/structdyn.git
93
+ cd structdyn
94
+ pip install -e .
95
+ python -m examples.sdf.eg_newmark
96
+ ```
97
+
98
+ ### Analytical Methods
99
+
100
+ `structdyn` can also solve for the response of an SDF system analytically for certain cases.
101
+
102
+ #### Free Vibration
103
+
104
+ ```python
105
+ from structdyn import SDF
106
+ from structdyn.sdf.analytical_methods.analytical_response import AnalyticalResponse
107
+
108
+ sdf = SDF(m=1.0, k=100.0, ji=0.05)
109
+
110
+ analytical = AnalyticalResponse(sdf)
111
+
112
+ # Free vibration response
113
+ df_free = analytical.free_vibration(u0=0.01, v0=0.0)
114
+ print(df_free)
115
+ ```
116
+
117
+ #### Harmonic Forcing
118
+
119
+ ```python
120
+ from structdyn import SDF
121
+ from structdyn.sdf.analytical_methods.analytical_response import AnalyticalResponse
122
+
123
+ sdf = SDF(m=1.0, k=100.0, ji=0.05)
124
+
125
+ analytical = AnalyticalResponse(sdf)
126
+
127
+ # Harmonic sine forcing response
128
+ df_harm = analytical.harmonic_response(p0=10.0, w=5.0, excitation="sine")
129
+ print(df_harm)
130
+ ```
131
+
132
+ ### Ground Motion Analysis
133
+
134
+ `structdyn` can be used to analyze the response of a structure to ground motion. The library includes several ground motion records, which can be loaded as follows:
135
+
136
+ ```python
137
+ from structdyn.sdf.sdf import SDF
138
+ from structdyn.ground_motions.ground_motion import GroundMotion
139
+
140
+ # Load the El Centro ground motion record
141
+ gm = GroundMotion.from_event("el_centro_1940", component="RSN6_IMPVALL.I_I-ELC180")
142
+
143
+ # Define an SDF system
144
+ sdf = SDF(45594, 18 * 10**5, 0.05)
145
+
146
+ # Solve for the response of the SDF system to the ground motion
147
+ results = sdf.find_response_ground_motion(gm, method='central_difference')
148
+
149
+ # Print the results
150
+ print(results)
151
+ ```
152
+
153
+ ### Nonlinear Analysis
154
+
155
+ `structdyn` supports nonlinear analysis using the `fd` parameter of the `SDF` class. Currently, the only available nonlinear model is the elastic-perfectly plastic model.
156
+
157
+ ```python
158
+ import numpy as np
159
+ from structdyn.sdf.sdf import SDF
160
+
161
+ # Define an elastic-perfectly plastic SDF system
162
+ sdf_epp = SDF(m=45594, k=18e5, ji=0.05, fd="elastoplastic", f_y=200000)
163
+
164
+ # Define the dynamic loading
165
+ dt = 0.1
166
+ time = np.arange(0, 10.01, dt)
167
+ load = np.zeros_like(time)
168
+ load[time <= 2] = 1000 * np.sin(np.pi * time[time <= 2])
169
+
170
+
171
+ # Solve for the response of the nonlinear system
172
+ results_epp = sdf_epp.find_response(time, load)
173
+
174
+ # Print the results
175
+ print(results_epp)
176
+ ```
177
+
178
+ ### Response Spectrum Analysis
179
+
180
+ `structdyn` can be used to compute the response spectrum of a ground motion.
181
+
182
+ ```python
183
+ import numpy as np
184
+ from structdyn.ground_motions.ground_motion import GroundMotion
185
+ from structdyn.sdf.response_spectrum import ResponseSpectrum
186
+
187
+ # Load the El Centro ground motion record
188
+ gm = GroundMotion.from_event("el_centro_1940", component="RSN6_IMPVALL.I_I-ELC180")
189
+
190
+ # Define the periods for which to compute the response spectrum
191
+ periods = np.arange(0, 5.01, 0.1)
192
+
193
+ # Create a ResponseSpectrum object
194
+ rs = ResponseSpectrum(periods, 0.02, gm)
195
+
196
+ # Compute the response spectrum
197
+ results = rs.compute()
198
+
199
+ # Print the results
200
+ print(results)
201
+ ```
202
+
203
+ ## Running Tests
204
+
205
+ To run the tests, you will need to install `pytest`. You can then run the tests from the root directory of the project:
206
+
207
+ ```bash
208
+ pip install pytest
209
+ pytest
210
+ ```
211
+
212
+ ## Contributing
213
+
214
+ Contributions are welcome! If you would like to contribute to the project, please follow these steps:
215
+
216
+ 1. Fork the repository.
217
+ 2. Create a new branch for your feature or bug fix.
218
+ 3. Make your changes and add tests.
219
+ 4. Run the tests to ensure that everything is working correctly.
220
+ 5. Submit a pull request.
@@ -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"]
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()
@@ -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()