structuralcodes 0.2.0__py3-none-any.whl → 0.3.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/_concrete_creep_and_shrinkage.py +1 -1
- structuralcodes/codes/mc2010/_concrete_creep_and_shrinkage.py +105 -73
- structuralcodes/core/_section_results.py +5 -19
- structuralcodes/core/base.py +26 -11
- structuralcodes/geometry/__init__.py +10 -1
- structuralcodes/geometry/_circular.py +81 -0
- structuralcodes/geometry/_geometry.py +1 -1
- structuralcodes/geometry/_rectangular.py +83 -0
- structuralcodes/geometry/_reinforcement.py +132 -5
- structuralcodes/materials/constitutive_laws/_bilinearcompression.py +46 -1
- structuralcodes/materials/constitutive_laws/_elastic.py +19 -0
- structuralcodes/materials/constitutive_laws/_elasticplastic.py +55 -0
- structuralcodes/materials/constitutive_laws/_parabolarectangle.py +57 -0
- structuralcodes/materials/constitutive_laws/_userdefined.py +44 -0
- structuralcodes/sections/__init__.py +2 -0
- structuralcodes/sections/_generic.py +161 -24
- structuralcodes/sections/_rc_utils.py +114 -0
- structuralcodes/sections/section_integrators/_fiber_integrator.py +204 -108
- structuralcodes/sections/section_integrators/_marin_integrator.py +273 -102
- structuralcodes/sections/section_integrators/_section_integrator.py +28 -4
- {structuralcodes-0.2.0.dist-info → structuralcodes-0.3.0.dist-info}/METADATA +2 -2
- {structuralcodes-0.2.0.dist-info → structuralcodes-0.3.0.dist-info}/RECORD +24 -21
- {structuralcodes-0.2.0.dist-info → structuralcodes-0.3.0.dist-info}/WHEEL +1 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Classes for rectangular geometries.
|
|
2
|
+
|
|
3
|
+
The class `RectangularGeometry` represents a rectangular SurfaceGeometry with
|
|
4
|
+
homogenous material.
|
|
5
|
+
This class is simply a wrapper of `SurfaceGeometry` class and permits an easy
|
|
6
|
+
input by the user.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import typing as t
|
|
10
|
+
|
|
11
|
+
from shapely import Polygon
|
|
12
|
+
|
|
13
|
+
from structuralcodes.core.base import ConstitutiveLaw, Material
|
|
14
|
+
|
|
15
|
+
from ._geometry import SurfaceGeometry
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RectangularGeometry(SurfaceGeometry):
|
|
19
|
+
"""This is a wrapper class for defining a `SurfaceGeometry` of rectangular
|
|
20
|
+
shape with a homogeneous material.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
_width: float
|
|
24
|
+
_height: float
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
width: float,
|
|
29
|
+
height: float,
|
|
30
|
+
material: t.Union[Material, ConstitutiveLaw],
|
|
31
|
+
density: t.Optional[float] = None,
|
|
32
|
+
concrete: bool = False,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Initialize a RectangularGeometry.
|
|
35
|
+
|
|
36
|
+
Arguments:
|
|
37
|
+
width (float): The width of the geometry.
|
|
38
|
+
height (float): The height of the geometry.
|
|
39
|
+
material (Union(Material, ConstitutiveLaw)): A Material or
|
|
40
|
+
ConsitutiveLaw class applied to the geometry.
|
|
41
|
+
density (Optional(float)): When a ConstitutiveLaw is passed as
|
|
42
|
+
material, the density can be provided by this argument. When
|
|
43
|
+
material is a Material object the density is taken from the
|
|
44
|
+
material.
|
|
45
|
+
concrete (bool): Flag to indicate if the geometry is concrete. When
|
|
46
|
+
passing a Material as material, this is automatically inferred.
|
|
47
|
+
|
|
48
|
+
Note:
|
|
49
|
+
The RectangularGeometry is simply a wrapper for a SurfaceGeometry
|
|
50
|
+
object.
|
|
51
|
+
"""
|
|
52
|
+
# Check that size is strictly positive
|
|
53
|
+
if width <= 0:
|
|
54
|
+
raise ValueError('Width must be a positive number.')
|
|
55
|
+
if height <= 0:
|
|
56
|
+
raise ValueError('Height must be a positive number.')
|
|
57
|
+
|
|
58
|
+
self._width = width
|
|
59
|
+
self._height = height
|
|
60
|
+
|
|
61
|
+
# Create the shapely polygon
|
|
62
|
+
polygon = Polygon(
|
|
63
|
+
(
|
|
64
|
+
(-width / 2, -height / 2),
|
|
65
|
+
(width / 2, -height / 2),
|
|
66
|
+
(width / 2, height / 2),
|
|
67
|
+
(-width / 2, height / 2),
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
# Pass everything to the base class
|
|
71
|
+
super().__init__(
|
|
72
|
+
poly=polygon, material=material, density=density, concrete=concrete
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def width(self):
|
|
77
|
+
"""Returns the width of the rectangle."""
|
|
78
|
+
return self._width
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def height(self):
|
|
82
|
+
"""Return the height of the rectangle."""
|
|
83
|
+
return self._height
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
"""Functions related to reinforcement definition."""
|
|
2
2
|
|
|
3
|
+
import math
|
|
3
4
|
import typing as t
|
|
4
5
|
|
|
5
6
|
import numpy as np
|
|
6
7
|
from shapely import Point
|
|
7
8
|
|
|
8
9
|
from structuralcodes.core.base import ConstitutiveLaw, Material
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
PointGeometry,
|
|
12
|
-
SurfaceGeometry,
|
|
13
|
-
)
|
|
10
|
+
|
|
11
|
+
from ._geometry import CompoundGeometry, PointGeometry, SurfaceGeometry
|
|
14
12
|
|
|
15
13
|
|
|
16
14
|
def add_reinforcement(
|
|
@@ -125,3 +123,132 @@ def add_reinforcement_line(
|
|
|
125
123
|
group_label=group_label,
|
|
126
124
|
)
|
|
127
125
|
return geo
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def add_reinforcement_circle(
|
|
129
|
+
geo: t.Union[SurfaceGeometry, CompoundGeometry],
|
|
130
|
+
center: t.Tuple[float, float],
|
|
131
|
+
radius: float,
|
|
132
|
+
diameter: float,
|
|
133
|
+
material: t.Union[Material, ConstitutiveLaw],
|
|
134
|
+
n: int = 0,
|
|
135
|
+
s: float = 0.0,
|
|
136
|
+
first: bool = True,
|
|
137
|
+
last: bool = True,
|
|
138
|
+
start_angle: float = 0.0,
|
|
139
|
+
stop_angle: float = 2 * np.pi,
|
|
140
|
+
group_label: t.Optional[str] = None,
|
|
141
|
+
) -> CompoundGeometry:
|
|
142
|
+
"""Adds a set of bars distributed in a circular arch line.
|
|
143
|
+
By default the whole circle is considered. If one wants to specify a
|
|
144
|
+
circular arch, the `start_angle` and `stop_angle` attributes need to be
|
|
145
|
+
specified.
|
|
146
|
+
|
|
147
|
+
Arguments:
|
|
148
|
+
geo (Union(SurfaceGeometry, CompoundGeometry)): The geometry used as
|
|
149
|
+
input.
|
|
150
|
+
center (Tuple(float, float)): Coordinates of the center point of
|
|
151
|
+
the circle line where reinforcement will be added.
|
|
152
|
+
radius (float): Radius of the circle line where reinforcement will be
|
|
153
|
+
added.
|
|
154
|
+
diameter (float): The diameter of the bars.
|
|
155
|
+
material (Union(Material, ConstitutiveLaw)): A valid material or
|
|
156
|
+
constitutive law.
|
|
157
|
+
n (int): The number of bars to be distributed inside the line (default
|
|
158
|
+
= 0).
|
|
159
|
+
s (float): The distance between the bars (default = 0).
|
|
160
|
+
first (bool): Boolean indicating if placing the first bar (default =
|
|
161
|
+
True).
|
|
162
|
+
last (bool): Boolean indicating if placing the last bar (default =
|
|
163
|
+
True).
|
|
164
|
+
start_angle (float): Start angle (respect to X axis) for defining the
|
|
165
|
+
arch where to add bars in radians (default = 0)
|
|
166
|
+
stop_angle (float): Stop angle (respect to X axis) for defining the
|
|
167
|
+
arch where to add bars in radians (default = 2pi)
|
|
168
|
+
group_label (Optional(str)): A label for grouping several objects
|
|
169
|
+
(default is None).
|
|
170
|
+
|
|
171
|
+
Note:
|
|
172
|
+
At least n or s should be greater than zero.
|
|
173
|
+
Attribues start_angle and stop_angle by default are 0 and 2pi
|
|
174
|
+
respectively, so that bars will be distributed along the whole circle.
|
|
175
|
+
If only a portion of the circle must be used (i.e. an arch of
|
|
176
|
+
circumference), then set start and stop angles correspondingly.
|
|
177
|
+
stop_angle must always be larger than start_angle.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
CompoundGeometry: A compound geometry with the original geometry and
|
|
181
|
+
the reinforcement.
|
|
182
|
+
"""
|
|
183
|
+
# Check that difference between stop and start angle is
|
|
184
|
+
# positive and less than 2pi
|
|
185
|
+
if stop_angle - start_angle <= 0 or stop_angle - start_angle > 2 * np.pi:
|
|
186
|
+
raise ValueError(
|
|
187
|
+
'Stop angle should be larger than start angle and difference \
|
|
188
|
+
them should be at most 2pi.'
|
|
189
|
+
)
|
|
190
|
+
# Calculate length from start_angle to stop_angle
|
|
191
|
+
length = radius * (stop_angle - start_angle)
|
|
192
|
+
|
|
193
|
+
# If the whole circle, than deal with the case that would add an extra bar
|
|
194
|
+
whole = math.isclose(length - 2 * np.pi * radius, 0, abs_tol=1e-4)
|
|
195
|
+
add_n = 0 if not whole else 1
|
|
196
|
+
|
|
197
|
+
# delta_angle is used if we need to center the set of bars
|
|
198
|
+
# in the curve.
|
|
199
|
+
delta_angle = 0
|
|
200
|
+
if n > 0 and s > 0:
|
|
201
|
+
# Provided both the number of bars and spacing
|
|
202
|
+
# Check there is enough space for fitting the bars
|
|
203
|
+
n += add_n
|
|
204
|
+
needed_length = (n - 1) * s
|
|
205
|
+
if needed_length > length:
|
|
206
|
+
raise ValueError(
|
|
207
|
+
f'There is not room to fit {n} bars with a spacing of {s} \
|
|
208
|
+
in {length}'
|
|
209
|
+
)
|
|
210
|
+
# Compute delta_angle to make bars centered in the curvilinear segment
|
|
211
|
+
delta_angle = (length - needed_length) / 2.0 / radius
|
|
212
|
+
elif n > 0:
|
|
213
|
+
# Provided the number of bars
|
|
214
|
+
s = length / (n - 1)
|
|
215
|
+
# If we are distributing bars i the whole circle add a fictitious extra
|
|
216
|
+
# bar (than later will be removed).
|
|
217
|
+
n += add_n
|
|
218
|
+
elif s > 0:
|
|
219
|
+
# Provided the spacing
|
|
220
|
+
# 1. Compute the number of bars
|
|
221
|
+
n = math.floor(length / s) + 1
|
|
222
|
+
# 2. Distribute the bars centered in the curvilinear segment
|
|
223
|
+
needed_length = (n - 1) * s
|
|
224
|
+
delta_angle = (length - needed_length) / 2.0 / radius
|
|
225
|
+
# set whole to False bacause in this case we don't need to deal with
|
|
226
|
+
# the special case
|
|
227
|
+
whole = False
|
|
228
|
+
else:
|
|
229
|
+
raise ValueError('At least n or s should be provided')
|
|
230
|
+
|
|
231
|
+
phi_rebars = np.linspace(
|
|
232
|
+
start_angle + delta_angle, stop_angle - delta_angle, n
|
|
233
|
+
)
|
|
234
|
+
if whole:
|
|
235
|
+
n -= 1
|
|
236
|
+
phi_rebars = phi_rebars[:-1]
|
|
237
|
+
|
|
238
|
+
x = center[0] + radius * np.cos(phi_rebars)
|
|
239
|
+
y = center[1] + radius * np.sin(phi_rebars)
|
|
240
|
+
|
|
241
|
+
# add the bars
|
|
242
|
+
for i in range(n):
|
|
243
|
+
if i == 0 and not first:
|
|
244
|
+
continue
|
|
245
|
+
if i == n - 1 and not last:
|
|
246
|
+
continue
|
|
247
|
+
geo = add_reinforcement(
|
|
248
|
+
geo,
|
|
249
|
+
(x[i], y[i]),
|
|
250
|
+
diameter,
|
|
251
|
+
material,
|
|
252
|
+
group_label=group_label,
|
|
253
|
+
)
|
|
254
|
+
return geo
|
|
@@ -103,7 +103,7 @@ class BilinearCompression(ConstitutiveLaw):
|
|
|
103
103
|
# We are in tensile branch
|
|
104
104
|
strains = None
|
|
105
105
|
coeff.append((0.0,))
|
|
106
|
-
elif strain[0] > self.
|
|
106
|
+
elif strain[0] > self._eps_c:
|
|
107
107
|
# We are in the linear branch
|
|
108
108
|
strains = None
|
|
109
109
|
a0 = self._E * strain[0]
|
|
@@ -129,6 +129,51 @@ class BilinearCompression(ConstitutiveLaw):
|
|
|
129
129
|
coeff.append((self._fc,))
|
|
130
130
|
return strains, coeff
|
|
131
131
|
|
|
132
|
+
def __marin_tangent__(
|
|
133
|
+
self, strain: t.Tuple[float, float]
|
|
134
|
+
) -> t.Tuple[t.List[t.Tuple], t.List[t.Tuple]]:
|
|
135
|
+
"""Returns coefficients and strain limits for Marin integration of
|
|
136
|
+
tangent in a simply formatted way.
|
|
137
|
+
|
|
138
|
+
Arguments:
|
|
139
|
+
strain (float, float): Tuple defining the strain profile: eps =
|
|
140
|
+
strain[0] + strain[1]*y.
|
|
141
|
+
|
|
142
|
+
Example:
|
|
143
|
+
[(0, -0.002), (-0.002, -0.003)]
|
|
144
|
+
[(a0, a1, a2), (a0)]
|
|
145
|
+
"""
|
|
146
|
+
strains = []
|
|
147
|
+
coeff = []
|
|
148
|
+
if strain[1] == 0:
|
|
149
|
+
# Uniform strain equal to strain[0]
|
|
150
|
+
# understand in which branch we are
|
|
151
|
+
strain[0] = self.preprocess_strains_with_limits(strain[0])
|
|
152
|
+
if strain[0] > 0:
|
|
153
|
+
# We are in tensile branch
|
|
154
|
+
strains = None
|
|
155
|
+
coeff.append((0.0,))
|
|
156
|
+
elif strain[0] > self._eps_c:
|
|
157
|
+
# We are in the linear branch
|
|
158
|
+
strains = None
|
|
159
|
+
a0 = self._E
|
|
160
|
+
coeff.append((a0,))
|
|
161
|
+
else:
|
|
162
|
+
# We are in the constant branch or
|
|
163
|
+
# We are in a branch of non-resisting concrete
|
|
164
|
+
# Too much compression
|
|
165
|
+
strains = None
|
|
166
|
+
coeff.append((0.0,))
|
|
167
|
+
else:
|
|
168
|
+
# linear part
|
|
169
|
+
strains.append((self._eps_c, 0))
|
|
170
|
+
a0 = self._E
|
|
171
|
+
coeff.append((a0,))
|
|
172
|
+
# Constant part
|
|
173
|
+
strains.append((self._eps_cu, self._eps_c))
|
|
174
|
+
coeff.append((0.0,))
|
|
175
|
+
return strains, coeff
|
|
176
|
+
|
|
132
177
|
def get_ultimate_strain(
|
|
133
178
|
self, yielding: bool = False
|
|
134
179
|
) -> t.Tuple[float, float]:
|
|
@@ -69,6 +69,25 @@ class Elastic(ConstitutiveLaw):
|
|
|
69
69
|
coeff = [(a0, a1)]
|
|
70
70
|
return strains, coeff
|
|
71
71
|
|
|
72
|
+
def __marin_tangent__(
|
|
73
|
+
self, strain: t.Tuple[float, float]
|
|
74
|
+
) -> t.Tuple[t.List[t.Tuple], t.List[t.Tuple]]:
|
|
75
|
+
"""Returns coefficients and strain limits for Marin integration of
|
|
76
|
+
tangent in a simply formatted way.
|
|
77
|
+
|
|
78
|
+
Arguments:
|
|
79
|
+
strain (float, float): Tuple defining the strain profile: eps =
|
|
80
|
+
strain[0] + strain[1]*y.
|
|
81
|
+
|
|
82
|
+
Example:
|
|
83
|
+
[(0, -0.002), (-0.002, -0.003)]
|
|
84
|
+
[(a0, a1, a2), (a0)]
|
|
85
|
+
"""
|
|
86
|
+
strains = None
|
|
87
|
+
a0 = self._E
|
|
88
|
+
coeff = [(a0,)]
|
|
89
|
+
return strains, coeff
|
|
90
|
+
|
|
72
91
|
def get_ultimate_strain(self, **kwargs) -> t.Tuple[float, float]:
|
|
73
92
|
"""Return the ultimate strain (negative and positive)."""
|
|
74
93
|
# There is no real strain limit, so set it to very large values
|
|
@@ -160,6 +160,61 @@ class ElasticPlastic(ConstitutiveLaw):
|
|
|
160
160
|
coeff.append((a0, a1))
|
|
161
161
|
return strains, coeff
|
|
162
162
|
|
|
163
|
+
def __marin_tangent__(
|
|
164
|
+
self, strain: t.Tuple[float, float]
|
|
165
|
+
) -> t.Tuple[t.List[t.Tuple], t.List[t.Tuple]]:
|
|
166
|
+
"""Returns coefficients and strain limits for Marin integration of
|
|
167
|
+
tangent in a simply formatted way.
|
|
168
|
+
|
|
169
|
+
Arguments:
|
|
170
|
+
strain (float, float): Tuple defining the strain profile: eps =
|
|
171
|
+
strain[0] + strain[1]*y.
|
|
172
|
+
|
|
173
|
+
Example:
|
|
174
|
+
[(0, -0.002), (-0.002, -0.003)]
|
|
175
|
+
[(a0, a1, a2), (a0)]
|
|
176
|
+
"""
|
|
177
|
+
strains = []
|
|
178
|
+
coeff = []
|
|
179
|
+
eps_sy_n, eps_sy_p = self.get_ultimate_strain(yielding=True)
|
|
180
|
+
eps_su_n, eps_su_p = self.get_ultimate_strain()
|
|
181
|
+
if strain[1] == 0:
|
|
182
|
+
# Uniform strain equal to strain[0]
|
|
183
|
+
# Understand in which branch are we
|
|
184
|
+
strain[0] = self.preprocess_strains_with_limits(strain[0])
|
|
185
|
+
if strain[0] > eps_sy_p and strain[0] <= eps_su_p:
|
|
186
|
+
# We are in the Hardening part positive
|
|
187
|
+
strains = None
|
|
188
|
+
a0 = self._Eh
|
|
189
|
+
coeff.append((a0,))
|
|
190
|
+
elif strain[0] < eps_sy_n and strain[0] >= eps_su_n:
|
|
191
|
+
# We are in the Hardening part negative
|
|
192
|
+
strains = None
|
|
193
|
+
a0 = self._Eh
|
|
194
|
+
coeff.append((a0,))
|
|
195
|
+
elif abs(strain[0]) <= self._eps_sy:
|
|
196
|
+
# We are in the elastic part
|
|
197
|
+
strains = None
|
|
198
|
+
a0 = self._E
|
|
199
|
+
coeff.append((a0,))
|
|
200
|
+
else:
|
|
201
|
+
strains = None
|
|
202
|
+
coeff.append((0.0,))
|
|
203
|
+
else:
|
|
204
|
+
# Hardening part negative
|
|
205
|
+
strains.append((eps_su_n, eps_sy_n))
|
|
206
|
+
a0 = self._Eh
|
|
207
|
+
coeff.append((a0,))
|
|
208
|
+
# Elastic part
|
|
209
|
+
strains.append((eps_sy_n, eps_sy_p))
|
|
210
|
+
a0 = self._E
|
|
211
|
+
coeff.append((a0,))
|
|
212
|
+
# Hardening part positive
|
|
213
|
+
strains.append((eps_sy_p, eps_su_p))
|
|
214
|
+
a0 = self._Eh
|
|
215
|
+
coeff.append((a0,))
|
|
216
|
+
return strains, coeff
|
|
217
|
+
|
|
163
218
|
def get_ultimate_strain(
|
|
164
219
|
self, yielding: bool = False
|
|
165
220
|
) -> t.Tuple[float, float]:
|
|
@@ -189,6 +189,63 @@ class ParabolaRectangle(ConstitutiveLaw):
|
|
|
189
189
|
coeff.append((self._fc,))
|
|
190
190
|
return strains, coeff
|
|
191
191
|
|
|
192
|
+
def __marin_tangent__(
|
|
193
|
+
self, strain: t.Tuple[float, float]
|
|
194
|
+
) -> t.Tuple[t.List[t.Tuple], t.List[t.Tuple]]:
|
|
195
|
+
"""Returns coefficients and strain limits for Marin integration of
|
|
196
|
+
tangent in a simply formatted way.
|
|
197
|
+
|
|
198
|
+
Arguments:
|
|
199
|
+
strain (float, float): Tuple defining the strain profile: eps =
|
|
200
|
+
strain[0] + strain[1]*y.
|
|
201
|
+
|
|
202
|
+
Example:
|
|
203
|
+
[(0, -0.002), (-0.002, -0.003)]
|
|
204
|
+
[(a0, a1, a2), (a0)]
|
|
205
|
+
"""
|
|
206
|
+
if self._n != 2:
|
|
207
|
+
# The constitutive law is not writtable as a polynomial,
|
|
208
|
+
# Call the generic distretizing method
|
|
209
|
+
return super().__marin_tangent__(strain=strain)
|
|
210
|
+
|
|
211
|
+
strains = []
|
|
212
|
+
coeff = []
|
|
213
|
+
if strain[1] == 0:
|
|
214
|
+
# Uniform strain equal to strain[0]
|
|
215
|
+
# understand in which branch are we
|
|
216
|
+
strain[0] = self.preprocess_strains_with_limits(strain[0])
|
|
217
|
+
if strain[0] > 0:
|
|
218
|
+
# We are in tensile branch
|
|
219
|
+
strains = None
|
|
220
|
+
coeff.append((0.0,))
|
|
221
|
+
elif strain[0] > self._eps_0:
|
|
222
|
+
# We are in the parabolic branch
|
|
223
|
+
strains = None
|
|
224
|
+
a0 = (
|
|
225
|
+
2
|
|
226
|
+
* self._fc
|
|
227
|
+
/ self._eps_0
|
|
228
|
+
* (1 - (strain[0] / self._eps_0))
|
|
229
|
+
)
|
|
230
|
+
a1 = -2 * self._fc / self._eps_0**2 * strain[1]
|
|
231
|
+
coeff.append((a0, a1))
|
|
232
|
+
else:
|
|
233
|
+
# We are in the constant branch or
|
|
234
|
+
# We are in a branch of non-resisting concrete
|
|
235
|
+
# Too much compression
|
|
236
|
+
strains = None
|
|
237
|
+
coeff.append((0.0,))
|
|
238
|
+
else:
|
|
239
|
+
# Parabolic part
|
|
240
|
+
strains.append((self._eps_0, 0))
|
|
241
|
+
a0 = 2 * self._fc / self._eps_0 * (1 - (strain[0] / self._eps_0))
|
|
242
|
+
a1 = -2 * self._fc / self._eps_0**2 * strain[1]
|
|
243
|
+
coeff.append((a0, a1))
|
|
244
|
+
# Constant part
|
|
245
|
+
strains.append((self._eps_u, self._eps_0))
|
|
246
|
+
coeff.append((0.0,))
|
|
247
|
+
return strains, coeff
|
|
248
|
+
|
|
192
249
|
def get_ultimate_strain(
|
|
193
250
|
self, yielding: bool = False
|
|
194
251
|
) -> t.Tuple[float, float]:
|
|
@@ -173,6 +173,50 @@ class UserDefined(ConstitutiveLaw):
|
|
|
173
173
|
|
|
174
174
|
return strains, coeff
|
|
175
175
|
|
|
176
|
+
def __marin_tangent__(
|
|
177
|
+
self, strain: t.Tuple[float, float]
|
|
178
|
+
) -> t.Tuple[t.List[t.Tuple], t.List[t.Tuple]]:
|
|
179
|
+
"""Returns coefficients and strain limits for Marin integration of
|
|
180
|
+
tangent in a simply formatted way.
|
|
181
|
+
|
|
182
|
+
Arguments:
|
|
183
|
+
strain (float, float): Tuple defining the strain profile: eps =
|
|
184
|
+
strain[0] + strain[1]*y.
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
[(0, -0.002), (-0.002, -0.003)]
|
|
188
|
+
[(a0, a1, a2), (a0)]
|
|
189
|
+
"""
|
|
190
|
+
strains = []
|
|
191
|
+
coeff = []
|
|
192
|
+
if strain[1] == 0:
|
|
193
|
+
# Uniform strain equal to strain[0]
|
|
194
|
+
# understand in which branch are we
|
|
195
|
+
strain[0] = self.preprocess_strains_with_limits(strain[0])
|
|
196
|
+
found = False
|
|
197
|
+
for i in range(len(self._x) - 1):
|
|
198
|
+
if self._x[i] <= strain[0] and self._x[i + 1] >= strain[0]:
|
|
199
|
+
strains = None
|
|
200
|
+
stiffness = (self._y[i + 1] - self._y[i]) / (
|
|
201
|
+
self._x[i + 1] - self._x[i]
|
|
202
|
+
)
|
|
203
|
+
coeff.append((stiffness,))
|
|
204
|
+
found = True
|
|
205
|
+
break
|
|
206
|
+
if not found:
|
|
207
|
+
strains = None
|
|
208
|
+
coeff.append((0.0,))
|
|
209
|
+
else:
|
|
210
|
+
for i in range(len(self._x) - 1):
|
|
211
|
+
# For each branch of the linear piecewise function
|
|
212
|
+
stiffness = (self._y[i + 1] - self._y[i]) / (
|
|
213
|
+
self._x[i + 1] - self._x[i]
|
|
214
|
+
)
|
|
215
|
+
strains.append((self._x[i], self._x[i + 1]))
|
|
216
|
+
coeff.append((stiffness,))
|
|
217
|
+
|
|
218
|
+
return strains, coeff
|
|
219
|
+
|
|
176
220
|
def get_ultimate_strain(self, **kwargs) -> t.Tuple[float, float]:
|
|
177
221
|
"""Return the ultimate strain (negative and positive)."""
|
|
178
222
|
del kwargs
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Main entry point for sections."""
|
|
2
2
|
|
|
3
3
|
from ._generic import GenericSection, GenericSectionCalculator
|
|
4
|
+
from ._rc_utils import calculate_elastic_cracked_properties
|
|
4
5
|
from .section_integrators import (
|
|
5
6
|
FiberIntegrator,
|
|
6
7
|
MarinIntegrator,
|
|
@@ -17,4 +18,5 @@ __all__ = [
|
|
|
17
18
|
'MarinIntegrator',
|
|
18
19
|
'integrator_factory',
|
|
19
20
|
'marin_integration',
|
|
21
|
+
'calculate_elastic_cracked_properties',
|
|
20
22
|
]
|