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.
- structdyn-0.5.1/LICENSE +21 -0
- structdyn-0.5.1/MANIFEST.in +3 -0
- structdyn-0.5.1/PKG-INFO +237 -0
- structdyn-0.5.1/README.md +220 -0
- structdyn-0.5.1/docs/source/conf.py +37 -0
- structdyn-0.5.1/examples/__init__.py +0 -0
- structdyn-0.5.1/examples/mdf/__init__.py +0 -0
- structdyn-0.5.1/examples/mdf/eg1_mdf.py +21 -0
- structdyn-0.5.1/examples/mdf/eg2_mdf.py +26 -0
- structdyn-0.5.1/examples/mdf/eg_cdm.py +19 -0
- structdyn-0.5.1/examples/mdf/eg_damping_mat.py +14 -0
- structdyn-0.5.1/examples/mdf/eg_newmark.py +18 -0
- structdyn-0.5.1/examples/mdf/eg_newmark_gm.py +32 -0
- structdyn-0.5.1/examples/sdf/__init__.py +0 -0
- structdyn-0.5.1/examples/sdf/eg_analytical.py +18 -0
- structdyn-0.5.1/examples/sdf/eg_cdm.py +23 -0
- structdyn-0.5.1/examples/sdf/eg_el_centro.py +21 -0
- structdyn-0.5.1/examples/sdf/eg_ground_motion.py +24 -0
- structdyn-0.5.1/examples/sdf/eg_interpolation.py +21 -0
- structdyn-0.5.1/examples/sdf/eg_newmark.py +19 -0
- structdyn-0.5.1/examples/sdf/eg_newmark_non_linear.py +19 -0
- structdyn-0.5.1/examples/sdf/eg_res_spec_el_centro.py +19 -0
- structdyn-0.5.1/pyproject.toml +27 -0
- structdyn-0.5.1/setup.cfg +4 -0
- structdyn-0.5.1/structdyn/__init__.py +23 -0
- structdyn-0.5.1/structdyn/ground_motions/__init__.py +3 -0
- structdyn-0.5.1/structdyn/ground_motions/data/elcentro_chopra.csv +1561 -0
- structdyn-0.5.1/structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC-UP.AT2 +1080 -0
- structdyn-0.5.1/structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC180-hor1.AT2 +1079 -0
- structdyn-0.5.1/structdyn/ground_motions/data/imperialValley_elCentro_1940/RSN6_IMPVALL.I_I-ELC270-hor2.AT2 +1074 -0
- structdyn-0.5.1/structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS-UP.AT2 +1604 -0
- structdyn-0.5.1/structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS000-hor1.AT2 +1604 -0
- structdyn-0.5.1/structdyn/ground_motions/data/lomaPrieta_corralitos_1989/RSN753_LOMAP_CLS090-hor2.AT2 +1604 -0
- structdyn-0.5.1/structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL-UP.AT2 +204 -0
- structdyn-0.5.1/structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL090-hor1.AT2 +204 -0
- structdyn-0.5.1/structdyn/ground_motions/data/northridge_sylmar_1994/RSN1690_NORTH151_SYL360-hor2.AT2 +204 -0
- structdyn-0.5.1/structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PUL164-hor1.AT2 +839 -0
- structdyn-0.5.1/structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PUL254-hor2.AT2 +839 -0
- structdyn-0.5.1/structdyn/ground_motions/data/sanFernando_pacoidaDam_1971/RSN77_SFERN_PULDWN-up.AT2 +839 -0
- structdyn-0.5.1/structdyn/ground_motions/ground_motion.py +174 -0
- structdyn-0.5.1/structdyn/mdf/__init__.py +2 -0
- structdyn-0.5.1/structdyn/mdf/analytical_methods/__init__.py +1 -0
- structdyn-0.5.1/structdyn/mdf/analytical_methods/modal_analysis.py +213 -0
- structdyn-0.5.1/structdyn/mdf/analytical_methods/modal_superposition.py +0 -0
- structdyn-0.5.1/structdyn/mdf/mdf.py +216 -0
- structdyn-0.5.1/structdyn/mdf/mdf_helpers/__init__.py +1 -0
- structdyn-0.5.1/structdyn/mdf/mdf_helpers/builders.py +45 -0
- structdyn-0.5.1/structdyn/mdf/numerical_methods/__init__.py +1 -0
- structdyn-0.5.1/structdyn/mdf/numerical_methods/central_difference.py +231 -0
- structdyn-0.5.1/structdyn/mdf/numerical_methods/newmark_beta.py +258 -0
- structdyn-0.5.1/structdyn/sdf/__init__.py +0 -0
- structdyn-0.5.1/structdyn/sdf/analytical_methods/__init__.py +0 -0
- structdyn-0.5.1/structdyn/sdf/analytical_methods/analytical_response.py +161 -0
- structdyn-0.5.1/structdyn/sdf/numerical_methods/__init__.py +1 -0
- structdyn-0.5.1/structdyn/sdf/numerical_methods/central_difference.py +123 -0
- structdyn-0.5.1/structdyn/sdf/numerical_methods/interpolation.py +140 -0
- structdyn-0.5.1/structdyn/sdf/numerical_methods/newmark_beta.py +311 -0
- structdyn-0.5.1/structdyn/sdf/response_spectrum.py +99 -0
- structdyn-0.5.1/structdyn/sdf/sdf.py +127 -0
- structdyn-0.5.1/structdyn/utils/__init__.py +1 -0
- structdyn-0.5.1/structdyn/utils/helpers.py +118 -0
- structdyn-0.5.1/structdyn.egg-info/PKG-INFO +237 -0
- structdyn-0.5.1/structdyn.egg-info/SOURCES.txt +69 -0
- structdyn-0.5.1/structdyn.egg-info/dependency_links.txt +1 -0
- structdyn-0.5.1/structdyn.egg-info/requires.txt +10 -0
- structdyn-0.5.1/structdyn.egg-info/top_level.txt +6 -0
- structdyn-0.5.1/tests/test_mdf.py +92 -0
- structdyn-0.5.1/tests/test_sdf.py +134 -0
- structdyn-0.5.1/trash/eg_fdef.py +37 -0
- structdyn-0.5.1/trash/gm_helper.py +69 -0
- structdyn-0.5.1/trash/setup.py +21 -0
structdyn-0.5.1/LICENSE
ADDED
|
@@ -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.
|
structdyn-0.5.1/PKG-INFO
ADDED
|
@@ -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
|
+
[](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
|
+
[](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()
|