structsolve 0.3.0__tar.gz → 0.3.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.
- {structsolve-0.3.0 → structsolve-0.3.1}/PKG-INFO +2 -1
- {structsolve-0.3.0 → structsolve-0.3.1}/pyproject.toml +2 -1
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/freq.py +35 -23
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/linear_buckling.py +31 -24
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve.egg-info/PKG-INFO +2 -1
- {structsolve-0.3.0 → structsolve-0.3.1}/LICENSE +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/README.md +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/setup.cfg +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/__init__.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/analysis.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/arc_length_crisfield.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/arc_length_riks.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/logger.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/newton_raphson.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/sparseutils.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve/static.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve.egg-info/SOURCES.txt +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve.egg-info/dependency_links.txt +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve.egg-info/requires.txt +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/structsolve.egg-info/top_level.txt +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/tests/test_analysis.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/tests/test_freq.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/tests/test_linear_buckling.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/tests/test_sparseutils.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/tests/test_static.py +0 -0
- {structsolve-0.3.0 → structsolve-0.3.1}/tests/test_static_deflection.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: structsolve
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Structural analysis solvers
|
|
5
5
|
Author-email: "Saullo G. P. Castro" <castrosaullo@gmail.com>
|
|
6
6
|
License: BSD-2-Clause
|
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
22
|
Classifier: Operating System :: Microsoft :: Windows
|
|
22
23
|
Classifier: Operating System :: Unix
|
|
23
24
|
Requires-Python: >=3.8
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "structsolve"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.1"
|
|
8
8
|
description = "Structural analysis solvers"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "BSD-2-Clause"}
|
|
@@ -28,6 +28,7 @@ classifiers = [
|
|
|
28
28
|
"Programming Language :: Python :: 3.11",
|
|
29
29
|
"Programming Language :: Python :: 3.12",
|
|
30
30
|
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Programming Language :: Python :: 3.14",
|
|
31
32
|
"Operating System :: Microsoft :: Windows",
|
|
32
33
|
"Operating System :: Unix",
|
|
33
34
|
]
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
import scipy
|
|
3
5
|
from scipy.sparse.linalg import eigs, spsolve
|
|
@@ -9,8 +11,16 @@ from .sparseutils import remove_null_cols
|
|
|
9
11
|
|
|
10
12
|
def _estimate_sigma(K, M):
|
|
11
13
|
try:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
rhs = M @ np.random.RandomState(42).randn(K.shape[0])
|
|
15
|
+
with warnings.catch_warnings(record=True) as caught:
|
|
16
|
+
warnings.simplefilter("always")
|
|
17
|
+
y = spsolve(K, rhs)
|
|
18
|
+
if any(issubclass(w.category, (RuntimeWarning, Warning))
|
|
19
|
+
and "singular" in str(w.message).lower() for w in caught):
|
|
20
|
+
return -1.
|
|
21
|
+
residual = np.linalg.norm(K @ y - rhs)
|
|
22
|
+
if residual > 1e-6 * np.linalg.norm(rhs):
|
|
23
|
+
return -1.
|
|
14
24
|
sigma = -abs((y @ K @ y) / (y @ M @ y))
|
|
15
25
|
if not np.isfinite(sigma) or sigma == 0:
|
|
16
26
|
return -1.
|
|
@@ -21,7 +31,7 @@ def _estimate_sigma(K, M):
|
|
|
21
31
|
|
|
22
32
|
def freq(K, M, tol=0, sparse_solver=True,
|
|
23
33
|
silent=False, sort=True, num_eigvalues=25,
|
|
24
|
-
num_eigvalues_print=5):
|
|
34
|
+
num_eigvalues_print=5, skip_null_cols=False):
|
|
25
35
|
"""Frequency Analysis
|
|
26
36
|
|
|
27
37
|
Calculate the eigenvalues (`\lambda^2`) and mass-normalized eigenvectors
|
|
@@ -53,6 +63,9 @@ def freq(K, M, tol=0, sparse_solver=True,
|
|
|
53
63
|
Number of calculated eigenvalues.
|
|
54
64
|
num_eigvalues_print : int, optional
|
|
55
65
|
Number of eigenvalues to print.
|
|
66
|
+
skip_null_cols : bool, optional
|
|
67
|
+
If True, skip the removal of null columns from the matrices.
|
|
68
|
+
Use only when K is known to be non-singular.
|
|
56
69
|
|
|
57
70
|
Returns
|
|
58
71
|
-------
|
|
@@ -67,10 +80,14 @@ def freq(K, M, tol=0, sparse_solver=True,
|
|
|
67
80
|
msg('Eigenvalue solver... ', level=2, silent=silent)
|
|
68
81
|
|
|
69
82
|
k = min(num_eigvalues, M.shape[0]-2)
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
size = M.shape[0]
|
|
84
|
+
if skip_null_cols:
|
|
85
|
+
used_cols = None
|
|
86
|
+
Keff, Meff = K, M
|
|
87
|
+
else:
|
|
72
88
|
Keff, Meff, used_cols = remove_null_cols(K, M, silent=silent,
|
|
73
89
|
level=3)
|
|
90
|
+
if sparse_solver:
|
|
74
91
|
#NOTE Looking for better performance with symmetric matrices, I tried
|
|
75
92
|
# using sparseutils.sparse.is_symmetric and eigsh, but it seems not
|
|
76
93
|
# to improve speed (I did not try passing only half of the sparse
|
|
@@ -82,35 +99,30 @@ def freq(K, M, tol=0, sparse_solver=True,
|
|
|
82
99
|
#NOTE eigs solves: [K] {u} = eigval [M] {u}
|
|
83
100
|
# therefore we must correct he sign of lambda^2 here:
|
|
84
101
|
lambda2 = -eigvals
|
|
85
|
-
eigvecs = np.zeros((sizebkp, k), dtype=peigvecs.dtype)
|
|
86
|
-
eigvecs[used_cols, :] = peigvecs
|
|
87
102
|
else:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
Meff = M.toarray()
|
|
103
|
+
if isinstance(Meff, scipy.sparse.spmatrix):
|
|
104
|
+
Meff = Meff.toarray()
|
|
91
105
|
else:
|
|
92
|
-
Meff = np.asarray(
|
|
93
|
-
if isinstance(
|
|
94
|
-
Keff =
|
|
106
|
+
Meff = np.asarray(Meff)
|
|
107
|
+
if isinstance(Keff, scipy.sparse.spmatrix):
|
|
108
|
+
Keff = Keff.toarray()
|
|
95
109
|
else:
|
|
96
|
-
Keff = np.asarray(
|
|
97
|
-
sizebkp = Meff.shape[0]
|
|
98
|
-
col_sum = Meff.sum(axis=0)
|
|
99
|
-
check = col_sum != 0
|
|
100
|
-
used_cols = np.arange(Meff.shape[0])[check]
|
|
101
|
-
Meff = Meff[:, check][check, :]
|
|
102
|
-
Keff = Keff[:, check][check, :]
|
|
110
|
+
Keff = np.asarray(Keff)
|
|
103
111
|
|
|
104
112
|
#TODO did not try using eigh when input is symmetric to see if there
|
|
105
113
|
# will be speed improvements
|
|
106
114
|
# for effiency reasons, solving:
|
|
107
115
|
# [M]{u} = (-1/lambda2)[K]{u}
|
|
108
116
|
# [M]{u} = eigval [K]{u}
|
|
117
|
+
msg('eig() solver...', level=3, silent=silent)
|
|
109
118
|
eigvals, peigvecs = eig(a=Meff, b=Keff)
|
|
110
119
|
lambda2 = -1./eigvals
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
eigvecs
|
|
120
|
+
|
|
121
|
+
if used_cols is not None:
|
|
122
|
+
eigvecs = np.zeros((size, peigvecs.shape[1]), dtype=peigvecs.dtype)
|
|
123
|
+
eigvecs[used_cols, :] = peigvecs
|
|
124
|
+
else:
|
|
125
|
+
eigvecs = peigvecs
|
|
114
126
|
|
|
115
127
|
msg('finished!', level=3, silent=silent)
|
|
116
128
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
from scipy.sparse.linalg import eigsh, spsolve
|
|
3
5
|
from scipy.linalg import eigh
|
|
@@ -8,8 +10,16 @@ from .sparseutils import remove_null_cols
|
|
|
8
10
|
|
|
9
11
|
def _estimate_sigma(K, KG):
|
|
10
12
|
try:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
rhs = KG @ np.random.RandomState(42).randn(K.shape[0])
|
|
14
|
+
with warnings.catch_warnings(record=True) as caught:
|
|
15
|
+
warnings.simplefilter("always")
|
|
16
|
+
y = spsolve(K, rhs)
|
|
17
|
+
if any(issubclass(w.category, (RuntimeWarning, Warning))
|
|
18
|
+
and "singular" in str(w.message).lower() for w in caught):
|
|
19
|
+
return 1.
|
|
20
|
+
residual = np.linalg.norm(K @ y - rhs)
|
|
21
|
+
if residual > 1e-6 * np.linalg.norm(rhs):
|
|
22
|
+
return 1.
|
|
13
23
|
sigma = abs((y @ KG @ y) / (y @ K @ y))
|
|
14
24
|
if not np.isfinite(sigma) or sigma == 0:
|
|
15
25
|
return 1.
|
|
@@ -18,7 +28,8 @@ def _estimate_sigma(K, KG):
|
|
|
18
28
|
return 1.
|
|
19
29
|
|
|
20
30
|
def lb(K, KG, tol=0, sparse_solver=True, silent=False,
|
|
21
|
-
num_eigvalues=25, num_eigvalues_print=5
|
|
31
|
+
num_eigvalues=25, num_eigvalues_print=5,
|
|
32
|
+
skip_null_cols=False):
|
|
22
33
|
"""Linear Buckling Analysis
|
|
23
34
|
|
|
24
35
|
It can also be used for more general eigenvalue analyzes if `K` is the
|
|
@@ -44,6 +55,9 @@ def lb(K, KG, tol=0, sparse_solver=True, silent=False,
|
|
|
44
55
|
Number of calculated eigenvalues.
|
|
45
56
|
num_eigvalues_print : int, optional
|
|
46
57
|
Number of eigenvalues to print.
|
|
58
|
+
skip_null_cols : bool, optional
|
|
59
|
+
If True, skip the removal of null columns from the matrices.
|
|
60
|
+
Use only when K is known to be non-singular.
|
|
47
61
|
|
|
48
62
|
Notes
|
|
49
63
|
-----
|
|
@@ -57,38 +71,31 @@ def lb(K, KG, tol=0, sparse_solver=True, silent=False,
|
|
|
57
71
|
msg('Eigenvalue solver... ', level=2, silent=silent)
|
|
58
72
|
|
|
59
73
|
k = min(num_eigvalues, KG.shape[0]-2)
|
|
74
|
+
size = KG.shape[0]
|
|
75
|
+
if skip_null_cols:
|
|
76
|
+
used_cols = None
|
|
77
|
+
else:
|
|
78
|
+
K, KG, used_cols = remove_null_cols(K, KG, silent=silent)
|
|
60
79
|
if sparse_solver:
|
|
61
80
|
mode = 'cayley'
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
msg('finished!', level=3, silent=silent)
|
|
68
|
-
except Exception as e:
|
|
69
|
-
warn(str(e), level=4, silent=silent)
|
|
70
|
-
msg('aborted!', level=3, silent=silent)
|
|
71
|
-
sizebkp = KG.shape[0]
|
|
72
|
-
K, KG, used_cols = remove_null_cols(K, KG, silent=silent)
|
|
73
|
-
sigma = _estimate_sigma(K, KG)
|
|
74
|
-
msg('eigsh() solver (sigma={0})...'.format(sigma), level=3, silent=silent)
|
|
75
|
-
eigvals, peigvecs = eigsh(A=KG, k=k,
|
|
76
|
-
which='SM', M=K, tol=tol, sigma=sigma, mode=mode)
|
|
77
|
-
msg('finished!', level=3, silent=silent)
|
|
78
|
-
eigvecs = np.zeros((sizebkp, num_eigvalues),
|
|
79
|
-
dtype=peigvecs.dtype)
|
|
80
|
-
eigvecs[used_cols, :] = peigvecs
|
|
81
|
+
sigma = _estimate_sigma(K, KG)
|
|
82
|
+
msg('eigsh() solver (sigma={0})...'.format(sigma), level=3, silent=silent)
|
|
83
|
+
eigvals, peigvecs = eigsh(A=KG, k=k,
|
|
84
|
+
which='SM', M=K, tol=tol, sigma=sigma, mode=mode)
|
|
85
|
+
msg('finished!', level=3, silent=silent)
|
|
81
86
|
|
|
82
87
|
else:
|
|
83
|
-
size = KG.shape[0]
|
|
84
|
-
K, KG, used_cols = remove_null_cols(K, KG, silent=silent)
|
|
85
88
|
K = K.toarray()
|
|
86
89
|
KG = KG.toarray()
|
|
87
90
|
msg('eigh() solver...', level=3, silent=silent)
|
|
88
91
|
eigvals, peigvecs = eigh(a=KG, b=K)
|
|
89
92
|
msg('finished!', level=3, silent=silent)
|
|
93
|
+
|
|
94
|
+
if used_cols is not None:
|
|
90
95
|
eigvecs = np.zeros((size, num_eigvalues), dtype=peigvecs.dtype)
|
|
91
96
|
eigvecs[used_cols, :] = peigvecs[:, :num_eigvalues]
|
|
97
|
+
else:
|
|
98
|
+
eigvecs = peigvecs[:, :num_eigvalues]
|
|
92
99
|
|
|
93
100
|
eigvals = -1./eigvals
|
|
94
101
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: structsolve
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Structural analysis solvers
|
|
5
5
|
Author-email: "Saullo G. P. Castro" <castrosaullo@gmail.com>
|
|
6
6
|
License: BSD-2-Clause
|
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
22
|
Classifier: Operating System :: Microsoft :: Windows
|
|
22
23
|
Classifier: Operating System :: Unix
|
|
23
24
|
Requires-Python: >=3.8
|
|
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
|