structuralcodes 0.1.1__py3-none-any.whl → 0.2.0__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.
Potentially problematic release.
This version of structuralcodes might be problematic. Click here for more details.
- structuralcodes/__init__.py +1 -1
- structuralcodes/codes/ec2_2004/__init__.py +43 -11
- structuralcodes/codes/ec2_2004/_concrete_creep_and_shrinkage.py +529 -0
- structuralcodes/core/base.py +16 -4
- structuralcodes/geometry/_geometry.py +4 -2
- structuralcodes/materials/constitutive_laws/__init__.py +84 -0
- structuralcodes/materials/constitutive_laws/_bilinearcompression.py +138 -0
- structuralcodes/materials/constitutive_laws/_elastic.py +114 -0
- structuralcodes/materials/constitutive_laws/_elasticplastic.py +172 -0
- structuralcodes/materials/constitutive_laws/_parabolarectangle.py +198 -0
- structuralcodes/materials/constitutive_laws/_popovics.py +133 -0
- structuralcodes/materials/constitutive_laws/_sargin.py +115 -0
- structuralcodes/materials/constitutive_laws/_userdefined.py +218 -0
- structuralcodes/sections/_generic.py +13 -3
- structuralcodes/sections/section_integrators/_fiber_integrator.py +1 -3
- structuralcodes/sections/section_integrators/_marin_integrator.py +1 -1
- {structuralcodes-0.1.1.dist-info → structuralcodes-0.2.0.dist-info}/METADATA +1 -1
- {structuralcodes-0.1.1.dist-info → structuralcodes-0.2.0.dist-info}/RECORD +19 -12
- structuralcodes/codes/ec2_2004/annex_b_shrink_and_creep.py +0 -257
- structuralcodes/materials/constitutive_laws.py +0 -981
- {structuralcodes-0.1.1.dist-info → structuralcodes-0.2.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Popovics constitutive law."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations # To have clean hints of ArrayLike in docs
|
|
4
|
+
|
|
5
|
+
import typing as t
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from numpy.typing import ArrayLike
|
|
9
|
+
|
|
10
|
+
from ...core.base import ConstitutiveLaw
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Popovics(ConstitutiveLaw):
|
|
14
|
+
"""Class for Popovics-Mander constitutive law.
|
|
15
|
+
|
|
16
|
+
The stresses and strains are assumed negative in compression and positive
|
|
17
|
+
in tension.
|
|
18
|
+
|
|
19
|
+
If the relation Ec = 5000 * sqrt(fc) is used for elastic modulus, the
|
|
20
|
+
constitutive law is identical to the one proposed by Mander et al. (1988).
|
|
21
|
+
|
|
22
|
+
References:
|
|
23
|
+
Popovics, S., 1973, “A Numerical Approach to the Complete Stress-Strain
|
|
24
|
+
Curve of Concrete”, Cement and Concrete Research, 3(4), 583-599.
|
|
25
|
+
|
|
26
|
+
Mander, J.B., Priestley, M.J.N., Park, R., 1988, "Theoretical Stress-Strain
|
|
27
|
+
Model for Confined Concrete", Journal of Structural Engineering, 114(8),
|
|
28
|
+
1804-1826.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
__materials__: t.Tuple[str] = ('concrete',)
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
fc: float,
|
|
36
|
+
eps_c: float = -0.002,
|
|
37
|
+
eps_cu: float = -0.0035,
|
|
38
|
+
Ec: t.Optional[float] = None,
|
|
39
|
+
name: t.Optional[str] = None,
|
|
40
|
+
) -> None:
|
|
41
|
+
"""Initialize a Popovics Material.
|
|
42
|
+
|
|
43
|
+
Arguments:
|
|
44
|
+
fc (float): the strength of concrete in compression
|
|
45
|
+
|
|
46
|
+
Keyword Arguments:
|
|
47
|
+
eps_c (float): Peak strain of concrete in compression. Default
|
|
48
|
+
value = -0.002.
|
|
49
|
+
eps_cu (float): Ultimate strain of concrete in compression. Default
|
|
50
|
+
value = -0.0035.
|
|
51
|
+
E (optional float): Elastic modulus of concrete. If None, the
|
|
52
|
+
equation Ec = 5000 * fc**0.5 proposed by Mander et al. (1988)
|
|
53
|
+
is adopted (fc in MPa). Default value = None.
|
|
54
|
+
name (str): A name for the constitutive law.
|
|
55
|
+
|
|
56
|
+
Raises:
|
|
57
|
+
ValueError: If E is less or equal to 0.
|
|
58
|
+
|
|
59
|
+
Note:
|
|
60
|
+
If positive values are input for fc, eps_c and eps_cu are input,
|
|
61
|
+
they will be assumed negative.
|
|
62
|
+
"""
|
|
63
|
+
name = name if name is not None else 'PopovicsLaw'
|
|
64
|
+
super().__init__(name=name)
|
|
65
|
+
self._fc = -abs(fc)
|
|
66
|
+
self._eps_c = -abs(eps_c)
|
|
67
|
+
self._eps_cu = -abs(eps_cu)
|
|
68
|
+
if Ec is None:
|
|
69
|
+
# fc in MPa, relation of Mander et al. (1988)
|
|
70
|
+
Ec = 5000 * abs(fc) ** 0.5
|
|
71
|
+
if Ec <= 0:
|
|
72
|
+
raise ValueError('Elastic modulus must be a positive number.')
|
|
73
|
+
E_sec = self._fc / self._eps_c
|
|
74
|
+
self._n = Ec / (Ec - E_sec)
|
|
75
|
+
|
|
76
|
+
def get_stress(
|
|
77
|
+
self, eps: t.Union[float, ArrayLike]
|
|
78
|
+
) -> t.Union[float, ArrayLike]:
|
|
79
|
+
"""Return the stress given the strain."""
|
|
80
|
+
eps = eps if np.isscalar(eps) else np.atleast_1d(eps)
|
|
81
|
+
# Preprocess eps array in order
|
|
82
|
+
eps = self.preprocess_strains_with_limits(eps=eps)
|
|
83
|
+
# Compute stress
|
|
84
|
+
# Compression branch
|
|
85
|
+
eta = eps / self._eps_c
|
|
86
|
+
|
|
87
|
+
sig = self._fc * eta * self._n / (self._n - 1 + eta**self._n)
|
|
88
|
+
|
|
89
|
+
# Elsewhere stress is 0.0
|
|
90
|
+
if np.isscalar(eps):
|
|
91
|
+
if eps < self._eps_cu or eps > 0:
|
|
92
|
+
return 0.0
|
|
93
|
+
else:
|
|
94
|
+
sig[eps < self._eps_cu] = 0.0
|
|
95
|
+
sig[eps > 0] = 0.0
|
|
96
|
+
|
|
97
|
+
return sig
|
|
98
|
+
|
|
99
|
+
def get_tangent(
|
|
100
|
+
self, eps: t.Union[float, ArrayLike]
|
|
101
|
+
) -> t.Union[float, ArrayLike]:
|
|
102
|
+
"""Return the tangent given strain."""
|
|
103
|
+
eps = eps if np.isscalar(eps) else np.atleast_1d(eps)
|
|
104
|
+
# Preprocess eps array in order
|
|
105
|
+
eps = self.preprocess_strains_with_limits(eps=eps)
|
|
106
|
+
# Compression branch
|
|
107
|
+
eta = eps / self._eps_c
|
|
108
|
+
|
|
109
|
+
tangent = (
|
|
110
|
+
(1 - eta**self._n)
|
|
111
|
+
/ (self._n - 1 + eta**self._n) ** 2
|
|
112
|
+
* self._n
|
|
113
|
+
* (self._n - 1)
|
|
114
|
+
* self._fc
|
|
115
|
+
/ self._eps_c
|
|
116
|
+
)
|
|
117
|
+
# Elsewhere tangent is zero
|
|
118
|
+
if np.isscalar(eps):
|
|
119
|
+
if eps < self._eps_cu or eps > 0:
|
|
120
|
+
return 0
|
|
121
|
+
else:
|
|
122
|
+
tangent[eps < self._eps_cu] = 0.0
|
|
123
|
+
tangent[eps > 0] = 0.0
|
|
124
|
+
|
|
125
|
+
return tangent
|
|
126
|
+
|
|
127
|
+
def get_ultimate_strain(
|
|
128
|
+
self, yielding: bool = False
|
|
129
|
+
) -> t.Tuple[float, float]:
|
|
130
|
+
"""Return the ultimate strain (negative and positive)."""
|
|
131
|
+
if yielding:
|
|
132
|
+
return (self._eps_c, 100)
|
|
133
|
+
return (self._eps_cu, 100)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Sargin constitutive law."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations # To have clean hints of ArrayLike in docs
|
|
4
|
+
|
|
5
|
+
import typing as t
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from numpy.typing import ArrayLike
|
|
9
|
+
|
|
10
|
+
from ...core.base import ConstitutiveLaw
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Sargin(ConstitutiveLaw):
|
|
14
|
+
"""Class for Sargin constitutive law.
|
|
15
|
+
|
|
16
|
+
The stresses and strains are assumed negative in compression and positive
|
|
17
|
+
in tension.
|
|
18
|
+
|
|
19
|
+
References:
|
|
20
|
+
Sargin, M. (1971), "Stress-strain relationship for concrete and the
|
|
21
|
+
analysis of structural concrete section, Study No. 4,
|
|
22
|
+
Solid Mechanics Division, University of Waterloo, Ontario, Canada
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__materials__: t.Tuple[str] = ('concrete',)
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
fc: float,
|
|
30
|
+
eps_c1: float = -0.0023,
|
|
31
|
+
eps_cu1: float = -0.0035,
|
|
32
|
+
k: float = 2.04,
|
|
33
|
+
name: t.Optional[str] = None,
|
|
34
|
+
) -> None:
|
|
35
|
+
"""Initialize a Sargin Material.
|
|
36
|
+
|
|
37
|
+
Arguments:
|
|
38
|
+
fc (float): The strength of concrete in compression
|
|
39
|
+
|
|
40
|
+
Keyword Arguments:
|
|
41
|
+
eps_c1 (float): Peak strain of concrete in compression. Default
|
|
42
|
+
value = -0.0023.
|
|
43
|
+
eps_u (float): Ultimate strain of concrete in compression. Default
|
|
44
|
+
value = -0.0035.
|
|
45
|
+
k (float): Plasticity number. Default value = 2.04.
|
|
46
|
+
name (str): A name for the constitutive law.
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
ValueError: If k is less or equal to 0.
|
|
50
|
+
|
|
51
|
+
Note:
|
|
52
|
+
If positive values are input for fc, eps_c1 and eps_cu1 are input,
|
|
53
|
+
they will be assumed negative.
|
|
54
|
+
"""
|
|
55
|
+
name = name if name is not None else 'SarginLaw'
|
|
56
|
+
super().__init__(name=name)
|
|
57
|
+
self._fc = -abs(fc)
|
|
58
|
+
self._eps_c1 = -abs(eps_c1)
|
|
59
|
+
self._eps_cu1 = -abs(eps_cu1)
|
|
60
|
+
self._k = k
|
|
61
|
+
|
|
62
|
+
def get_stress(
|
|
63
|
+
self, eps: t.Union[float, ArrayLike]
|
|
64
|
+
) -> t.Union[float, ArrayLike]:
|
|
65
|
+
"""Return the stress given the strain."""
|
|
66
|
+
eps = eps if np.isscalar(eps) else np.atleast_1d(eps)
|
|
67
|
+
# Preprocess eps array in order
|
|
68
|
+
eps = self.preprocess_strains_with_limits(eps=eps)
|
|
69
|
+
# Compute stress
|
|
70
|
+
# Polynomial branch
|
|
71
|
+
eta = eps / self._eps_c1
|
|
72
|
+
|
|
73
|
+
sig = self._fc * (self._k * eta - eta**2) / (1 + (self._k - 2) * eta)
|
|
74
|
+
|
|
75
|
+
# Elsewhere stress is 0.0
|
|
76
|
+
if np.isscalar(eps):
|
|
77
|
+
if eps < self._eps_cu1 or eps > 0:
|
|
78
|
+
return 0.0
|
|
79
|
+
else:
|
|
80
|
+
sig[eps < self._eps_cu1] = 0.0
|
|
81
|
+
sig[eps > 0] = 0.0
|
|
82
|
+
|
|
83
|
+
return sig
|
|
84
|
+
|
|
85
|
+
def get_tangent(
|
|
86
|
+
self, eps: t.Union[float, ArrayLike]
|
|
87
|
+
) -> t.Union[float, ArrayLike]:
|
|
88
|
+
"""Return the tangent given strain."""
|
|
89
|
+
eps = eps if np.isscalar(eps) else np.atleast_1d(eps)
|
|
90
|
+
# polynomial branch
|
|
91
|
+
eta = eps / self._eps_c1
|
|
92
|
+
|
|
93
|
+
tangent = (
|
|
94
|
+
self._fc
|
|
95
|
+
/ self._eps_c1
|
|
96
|
+
* ((2 - self._k) * eta**2 - 2 * eta + self._k)
|
|
97
|
+
/ (1 + (self._k - 2) * eta) ** 2
|
|
98
|
+
)
|
|
99
|
+
# Elsewhere tangent is zero
|
|
100
|
+
if np.isscalar(eps):
|
|
101
|
+
if eps < self._eps_cu1 or eps > 0:
|
|
102
|
+
return 0
|
|
103
|
+
else:
|
|
104
|
+
tangent[eps < self._eps_cu1] = 0.0
|
|
105
|
+
tangent[eps > 0] = 0.0
|
|
106
|
+
|
|
107
|
+
return tangent
|
|
108
|
+
|
|
109
|
+
def get_ultimate_strain(
|
|
110
|
+
self, yielding: bool = False
|
|
111
|
+
) -> t.Tuple[float, float]:
|
|
112
|
+
"""Return the ultimate strain (negative and positive)."""
|
|
113
|
+
if yielding:
|
|
114
|
+
return (self._eps_c1, 100)
|
|
115
|
+
return (self._eps_cu1, 100)
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""User defined constitutive law."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations # To have clean hints of ArrayLike in docs
|
|
4
|
+
|
|
5
|
+
import typing as t
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from numpy.typing import ArrayLike
|
|
9
|
+
|
|
10
|
+
from ...core.base import ConstitutiveLaw
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UserDefined(ConstitutiveLaw):
|
|
14
|
+
"""Class for a user defined constitutive law.
|
|
15
|
+
|
|
16
|
+
The curve is defined with positive and optionally negative values. After
|
|
17
|
+
the last value, the stress can go to zero to simulate failure (default), or
|
|
18
|
+
be maintained constante, or the last tanget or secant values may be
|
|
19
|
+
maintained indefinetely. The flag parameter controls this behavior.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
__materials__: t.Tuple[str] = ('concrete', 'steel', 'rebars')
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
x: ArrayLike,
|
|
27
|
+
y: ArrayLike,
|
|
28
|
+
name: t.Optional[str] = None,
|
|
29
|
+
flag: int = 0,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Initialize a UserDefined constitutive law.
|
|
32
|
+
|
|
33
|
+
Arguments:
|
|
34
|
+
x (ArrayLike): Data for strains.
|
|
35
|
+
y (ArrayLike): Data for stresses. Must be of same length as x.
|
|
36
|
+
|
|
37
|
+
Keyword Arguments:
|
|
38
|
+
name (Optional, str): A name for the constitutive law.
|
|
39
|
+
flag (Optional): A flag specifying the behavior after the last
|
|
40
|
+
point. Admissible values: 0 (default): stress drops to zero
|
|
41
|
+
after ultimate strain, 1: stress is mantained constant, 2:
|
|
42
|
+
last tangent is used, 3: last secant is used.
|
|
43
|
+
"""
|
|
44
|
+
name = name if name is not None else 'UserDefinedLaw'
|
|
45
|
+
super().__init__(name=name)
|
|
46
|
+
x = np.atleast_1d(np.asarray(x))
|
|
47
|
+
y = np.atleast_1d(np.asarray(y))
|
|
48
|
+
if len(x) != len(y):
|
|
49
|
+
raise ValueError('The two arrays should have the same length')
|
|
50
|
+
if not np.any(x < 0):
|
|
51
|
+
# User provided only positive part, reflect in negative
|
|
52
|
+
self._x = np.concatenate((-np.flip(x)[:-1], x))
|
|
53
|
+
self._y = np.concatenate((-np.flip(y)[:-1], y))
|
|
54
|
+
else:
|
|
55
|
+
# User gave both positive and negative parts
|
|
56
|
+
self._x = x
|
|
57
|
+
self._y = y
|
|
58
|
+
# Define what happens after last strain
|
|
59
|
+
if flag not in (0, 1, 2, 3):
|
|
60
|
+
raise ValueError('Flag can assume values 0, 1, 2 or 3.')
|
|
61
|
+
self._ultimate_strain_p = self._x[-1]
|
|
62
|
+
self._ultimate_strain_n = self._x[0]
|
|
63
|
+
if flag in (1, 2, 3):
|
|
64
|
+
x = np.insert(self._x, 0, self._x[0] * 100)
|
|
65
|
+
x = np.append(x, self._x[-1] * 100)
|
|
66
|
+
if flag == 1:
|
|
67
|
+
y = np.insert(self._y, 0, self._y[0])
|
|
68
|
+
y = np.append(y, self._y[-1])
|
|
69
|
+
elif flag == 2:
|
|
70
|
+
tangent_p = (self._y[-1] - self._y[-2]) / (
|
|
71
|
+
self._x[-1] - self._x[-2]
|
|
72
|
+
)
|
|
73
|
+
tangent_n = (self._y[1] - self._y[0]) / (
|
|
74
|
+
self._x[1] - self._x[0]
|
|
75
|
+
)
|
|
76
|
+
y = np.insert(
|
|
77
|
+
self._y, 0, (x[0] - x[1]) * tangent_n + self._y[0]
|
|
78
|
+
)
|
|
79
|
+
y = np.append(y, (x[-1] - x[-2]) * tangent_p + self._y[-1])
|
|
80
|
+
elif flag == 3:
|
|
81
|
+
secant_p = self._y[-1] / self._x[-1]
|
|
82
|
+
secant_n = self._y[0] / self._x[0]
|
|
83
|
+
y = np.insert(
|
|
84
|
+
self._y, 0, (x[0] - x[1]) * secant_n + self._y[0]
|
|
85
|
+
)
|
|
86
|
+
y = np.append(y, (x[-1] - x[-2]) * secant_p + self._y[-1])
|
|
87
|
+
self._x = x
|
|
88
|
+
self._y = y
|
|
89
|
+
|
|
90
|
+
# Compute slope of each segment
|
|
91
|
+
self._slopes = np.diff(self._y) / np.diff(self._x)
|
|
92
|
+
|
|
93
|
+
def get_stress(
|
|
94
|
+
self, eps: t.Union[float, ArrayLike]
|
|
95
|
+
) -> t.Union[float, ArrayLike]:
|
|
96
|
+
"""Return the stress given strain."""
|
|
97
|
+
eps = eps if np.isscalar(eps) else np.atleast_1d(eps)
|
|
98
|
+
# Preprocess eps array in order
|
|
99
|
+
eps = self.preprocess_strains_with_limits(eps=eps)
|
|
100
|
+
# Compute stress
|
|
101
|
+
return np.interp(eps, self._x, self._y, left=0, right=0)
|
|
102
|
+
|
|
103
|
+
def get_tangent(
|
|
104
|
+
self, eps: t.Union[float, ArrayLike]
|
|
105
|
+
) -> t.Union[float, ArrayLike]:
|
|
106
|
+
"""Return the tangent given strain."""
|
|
107
|
+
eps = eps if np.isscalar(eps) else np.atleast_1d(eps)
|
|
108
|
+
|
|
109
|
+
# Find the segment index for each x value
|
|
110
|
+
indices = np.searchsorted(self._x, eps) - 1
|
|
111
|
+
|
|
112
|
+
# Check that indices are within vlaid range
|
|
113
|
+
indices = np.clip(indices, 0, len(self._slopes) - 1)
|
|
114
|
+
|
|
115
|
+
# Get the corresponding slopes
|
|
116
|
+
tangent = self._slopes[indices]
|
|
117
|
+
|
|
118
|
+
# Elsewhere tangent is zero
|
|
119
|
+
if np.isscalar(eps):
|
|
120
|
+
if eps < self._x[0] or eps > self._x[-1]:
|
|
121
|
+
tangent = 0
|
|
122
|
+
else:
|
|
123
|
+
tangent[eps < self._x[0]] = 0.0
|
|
124
|
+
tangent[eps > self._x[-1]] = 0.0
|
|
125
|
+
|
|
126
|
+
return tangent
|
|
127
|
+
|
|
128
|
+
def __marin__(
|
|
129
|
+
self, strain: t.Tuple[float, float]
|
|
130
|
+
) -> t.Tuple[t.List[t.Tuple], t.List[t.Tuple]]:
|
|
131
|
+
"""Returns coefficients and strain limits for Marin integration in a
|
|
132
|
+
simply formatted way.
|
|
133
|
+
|
|
134
|
+
Arguments:
|
|
135
|
+
strain (float, float): Tuple defining the strain profile: eps =
|
|
136
|
+
strain[0] + strain[1]*y.
|
|
137
|
+
|
|
138
|
+
Example:
|
|
139
|
+
[(0, -0.002), (-0.002, -0.003)]
|
|
140
|
+
[(a0, a1, a2), (a0)]
|
|
141
|
+
"""
|
|
142
|
+
strains = []
|
|
143
|
+
coeff = []
|
|
144
|
+
if strain[1] == 0:
|
|
145
|
+
# Uniform strain equal to strain[0]
|
|
146
|
+
# understand in which branch are we
|
|
147
|
+
strain[0] = self.preprocess_strains_with_limits(strain[0])
|
|
148
|
+
found = False
|
|
149
|
+
for i in range(len(self._x) - 1):
|
|
150
|
+
if self._x[i] <= strain[0] and self._x[i + 1] >= strain[0]:
|
|
151
|
+
strains = None
|
|
152
|
+
stiffness = (self._y[i + 1] - self._y[i]) / (
|
|
153
|
+
self._x[i + 1] - self._x[i]
|
|
154
|
+
)
|
|
155
|
+
a0 = stiffness * (strain[0] - self._x[i]) + self._y[i]
|
|
156
|
+
a1 = stiffness * strain[1]
|
|
157
|
+
coeff.append((a0, a1))
|
|
158
|
+
found = True
|
|
159
|
+
break
|
|
160
|
+
if not found:
|
|
161
|
+
strains = None
|
|
162
|
+
coeff.append((0.0,))
|
|
163
|
+
else:
|
|
164
|
+
for i in range(len(self._x) - 1):
|
|
165
|
+
# For each branch of the linear piecewise function
|
|
166
|
+
stiffness = (self._y[i + 1] - self._y[i]) / (
|
|
167
|
+
self._x[i + 1] - self._x[i]
|
|
168
|
+
)
|
|
169
|
+
strains.append((self._x[i], self._x[i + 1]))
|
|
170
|
+
a0 = stiffness * (strain[0] - self._x[i]) + self._y[i]
|
|
171
|
+
a1 = stiffness * strain[1]
|
|
172
|
+
coeff.append((a0, a1))
|
|
173
|
+
|
|
174
|
+
return strains, coeff
|
|
175
|
+
|
|
176
|
+
def get_ultimate_strain(self, **kwargs) -> t.Tuple[float, float]:
|
|
177
|
+
"""Return the ultimate strain (negative and positive)."""
|
|
178
|
+
del kwargs
|
|
179
|
+
return (self._ultimate_strain_n, self._ultimate_strain_p)
|
|
180
|
+
|
|
181
|
+
def set_ultimate_strain(
|
|
182
|
+
self, eps_su=t.Union[float, t.Tuple[float, float]]
|
|
183
|
+
) -> None:
|
|
184
|
+
"""Set ultimate strains for Elastic Material if needed.
|
|
185
|
+
|
|
186
|
+
Arguments:
|
|
187
|
+
eps_su (float or (float, float)): Defining ultimate strain. If a
|
|
188
|
+
single value is provided the same is adopted for both negative
|
|
189
|
+
and positive strains. If a tuple is provided, it should be
|
|
190
|
+
given as (negative, positive).
|
|
191
|
+
"""
|
|
192
|
+
if isinstance(eps_su, float):
|
|
193
|
+
self._ultimate_strain_p = abs(eps_su)
|
|
194
|
+
self._ultimate_strain_n = -abs(eps_su)
|
|
195
|
+
elif isinstance(eps_su, tuple):
|
|
196
|
+
if len(eps_su) < 2:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
'Two values need to be provided when setting the tuple'
|
|
199
|
+
)
|
|
200
|
+
eps_su_n = eps_su[0]
|
|
201
|
+
eps_su_p = eps_su[1]
|
|
202
|
+
if eps_su_p < eps_su_n:
|
|
203
|
+
eps_su_p, eps_su_n = eps_su_n, eps_su_p
|
|
204
|
+
if eps_su_p < 0:
|
|
205
|
+
raise ValueError(
|
|
206
|
+
'Positive ultimate strain should be non-negative'
|
|
207
|
+
)
|
|
208
|
+
if eps_su_n > 0:
|
|
209
|
+
raise ValueError(
|
|
210
|
+
'Negative utimate strain should be non-positive'
|
|
211
|
+
)
|
|
212
|
+
self._ultimate_strain_p = eps_su_p
|
|
213
|
+
self._ultimate_strain_n = eps_su_n
|
|
214
|
+
else:
|
|
215
|
+
raise ValueError(
|
|
216
|
+
'set_ultimate_strain requires a single value or a tuple \
|
|
217
|
+
with two values'
|
|
218
|
+
)
|
|
@@ -55,6 +55,16 @@ class GenericSection(Section):
|
|
|
55
55
|
of the section.
|
|
56
56
|
name (str): The name of the section.
|
|
57
57
|
integrator (str): The name of the SectionIntegrator to use.
|
|
58
|
+
kwargs (dict): A collection of keyword arguments to pass on to the
|
|
59
|
+
section calculator.
|
|
60
|
+
|
|
61
|
+
Note:
|
|
62
|
+
The GenericSection uses a GenericSectionCalculator for all
|
|
63
|
+
calculations. The GenericSectionCalculator uses a SectionIntegrator
|
|
64
|
+
for integrating over the section. Any additional keyword arguments
|
|
65
|
+
used when creating the GenericSection are passed on to the
|
|
66
|
+
SectionCalculator to customize the behaviour. See
|
|
67
|
+
GenericSectionCalculator for available keyword arguments.
|
|
58
68
|
"""
|
|
59
69
|
if name is None:
|
|
60
70
|
name = 'GenericSection'
|
|
@@ -98,7 +108,7 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
98
108
|
(default = 'marin').
|
|
99
109
|
|
|
100
110
|
Note:
|
|
101
|
-
When using
|
|
111
|
+
When using `fiber` integrator the kwarg `mesh_size` can be used to
|
|
102
112
|
specify a dimensionless number (between 0 and 1) specifying the
|
|
103
113
|
size of the resulting mesh.
|
|
104
114
|
"""
|
|
@@ -142,13 +152,13 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
142
152
|
# Computation of surface area, reinforcement area, EA (axial rigidity)
|
|
143
153
|
# and mass: Morten -> problem with units! how do we deal with it?
|
|
144
154
|
for geo in self.section.geometry.geometries:
|
|
145
|
-
gp.ea += geo.area * geo.material.get_tangent(eps=0)
|
|
155
|
+
gp.ea += geo.area * geo.material.get_tangent(eps=0)
|
|
146
156
|
if geo.density is not None:
|
|
147
157
|
# this assumes area in mm2 and density in kg/m3
|
|
148
158
|
gp.mass += geo.area * geo.density * 1e-9
|
|
149
159
|
|
|
150
160
|
for geo in self.section.geometry.point_geometries:
|
|
151
|
-
gp.ea += geo.area * geo.material.get_tangent(eps=0)
|
|
161
|
+
gp.ea += geo.area * geo.material.get_tangent(eps=0)
|
|
152
162
|
gp.area_reinforcement += geo.area
|
|
153
163
|
if geo.density is not None:
|
|
154
164
|
# this assumes area in mm2 and density in kg/m3
|
|
@@ -103,9 +103,7 @@ class FiberIntegrator(SectionIntegrator):
|
|
|
103
103
|
# define the maximum area of the triangles
|
|
104
104
|
max_area = g.area * mesh_size
|
|
105
105
|
# triangulate the geometry getting back the mesh
|
|
106
|
-
mesh = triangle.triangulate(
|
|
107
|
-
tri, f'pq{30:.1f}Aa{max_area:.1f}o1'
|
|
108
|
-
)
|
|
106
|
+
mesh = triangle.triangulate(tri, f'pq{30:.1f}Aa{max_area}o1')
|
|
109
107
|
mat = g.material
|
|
110
108
|
# Get x and y coordinates (centroid) and area for each fiber
|
|
111
109
|
x = []
|
|
@@ -143,7 +143,7 @@ class MarinIntegrator(SectionIntegrator):
|
|
|
143
143
|
strain = strain_rotated[0] + strain_rotated[1] * yp
|
|
144
144
|
x.append(xp)
|
|
145
145
|
y.append(yp)
|
|
146
|
-
F.append(pg.material.get_stress(strain)
|
|
146
|
+
F.append(pg.material.get_stress(strain) * A)
|
|
147
147
|
prepared_input.append((1, np.array(x), np.array(y), np.array(F)))
|
|
148
148
|
|
|
149
149
|
return angle, prepared_input
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: structuralcodes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A Python package that contains models from structural design codes.
|
|
5
5
|
Author-email: fib - International Federation for Structural Concrete <info@fib-international.org>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
structuralcodes/__init__.py,sha256=
|
|
1
|
+
structuralcodes/__init__.py,sha256=pxmTgFCzRRSx9OPXM_I5KbP045gFiNqoR_v6N1Ni7as,390
|
|
2
2
|
structuralcodes/codes/__init__.py,sha256=g5xMAJ3jEZHFd0cypvZY6lMCi7XeVEntsO8zHzI2mWc,2803
|
|
3
|
-
structuralcodes/codes/ec2_2004/__init__.py,sha256=
|
|
3
|
+
structuralcodes/codes/ec2_2004/__init__.py,sha256=DljXFNrCGE1lZIOsgyZgJ7Xo-xUidJomDrDKyfOHcH8,2431
|
|
4
|
+
structuralcodes/codes/ec2_2004/_concrete_creep_and_shrinkage.py,sha256=y4HhOpaXwNMCHh4wu4LSn14oD1ylpPNvVJOJXLxStzQ,15284
|
|
4
5
|
structuralcodes/codes/ec2_2004/_concrete_material_properties.py,sha256=Ol51tzcVOHUvc2Vea24WQJ4FABxXc-9cB5RVu2N1pio,5964
|
|
5
6
|
structuralcodes/codes/ec2_2004/_reinforcement_material_properties.py,sha256=_ZlvdHcOswu1Ge1XjSvt4j5ue-znDceMOlA0s528IqM,2779
|
|
6
7
|
structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py,sha256=a91tWQKNTxB2SpSKu0Wtm-P5GdmifRLggNlEHIQ3XMY,31981
|
|
7
|
-
structuralcodes/codes/ec2_2004/annex_b_shrink_and_creep.py,sha256=kaMXZ_Ufp-k1wYQDXB27Tt2BUmi_lGYYuNzQxGtC6SQ,7348
|
|
8
8
|
structuralcodes/codes/ec2_2004/shear.py,sha256=gzhgIa-EgoD9gLO_Hfa8VeCmjAxuPK0wZ0soDKC7W5w,17095
|
|
9
9
|
structuralcodes/codes/ec2_2023/__init__.py,sha256=UohRxikCUqPAUpHj4uSWHw5drICjZm3zvJJw7clljo0,1618
|
|
10
10
|
structuralcodes/codes/ec2_2023/_annexB_time_dependent.py,sha256=ykRAHBHzqtMSErkVA-rwTHBdUq8-L7q2AOaEd2YW5wc,472
|
|
@@ -21,31 +21,38 @@ structuralcodes/codes/mc2010/_reinforcement_material_properties.py,sha256=FELmgM
|
|
|
21
21
|
structuralcodes/codes/mc2020/__init__.py,sha256=5hrAfBtAeG69N_lroFpG10_ZKB1SuNlKBnuHug2DI3E,174
|
|
22
22
|
structuralcodes/core/__init__.py,sha256=spnvZIm_w3jX_lV-v3bloDjgHh8lrH6UHpA1Nv1zeAI,55
|
|
23
23
|
structuralcodes/core/_section_results.py,sha256=hHXoS71TpSmWqw276pBeLiLrEEiMEWclOd28ArRW_Kk,8280
|
|
24
|
-
structuralcodes/core/base.py,sha256=
|
|
24
|
+
structuralcodes/core/base.py,sha256=7cpDM2hvBZp9nyU714XRiMzDPNdydJqLtIHHvcXZctE,8935
|
|
25
25
|
structuralcodes/geometry/__init__.py,sha256=FwzywfyGKOk6v96ZyOfyBo5iVeuK_W0TQVz5llAkYW4,559
|
|
26
|
-
structuralcodes/geometry/_geometry.py,sha256=
|
|
26
|
+
structuralcodes/geometry/_geometry.py,sha256=8usT5UfDlT-A8sMwM6Bh4YKIB9QuyAU5tGgsujeACEA,31240
|
|
27
27
|
structuralcodes/geometry/_reinforcement.py,sha256=N2wTH-NoZ1fG-_vRT9gGX2Kk3zlW7CbDtl1oqS_lMv0,4144
|
|
28
28
|
structuralcodes/geometry/_steel_sections.py,sha256=UdJmhhnK8r5gEfBzvWsMFHGs5gmuoOhFoduBanlRMQg,60225
|
|
29
29
|
structuralcodes/materials/__init__.py,sha256=r5E5vsXVKB-BGZXTnEbsrYJbH6rr6Xlc_b4LlcUPIbc,173
|
|
30
|
-
structuralcodes/materials/constitutive_laws.py,sha256=DX_yuC4OpgDCl_g3sl0Hi2ee7lFD2fy3yO4PTINKBzE,34455
|
|
31
30
|
structuralcodes/materials/concrete/__init__.py,sha256=GRD5WcbYrnE4iN-L7qVkhVTi7w_PUP7pnbGueOaVeFs,2576
|
|
32
31
|
structuralcodes/materials/concrete/_concrete.py,sha256=3zMTFtaqFeUl7ne7-pe9wF4LryzqvGpUwThnHTidCZU,3774
|
|
33
32
|
structuralcodes/materials/concrete/_concreteEC2_2004.py,sha256=gWG3O9yeGw3UeftCjYTajZco_XYDmBxPGqhAEpH3nY0,14666
|
|
34
33
|
structuralcodes/materials/concrete/_concreteEC2_2023.py,sha256=vguNzlfoPuaieTVw9T3xWU0wb230WvER4Vy1jswcdlo,14017
|
|
35
34
|
structuralcodes/materials/concrete/_concreteMC2010.py,sha256=lHy-WYiVpXPwiNAyjUBxuGWuGFd0-Uirh6KiolMH4MY,15313
|
|
35
|
+
structuralcodes/materials/constitutive_laws/__init__.py,sha256=r817qyeimqZyyan2mU8cVwjwMkiB--f-BOIBSzXKiZo,2954
|
|
36
|
+
structuralcodes/materials/constitutive_laws/_bilinearcompression.py,sha256=mkuMSiKpfZv-meIvHedrlILfRBdOsR46QCiaiyxPxVs,4528
|
|
37
|
+
structuralcodes/materials/constitutive_laws/_elastic.py,sha256=Kl-A_3W2qoJUEPE3meWABSqUlNChMExiq2LdRehbqrI,3722
|
|
38
|
+
structuralcodes/materials/constitutive_laws/_elasticplastic.py,sha256=GDIIXJ93nqV-G8-o6HxXGUTd3TgNWiHQqXbULFcCGUI,6096
|
|
39
|
+
structuralcodes/materials/constitutive_laws/_parabolarectangle.py,sha256=CvjmiGCmNTqxY6d5jNqCo6MAh_BUkypvv_-ZJB9JyQE,6489
|
|
40
|
+
structuralcodes/materials/constitutive_laws/_popovics.py,sha256=dpXFQ9KHE245C9dgOLz9KXYHZiAYrRan5exgj0j_JxM,4322
|
|
41
|
+
structuralcodes/materials/constitutive_laws/_sargin.py,sha256=WJGw0EtqkPh-d3N6vTPRIfhE1Ypyc16JpGcoi-0U1A8,3495
|
|
42
|
+
structuralcodes/materials/constitutive_laws/_userdefined.py,sha256=urt0yuJicO51jnQ2S8bfmrgVTyYh09Olnzy9_tISGK4,8292
|
|
36
43
|
structuralcodes/materials/reinforcement/__init__.py,sha256=-UA04GSNN6_xLKqnH_5taiOmgxYwD_wtT6Nw8UbfkJY,2757
|
|
37
44
|
structuralcodes/materials/reinforcement/_reinforcement.py,sha256=zrSdBvHKTYqOHpkJzxit8w_b2JG2pggviOvgZyH246Q,5029
|
|
38
45
|
structuralcodes/materials/reinforcement/_reinforcementEC2_2004.py,sha256=svLpubjaTH_DepwY68TQIA8fRwadoAE3Y3KsyViGQHk,3265
|
|
39
46
|
structuralcodes/materials/reinforcement/_reinforcementEC2_2023.py,sha256=3tKpFcMNYK52s5K2K_PctRcuSgwZTe-QXX3xziHPUno,2887
|
|
40
47
|
structuralcodes/materials/reinforcement/_reinforcementMC2010.py,sha256=az_IAQJNKSF6Vv9KMoXjWTdYkWI6xcEm7s8i8GETn3A,2939
|
|
41
48
|
structuralcodes/sections/__init__.py,sha256=qPoD5eS31at-uveYtxtVkXGLNHPrIMRrxGYY3wOLQ4s,441
|
|
42
|
-
structuralcodes/sections/_generic.py,sha256=
|
|
49
|
+
structuralcodes/sections/_generic.py,sha256=I_YQNeK9ww3wDtkSBlhF7u6gXVAj2I5Sttv9i-uk8UI,50525
|
|
43
50
|
structuralcodes/sections/section_integrators/__init__.py,sha256=PK4ixV0XrfHXN-itIrB1r90npoWo3aIJqMcenqcaees,399
|
|
44
51
|
structuralcodes/sections/section_integrators/_factory.py,sha256=MHp14hfWU-oXTiIutCKLJEC47LirYsHgEAAmHVtnFMY,1242
|
|
45
|
-
structuralcodes/sections/section_integrators/_fiber_integrator.py,sha256=
|
|
52
|
+
structuralcodes/sections/section_integrators/_fiber_integrator.py,sha256=Ucas8nA9BB4ILfFPplJp3WkgLc9ntf9UN7AmcUwqA_A,9263
|
|
46
53
|
structuralcodes/sections/section_integrators/_marin_integration.py,sha256=SZgya6d_Tequ3jez7UEBlYioZepW2IDKaAxn_6WrMbU,1563
|
|
47
|
-
structuralcodes/sections/section_integrators/_marin_integrator.py,sha256=
|
|
54
|
+
structuralcodes/sections/section_integrators/_marin_integrator.py,sha256=DHAJwurHhVp68K9fozw0MbmxZvk_NAKnNVi5abp65sY,9118
|
|
48
55
|
structuralcodes/sections/section_integrators/_section_integrator.py,sha256=O-jsG1Pu_doovgRJsFG1Sf0KlkN2wNfQdmgkJiSHNN0,1590
|
|
49
|
-
structuralcodes-0.
|
|
50
|
-
structuralcodes-0.
|
|
51
|
-
structuralcodes-0.
|
|
56
|
+
structuralcodes-0.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
|
57
|
+
structuralcodes-0.2.0.dist-info/METADATA,sha256=7RAyKNKlQYjXC3sFiVRWTwp3HUMAhN5SvJAvcF2LTZ0,2444
|
|
58
|
+
structuralcodes-0.2.0.dist-info/RECORD,,
|