structuralcodes 0.3.1__py3-none-any.whl → 0.5.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 +2 -0
- structuralcodes/codes/ec2_2004/shear.py +44 -4
- structuralcodes/codes/mc2010/__init__.py +40 -0
- structuralcodes/codes/mc2010/_concrete_punching.py +300 -388
- structuralcodes/codes/mc2010/_interface_concrete_steel_rebar.py +348 -0
- structuralcodes/core/base.py +1 -22
- structuralcodes/geometry/_circular.py +3 -10
- structuralcodes/geometry/_geometry.py +47 -92
- structuralcodes/geometry/_rectangular.py +3 -10
- structuralcodes/geometry/_reinforcement.py +8 -11
- structuralcodes/materials/__init__.py +2 -1
- structuralcodes/materials/basic/__init__.py +11 -0
- structuralcodes/materials/basic/_elastic.py +52 -0
- structuralcodes/materials/basic/_elasticplastic.py +75 -0
- structuralcodes/materials/basic/_generic.py +26 -0
- structuralcodes/materials/concrete/_concrete.py +1 -62
- structuralcodes/materials/concrete/_concreteEC2_2004.py +270 -224
- structuralcodes/materials/concrete/_concreteEC2_2023.py +246 -188
- structuralcodes/materials/concrete/_concreteMC2010.py +280 -235
- structuralcodes/materials/constitutive_laws/__init__.py +16 -15
- structuralcodes/materials/reinforcement/_reinforcement.py +0 -71
- structuralcodes/materials/reinforcement/_reinforcementEC2_2004.py +37 -2
- structuralcodes/materials/reinforcement/_reinforcementEC2_2023.py +34 -1
- structuralcodes/materials/reinforcement/_reinforcementMC2010.py +38 -2
- structuralcodes/sections/_generic.py +76 -21
- structuralcodes/sections/_rc_utils.py +15 -5
- structuralcodes/sections/section_integrators/_fiber_integrator.py +19 -11
- structuralcodes/sections/section_integrators/_marin_integrator.py +24 -19
- {structuralcodes-0.3.1.dist-info → structuralcodes-0.5.0.dist-info}/METADATA +3 -2
- {structuralcodes-0.3.1.dist-info → structuralcodes-0.5.0.dist-info}/RECORD +33 -27
- {structuralcodes-0.3.1.dist-info → structuralcodes-0.5.0.dist-info}/WHEEL +1 -1
- structuralcodes-0.5.0.dist-info/licenses/LICENSE +201 -0
|
@@ -61,24 +61,25 @@ def create_constitutive_law(
|
|
|
61
61
|
|
|
62
62
|
If the consitutive law selected is not available for the specific
|
|
63
63
|
material, an exception will be raised.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
ValueError: If the constitutive law is not available for the material.
|
|
67
|
+
ValueError: If the constitutive law name is unknown.
|
|
64
68
|
"""
|
|
65
|
-
law = None
|
|
66
69
|
const_law = CONSTITUTIVE_LAWS.get(constitutive_law_name.lower())
|
|
67
70
|
if const_law is not None:
|
|
68
71
|
method_name = f'__{constitutive_law_name}__'
|
|
69
72
|
# check if the material object has the special method needed
|
|
70
|
-
if hasattr(material, method_name)
|
|
73
|
+
if hasattr(material, method_name) and callable(
|
|
74
|
+
getattr(material, method_name)
|
|
75
|
+
):
|
|
71
76
|
method = getattr(material, method_name)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
82
|
-
else:
|
|
83
|
-
raise ValueError(f'Unknown constitutive law: {constitutive_law_name}')
|
|
84
|
-
return law
|
|
77
|
+
# get the kwargs from the special dunder method
|
|
78
|
+
kwargs = method()
|
|
79
|
+
# create and return the constitutive law
|
|
80
|
+
return const_law(**kwargs)
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f'Constitutive law {constitutive_law_name} not available for'
|
|
83
|
+
f' material {material.__class__.__name__}'
|
|
84
|
+
)
|
|
85
|
+
raise ValueError(f'Unknown constitutive law: {constitutive_law_name}')
|
|
@@ -4,10 +4,6 @@ import abc
|
|
|
4
4
|
import typing as t
|
|
5
5
|
|
|
6
6
|
from structuralcodes.core.base import ConstitutiveLaw, Material
|
|
7
|
-
from structuralcodes.materials.constitutive_laws import (
|
|
8
|
-
ElasticPlastic,
|
|
9
|
-
create_constitutive_law,
|
|
10
|
-
)
|
|
11
7
|
|
|
12
8
|
|
|
13
9
|
class Reinforcement(Material):
|
|
@@ -39,45 +35,21 @@ class Reinforcement(Material):
|
|
|
39
35
|
self._epsuk = abs(epsuk)
|
|
40
36
|
self._gamma_s = gamma_s
|
|
41
37
|
|
|
42
|
-
# Calculate the plastic hardening modulus
|
|
43
|
-
if self.epsuk - self.fyk / self.Es > 0.0 and self.ftk - self.fyk > 0:
|
|
44
|
-
Eh = (self.ftk - self.fyk) / (self.epsuk - self.fyk / self.Es)
|
|
45
|
-
else:
|
|
46
|
-
Eh = 0.0
|
|
47
|
-
self._constitutive_law = ElasticPlastic(
|
|
48
|
-
E=self.Es, fy=self.fyd(), Eh=Eh, eps_su=self.epsud()
|
|
49
|
-
)
|
|
50
|
-
|
|
51
38
|
@property
|
|
52
39
|
def fyk(self) -> float:
|
|
53
40
|
"""Returns fyk in MPa."""
|
|
54
41
|
return self._fyk
|
|
55
42
|
|
|
56
|
-
@fyk.setter
|
|
57
|
-
def fyk(self, fyk: float) -> None:
|
|
58
|
-
"""Setter for fyk (in MPa)."""
|
|
59
|
-
self._fyk = abs(fyk)
|
|
60
|
-
|
|
61
43
|
@property
|
|
62
44
|
def Es(self) -> float:
|
|
63
45
|
"""Returns Es in MPa."""
|
|
64
46
|
return self._Es
|
|
65
47
|
|
|
66
|
-
@Es.setter
|
|
67
|
-
def Es(self, Es: float) -> None:
|
|
68
|
-
"""Setter for Es (in MPa)."""
|
|
69
|
-
self._Es = abs(Es)
|
|
70
|
-
|
|
71
48
|
@property
|
|
72
49
|
def ftk(self) -> float:
|
|
73
50
|
"""Returns ftk in MPa."""
|
|
74
51
|
return self._ftk
|
|
75
52
|
|
|
76
|
-
@ftk.setter
|
|
77
|
-
def ftk(self, ftk: float) -> None:
|
|
78
|
-
"""Setter for ftk (in MPa)."""
|
|
79
|
-
self._ftk = abs(ftk)
|
|
80
|
-
|
|
81
53
|
@property
|
|
82
54
|
def epsuk(self) -> float:
|
|
83
55
|
"""Returns epsuk."""
|
|
@@ -98,49 +70,6 @@ class Reinforcement(Material):
|
|
|
98
70
|
"""Returns the constitutive law object."""
|
|
99
71
|
return self._constitutive_law
|
|
100
72
|
|
|
101
|
-
@constitutive_law.setter
|
|
102
|
-
def constitutive_law(
|
|
103
|
-
self,
|
|
104
|
-
constitutive_law: t.Union[
|
|
105
|
-
ConstitutiveLaw,
|
|
106
|
-
t.Literal[
|
|
107
|
-
'elastic',
|
|
108
|
-
'elasticperfecltyplastic',
|
|
109
|
-
'elasticplastic',
|
|
110
|
-
],
|
|
111
|
-
],
|
|
112
|
-
) -> None:
|
|
113
|
-
"""Setter for constitutive law.
|
|
114
|
-
|
|
115
|
-
Arguments:
|
|
116
|
-
consitutive_law (ConstitutiveLaw | str): a valid ConstitutiveLaw
|
|
117
|
-
object for reinforcement or a string defining a valid
|
|
118
|
-
constitutive law type for reinforcement. (valid options:
|
|
119
|
-
'elastic', 'elasticperfectlyplastic', 'elasticplastic').
|
|
120
|
-
"""
|
|
121
|
-
if constitutive_law is None:
|
|
122
|
-
raise ValueError(
|
|
123
|
-
'At least a constitutive law or a string defining the '
|
|
124
|
-
'constitutive law must be provided.'
|
|
125
|
-
)
|
|
126
|
-
if isinstance(constitutive_law, str):
|
|
127
|
-
constitutive_law = create_constitutive_law(
|
|
128
|
-
constitutive_law_name=constitutive_law, material=self
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
if isinstance(constitutive_law, ConstitutiveLaw):
|
|
132
|
-
if 'rebars' in constitutive_law.__materials__:
|
|
133
|
-
self._constitutive_law = constitutive_law
|
|
134
|
-
else:
|
|
135
|
-
raise ValueError(
|
|
136
|
-
'The constitutive law selected is not suitable '
|
|
137
|
-
'for being used with a Reinforcement material.'
|
|
138
|
-
)
|
|
139
|
-
else:
|
|
140
|
-
raise ValueError(
|
|
141
|
-
f'The constitutive law {constitutive_law} could not be created'
|
|
142
|
-
)
|
|
143
|
-
|
|
144
73
|
@property
|
|
145
74
|
@abc.abstractmethod
|
|
146
75
|
def gamma_s(self) -> float:
|
|
@@ -4,6 +4,7 @@ import typing as t
|
|
|
4
4
|
|
|
5
5
|
from structuralcodes.codes import ec2_2004
|
|
6
6
|
|
|
7
|
+
from ..constitutive_laws import ConstitutiveLaw, create_constitutive_law
|
|
7
8
|
from ._reinforcement import Reinforcement
|
|
8
9
|
|
|
9
10
|
|
|
@@ -20,6 +21,16 @@ class ReinforcementEC2_2004(Reinforcement): # noqa: N801
|
|
|
20
21
|
gamma_eps: t.Optional[float] = None,
|
|
21
22
|
name: t.Optional[str] = None,
|
|
22
23
|
density: float = 7850.0,
|
|
24
|
+
constitutive_law: t.Optional[
|
|
25
|
+
t.Union[
|
|
26
|
+
t.Literal[
|
|
27
|
+
'elastic',
|
|
28
|
+
'elasticperfectlyplastic',
|
|
29
|
+
'elasticplastic',
|
|
30
|
+
],
|
|
31
|
+
ConstitutiveLaw,
|
|
32
|
+
]
|
|
33
|
+
] = 'elasticplastic',
|
|
23
34
|
):
|
|
24
35
|
"""Initializes a new instance of Reinforcement for EC2 2004.
|
|
25
36
|
|
|
@@ -33,13 +44,25 @@ class ReinforcementEC2_2004(Reinforcement): # noqa: N801
|
|
|
33
44
|
Default value is 1.15.
|
|
34
45
|
|
|
35
46
|
Keyword Arguments:
|
|
47
|
+
gamma_eps (float): The partial factor for ultimate strain. Default
|
|
48
|
+
value is 0.9.
|
|
36
49
|
name (str): A descriptive name for the reinforcement.
|
|
37
50
|
density (float): Density of material in kg/m3 (default: 7850).
|
|
51
|
+
constitutive_law (ConstitutiveLaw | str): A valid ConstitutiveLaw
|
|
52
|
+
object for reinforcement or a string defining a valid
|
|
53
|
+
constitutive law type for reinforcement. (valid options for
|
|
54
|
+
string: 'elastic', 'elasticplastic', or
|
|
55
|
+
'elasticperfectlyplastic').
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
ValueError: If the constitutive law name is not available for the
|
|
59
|
+
material.
|
|
60
|
+
ValueError: If the provided constitutive law is not valid for
|
|
61
|
+
reinforcement.
|
|
38
62
|
"""
|
|
39
63
|
if name is None:
|
|
40
64
|
name = f'Reinforcement{round(fyk):d}'
|
|
41
65
|
|
|
42
|
-
self._gamma_eps = gamma_eps
|
|
43
66
|
super().__init__(
|
|
44
67
|
fyk=fyk,
|
|
45
68
|
Es=Es,
|
|
@@ -49,6 +72,18 @@ class ReinforcementEC2_2004(Reinforcement): # noqa: N801
|
|
|
49
72
|
epsuk=epsuk,
|
|
50
73
|
gamma_s=gamma_s,
|
|
51
74
|
)
|
|
75
|
+
self._gamma_eps = gamma_eps
|
|
76
|
+
self._constitutive_law = (
|
|
77
|
+
constitutive_law
|
|
78
|
+
if isinstance(constitutive_law, ConstitutiveLaw)
|
|
79
|
+
else create_constitutive_law(
|
|
80
|
+
constitutive_law_name=constitutive_law, material=self
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
if 'steel' not in self._constitutive_law.__materials__:
|
|
84
|
+
raise ValueError(
|
|
85
|
+
'The provided constitutive law is not valid for reinforcement.'
|
|
86
|
+
)
|
|
52
87
|
|
|
53
88
|
def fyd(self) -> float:
|
|
54
89
|
"""The design yield strength."""
|
|
@@ -94,7 +129,7 @@ class ReinforcementEC2_2004(Reinforcement): # noqa: N801
|
|
|
94
129
|
"""Returns kwargs for ElasticPlastic constitutive law with strain
|
|
95
130
|
hardening.
|
|
96
131
|
"""
|
|
97
|
-
Eh = (self.ftd() - self.fyd()) / (self.
|
|
132
|
+
Eh = (self.ftd() - self.fyd()) / (self.epsud() - self.epsyd)
|
|
98
133
|
return {
|
|
99
134
|
'E': self.Es,
|
|
100
135
|
'fy': self.fyd(),
|
|
@@ -4,6 +4,7 @@ import typing as t
|
|
|
4
4
|
|
|
5
5
|
from structuralcodes.codes import ec2_2023
|
|
6
6
|
|
|
7
|
+
from ..constitutive_laws import ConstitutiveLaw, create_constitutive_law
|
|
7
8
|
from ._reinforcement import Reinforcement
|
|
8
9
|
|
|
9
10
|
|
|
@@ -19,6 +20,16 @@ class ReinforcementEC2_2023(Reinforcement): # noqa: N801
|
|
|
19
20
|
gamma_s: t.Optional[float] = None,
|
|
20
21
|
name: t.Optional[str] = None,
|
|
21
22
|
density: float = 7850.0,
|
|
23
|
+
constitutive_law: t.Optional[
|
|
24
|
+
t.Union[
|
|
25
|
+
t.Literal[
|
|
26
|
+
'elastic',
|
|
27
|
+
'elasticperfectlyplastic',
|
|
28
|
+
'elasticplastic',
|
|
29
|
+
],
|
|
30
|
+
ConstitutiveLaw,
|
|
31
|
+
]
|
|
32
|
+
] = 'elasticplastic',
|
|
22
33
|
):
|
|
23
34
|
"""Initializes a new instance of Reinforcement for EC2 2023.
|
|
24
35
|
|
|
@@ -34,6 +45,17 @@ class ReinforcementEC2_2023(Reinforcement): # noqa: N801
|
|
|
34
45
|
Keyword Args:
|
|
35
46
|
name (str): A descriptive name for the reinforcement.
|
|
36
47
|
density (float): Density of material in kg/m3 (default: 7850).
|
|
48
|
+
constitutive_law (ConstitutiveLaw | str): A valid ConstitutiveLaw
|
|
49
|
+
object for reinforcement or a string defining a valid
|
|
50
|
+
constitutive law type for reinforcement. (valid options for
|
|
51
|
+
string: 'elastic', 'elasticplastic', or
|
|
52
|
+
'elasticperfectlyplastic').
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If the constitutive law name is not available for the
|
|
56
|
+
material.
|
|
57
|
+
ValueError: If the provided constitutive law is not valid for
|
|
58
|
+
reinforcement.
|
|
37
59
|
"""
|
|
38
60
|
if name is None:
|
|
39
61
|
name = f'Reinforcement{round(fyk):d}'
|
|
@@ -46,6 +68,17 @@ class ReinforcementEC2_2023(Reinforcement): # noqa: N801
|
|
|
46
68
|
epsuk=epsuk,
|
|
47
69
|
gamma_s=gamma_s,
|
|
48
70
|
)
|
|
71
|
+
self._constitutive_law = (
|
|
72
|
+
constitutive_law
|
|
73
|
+
if isinstance(constitutive_law, ConstitutiveLaw)
|
|
74
|
+
else create_constitutive_law(
|
|
75
|
+
constitutive_law_name=constitutive_law, material=self
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
if 'steel' not in self._constitutive_law.__materials__:
|
|
79
|
+
raise ValueError(
|
|
80
|
+
'The provided constitutive law is not valid for reinforcement.'
|
|
81
|
+
)
|
|
49
82
|
|
|
50
83
|
def fyd(self) -> float:
|
|
51
84
|
"""The design yield strength."""
|
|
@@ -84,7 +117,7 @@ class ReinforcementEC2_2023(Reinforcement): # noqa: N801
|
|
|
84
117
|
"""Returns kwargs for ElasticPlastic constitutive law with strain
|
|
85
118
|
hardening.
|
|
86
119
|
"""
|
|
87
|
-
Eh = (self.ftd() - self.fyd()) / (self.
|
|
120
|
+
Eh = (self.ftd() - self.fyd()) / (self.epsud() - self.epsyd)
|
|
88
121
|
return {
|
|
89
122
|
'E': self.Es,
|
|
90
123
|
'fy': self.fyd(),
|
|
@@ -4,6 +4,7 @@ import typing as t
|
|
|
4
4
|
|
|
5
5
|
from structuralcodes.codes import mc2010
|
|
6
6
|
|
|
7
|
+
from ..constitutive_laws import ConstitutiveLaw, create_constitutive_law
|
|
7
8
|
from ._reinforcement import Reinforcement
|
|
8
9
|
|
|
9
10
|
|
|
@@ -20,6 +21,16 @@ class ReinforcementMC2010(Reinforcement):
|
|
|
20
21
|
gamma_eps: t.Optional[float] = None,
|
|
21
22
|
name: t.Optional[str] = None,
|
|
22
23
|
density: float = 7850.0,
|
|
24
|
+
constitutive_law: t.Optional[
|
|
25
|
+
t.Union[
|
|
26
|
+
t.Literal[
|
|
27
|
+
'elastic',
|
|
28
|
+
'elasticperfectlyplastic',
|
|
29
|
+
'elasticplastic',
|
|
30
|
+
],
|
|
31
|
+
ConstitutiveLaw,
|
|
32
|
+
]
|
|
33
|
+
] = 'elasticplastic',
|
|
23
34
|
):
|
|
24
35
|
"""Initializes a new instance of Reinforcement for MC2010.
|
|
25
36
|
|
|
@@ -33,12 +44,25 @@ class ReinforcementMC2010(Reinforcement):
|
|
|
33
44
|
Default value is 1.15.
|
|
34
45
|
|
|
35
46
|
Keyword Args:
|
|
47
|
+
gamma_eps (float): The partial factor for ultimate strain. Default
|
|
48
|
+
value is 0.9.
|
|
36
49
|
name (str): A descriptive name for the reinforcement.
|
|
37
50
|
density (float): Density of material in kg/m3 (default: 7850).
|
|
51
|
+
constitutive_law (ConstitutiveLaw | str): A valid ConstitutiveLaw
|
|
52
|
+
object for reinforcement or a string defining a valid
|
|
53
|
+
constitutive law type for reinforcement. (valid options for
|
|
54
|
+
string: 'elastic', 'elasticplastic', or
|
|
55
|
+
'elasticperfectlyplastic').
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
ValueError: If the constitutive law name is not available for the
|
|
59
|
+
material.
|
|
60
|
+
ValueError: If the provided constitutive law is not valid for
|
|
61
|
+
reinforcement.
|
|
38
62
|
"""
|
|
39
63
|
if name is None:
|
|
40
64
|
name = f'Reinforcement{round(fyk):d}'
|
|
41
|
-
|
|
65
|
+
|
|
42
66
|
super().__init__(
|
|
43
67
|
fyk=fyk,
|
|
44
68
|
Es=Es,
|
|
@@ -48,6 +72,18 @@ class ReinforcementMC2010(Reinforcement):
|
|
|
48
72
|
epsuk=epsuk,
|
|
49
73
|
gamma_s=gamma_s,
|
|
50
74
|
)
|
|
75
|
+
self._gamma_eps = gamma_eps
|
|
76
|
+
self._constitutive_law = (
|
|
77
|
+
constitutive_law
|
|
78
|
+
if isinstance(constitutive_law, ConstitutiveLaw)
|
|
79
|
+
else create_constitutive_law(
|
|
80
|
+
constitutive_law_name=constitutive_law, material=self
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
if 'steel' not in self._constitutive_law.__materials__:
|
|
84
|
+
raise ValueError(
|
|
85
|
+
'The provided constitutive law is not valid for reinforcement.'
|
|
86
|
+
)
|
|
51
87
|
|
|
52
88
|
def fyd(self) -> float:
|
|
53
89
|
"""The design yield strength."""
|
|
@@ -89,7 +125,7 @@ class ReinforcementMC2010(Reinforcement):
|
|
|
89
125
|
"""Returns kwargs for ElasticPlastic constitutive law with strain
|
|
90
126
|
hardening.
|
|
91
127
|
"""
|
|
92
|
-
Eh = (self.ftd() - self.fyd()) / (self.
|
|
128
|
+
Eh = (self.ftd() - self.fyd()) / (self.epsud() - self.epsyd)
|
|
93
129
|
return {
|
|
94
130
|
'E': self.Es,
|
|
95
131
|
'fy': self.fyd(),
|
|
@@ -19,7 +19,7 @@ from structuralcodes.geometry import (
|
|
|
19
19
|
PointGeometry,
|
|
20
20
|
SurfaceGeometry,
|
|
21
21
|
)
|
|
22
|
-
from structuralcodes.materials.
|
|
22
|
+
from structuralcodes.materials.basic import ElasticMaterial
|
|
23
23
|
|
|
24
24
|
from .section_integrators import SectionIntegrator, integrator_factory
|
|
25
25
|
|
|
@@ -42,6 +42,8 @@ class GenericSection(Section):
|
|
|
42
42
|
strength, moment curvature, etc.).
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
|
+
geometry: CompoundGeometry
|
|
46
|
+
|
|
45
47
|
def __init__(
|
|
46
48
|
self,
|
|
47
49
|
geometry: t.Union[SurfaceGeometry, CompoundGeometry],
|
|
@@ -96,6 +98,7 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
96
98
|
"""Calculator class implementing analysis algorithms for code checks."""
|
|
97
99
|
|
|
98
100
|
integrator: SectionIntegrator
|
|
101
|
+
section: GenericSection
|
|
99
102
|
|
|
100
103
|
def __init__(
|
|
101
104
|
self,
|
|
@@ -155,13 +158,17 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
155
158
|
# Computation of surface area, reinforcement area, EA (axial rigidity)
|
|
156
159
|
# and mass: Morten -> problem with units! how do we deal with it?
|
|
157
160
|
for geo in self.section.geometry.geometries:
|
|
158
|
-
gp.ea += geo.area * geo.material.get_tangent(
|
|
161
|
+
gp.ea += geo.area * geo.material.constitutive_law.get_tangent(
|
|
162
|
+
eps=0
|
|
163
|
+
)
|
|
159
164
|
if geo.density is not None:
|
|
160
165
|
# this assumes area in mm2 and density in kg/m3
|
|
161
166
|
gp.mass += geo.area * geo.density * 1e-9
|
|
162
167
|
|
|
163
168
|
for geo in self.section.geometry.point_geometries:
|
|
164
|
-
gp.ea += geo.area * geo.material.get_tangent(
|
|
169
|
+
gp.ea += geo.area * geo.material.constitutive_law.get_tangent(
|
|
170
|
+
eps=0
|
|
171
|
+
)
|
|
165
172
|
gp.area_reinforcement += geo.area
|
|
166
173
|
if geo.density is not None:
|
|
167
174
|
# this assumes area in mm2 and density in kg/m3
|
|
@@ -237,7 +244,7 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
237
244
|
|
|
238
245
|
# Create a dummy material for integration of area moments
|
|
239
246
|
# This is used for J, S etc, not for E_J E_S etc
|
|
240
|
-
dummy_mat =
|
|
247
|
+
dummy_mat = ElasticMaterial(E=1, density=1)
|
|
241
248
|
# Computation of moments of area (material-independet)
|
|
242
249
|
# Note: this could be un-meaningfull when many materials
|
|
243
250
|
# are combined
|
|
@@ -309,15 +316,40 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
309
316
|
chi_min = 1e10
|
|
310
317
|
for g in geom.geometries + geom.point_geometries:
|
|
311
318
|
for other_g in geom.geometries + geom.point_geometries:
|
|
319
|
+
# This is left on purpose: even if tempted we should not do
|
|
320
|
+
# this check:
|
|
312
321
|
# if g != other_g:
|
|
313
|
-
eps_p = g.material.get_ultimate_strain(
|
|
322
|
+
eps_p = g.material.constitutive_law.get_ultimate_strain(
|
|
323
|
+
yielding=yielding
|
|
324
|
+
)[1]
|
|
314
325
|
if isinstance(g, SurfaceGeometry):
|
|
315
326
|
y_p = g.polygon.bounds[1]
|
|
316
327
|
elif isinstance(g, PointGeometry):
|
|
317
328
|
y_p = g._point.coords[0][1]
|
|
318
|
-
|
|
319
|
-
|
|
329
|
+
# Check if the section is a reinforced concrete section:
|
|
330
|
+
# If it is, we need to obtain the "yield" strain of concrete
|
|
331
|
+
# (-0.002 for default parabola-rectangle concrete)
|
|
332
|
+
# If the geometry is not concrete, don't get the yield strain
|
|
333
|
+
# If it is not a reinforced concrete section, return
|
|
334
|
+
# the yield strain if asked.
|
|
335
|
+
is_rc_section = self.section.geometry.reinforced_concrete
|
|
336
|
+
is_concrete_geom = (
|
|
337
|
+
isinstance(other_g, SurfaceGeometry) and other_g.concrete
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
use_yielding = (
|
|
341
|
+
yielding
|
|
342
|
+
if (
|
|
343
|
+
(is_rc_section and is_concrete_geom)
|
|
344
|
+
or (not is_rc_section)
|
|
345
|
+
)
|
|
346
|
+
else False
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
eps_n = other_g.material.constitutive_law.get_ultimate_strain(
|
|
350
|
+
yielding=use_yielding
|
|
320
351
|
)[0]
|
|
352
|
+
|
|
321
353
|
if isinstance(other_g, SurfaceGeometry):
|
|
322
354
|
y_n = other_g.polygon.bounds[3]
|
|
323
355
|
elif isinstance(other_g, PointGeometry):
|
|
@@ -439,12 +471,18 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
439
471
|
apply the bisection algorithm.
|
|
440
472
|
"""
|
|
441
473
|
ITMAX = 20
|
|
474
|
+
MAXRESTATTEMPTS = 20
|
|
442
475
|
sign = -1 if dn_a > 0 else 1
|
|
443
476
|
found = False
|
|
444
477
|
it = 0
|
|
478
|
+
restarts = 0
|
|
445
479
|
delta = 1e-3
|
|
446
|
-
|
|
447
|
-
|
|
480
|
+
# Use a growth factor for an exponential finding
|
|
481
|
+
r = 2.0
|
|
482
|
+
diverging = False
|
|
483
|
+
diverging_steps = 0
|
|
484
|
+
while not found and it < ITMAX and restarts < MAXRESTATTEMPTS:
|
|
485
|
+
eps_0_b = eps_0_a + sign * delta * r ** (it)
|
|
448
486
|
(
|
|
449
487
|
n_int,
|
|
450
488
|
_,
|
|
@@ -457,10 +495,20 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
457
495
|
if dn_a * dn_b < 0:
|
|
458
496
|
found = True
|
|
459
497
|
elif abs(dn_b) > abs(dn_a):
|
|
460
|
-
# we are driving
|
|
498
|
+
# we are driving away from the solution, probably due
|
|
461
499
|
# to failure of a material
|
|
462
|
-
|
|
463
|
-
|
|
500
|
+
diverging = True
|
|
501
|
+
if diverging:
|
|
502
|
+
# Count for how many steps we are diverging
|
|
503
|
+
diverging_steps += 1
|
|
504
|
+
# If we are consistently diverging for more than 10 steps,
|
|
505
|
+
# Restart the process with a small delta
|
|
506
|
+
if diverging_steps > 10:
|
|
507
|
+
delta /= 2
|
|
508
|
+
it = 0
|
|
509
|
+
restarts += 1
|
|
510
|
+
diverging = False
|
|
511
|
+
diverging_steps = 0
|
|
464
512
|
it += 1
|
|
465
513
|
if it >= ITMAX and not found:
|
|
466
514
|
s = f'Last iteration reached a unbalance of: \
|
|
@@ -567,14 +615,20 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
567
615
|
|
|
568
616
|
@property
|
|
569
617
|
def n_min(self) -> float:
|
|
570
|
-
"""Return minimum axial load.
|
|
618
|
+
"""Return minimum axial load.
|
|
619
|
+
|
|
620
|
+
In most situations, this is the capacity in compression.
|
|
621
|
+
"""
|
|
571
622
|
if self._n_min is None:
|
|
572
623
|
self._n_min, self._n_max = self.calculate_limit_axial_load()
|
|
573
624
|
return self._n_min
|
|
574
625
|
|
|
575
626
|
@property
|
|
576
627
|
def n_max(self) -> float:
|
|
577
|
-
"""Return maximum axial load.
|
|
628
|
+
"""Return maximum axial load.
|
|
629
|
+
|
|
630
|
+
In most situations, this is the capacity in tension.
|
|
631
|
+
"""
|
|
578
632
|
if self._n_max is None:
|
|
579
633
|
self._n_min, self._n_max = self.calculate_limit_axial_load()
|
|
580
634
|
return self._n_max
|
|
@@ -631,7 +685,7 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
631
685
|
matrix then `integrate='modulus'`.
|
|
632
686
|
|
|
633
687
|
Examples:
|
|
634
|
-
result = self.integrate_strain_profile(strain,integrate='
|
|
688
|
+
result = self.integrate_strain_profile(strain,integrate='modulus')
|
|
635
689
|
# `result` will be the tangent stiffness matrix (a 3x3 numpy array)
|
|
636
690
|
|
|
637
691
|
result = self.integrate_strain_profile(strain)
|
|
@@ -678,6 +732,9 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
678
732
|
Returns:
|
|
679
733
|
UltimateBendingMomentResults: The results from the calculation.
|
|
680
734
|
"""
|
|
735
|
+
# Check if the section can carry the axial load
|
|
736
|
+
self.check_axial_load(n=n)
|
|
737
|
+
|
|
681
738
|
# Compute the bending strength with the bisection algorithm
|
|
682
739
|
# Rotate the section of angle theta
|
|
683
740
|
rotated_geom = self.section.geometry.rotate(-theta)
|
|
@@ -685,8 +742,6 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
685
742
|
# Rotate also triangulated data!
|
|
686
743
|
self._rotate_triangulated_data(-theta)
|
|
687
744
|
|
|
688
|
-
# Check if the section can carry the axial load
|
|
689
|
-
self.check_axial_load(n=n)
|
|
690
745
|
# Find the strain distribution corresponding to failure and equilibrium
|
|
691
746
|
# with external axial force
|
|
692
747
|
strain = self.find_equilibrium_fixed_pivot(rotated_geom, n)
|
|
@@ -752,6 +807,9 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
752
807
|
Returns:
|
|
753
808
|
MomentCurvatureResults: The calculation results.
|
|
754
809
|
"""
|
|
810
|
+
# Check if the section can carry the axial load
|
|
811
|
+
self.check_axial_load(n=n)
|
|
812
|
+
|
|
755
813
|
# Create an empty response object
|
|
756
814
|
res = s_res.MomentCurvatureResults()
|
|
757
815
|
res.n = n
|
|
@@ -761,9 +819,6 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
761
819
|
# Rotate also triangulated data!
|
|
762
820
|
self._rotate_triangulated_data(-theta)
|
|
763
821
|
|
|
764
|
-
# Check if the section can carry the axial load
|
|
765
|
-
self.check_axial_load(n=n)
|
|
766
|
-
|
|
767
822
|
if chi is None:
|
|
768
823
|
# Find ultimate curvature from the strain distribution
|
|
769
824
|
# corresponding to failure and equilibrium with external axial
|
|
@@ -1342,7 +1397,7 @@ class GenericSectionCalculator(SectionCalculator):
|
|
|
1342
1397
|
n (float): Axial load.
|
|
1343
1398
|
my (float): Bending moment around y-axis.
|
|
1344
1399
|
mz (float): Bending moment around z-axis.
|
|
1345
|
-
initial (bool): If True the modified newton with initial
|
|
1400
|
+
initial (bool): If True the modified newton with initial tangent is
|
|
1346
1401
|
used (default = False).
|
|
1347
1402
|
max_iter (int): the maximum number of iterations in the iterative
|
|
1348
1403
|
process (default = 10).
|
|
@@ -4,7 +4,8 @@ import typing as t
|
|
|
4
4
|
|
|
5
5
|
import structuralcodes.core._section_results as s_res
|
|
6
6
|
from structuralcodes.geometry import CompoundGeometry, SurfaceGeometry
|
|
7
|
-
from structuralcodes.materials.
|
|
7
|
+
from structuralcodes.materials.basic import ElasticMaterial, GenericMaterial
|
|
8
|
+
from structuralcodes.materials.constitutive_laws import UserDefined
|
|
8
9
|
from structuralcodes.sections import GenericSection
|
|
9
10
|
from structuralcodes.sections.section_integrators import FiberIntegrator
|
|
10
11
|
|
|
@@ -57,13 +58,22 @@ def calculate_elastic_cracked_properties(
|
|
|
57
58
|
rotated_geometry = section.geometry.rotate(-theta)
|
|
58
59
|
|
|
59
60
|
for geo in rotated_geometry.geometries:
|
|
60
|
-
Ec = geo.material.get_tangent(eps=0)
|
|
61
|
-
|
|
61
|
+
Ec = geo.material.constitutive_law.get_tangent(eps=0)
|
|
62
|
+
density = geo.material.density
|
|
63
|
+
elastic_concrete_law = UserDefined([-100, 0], [-100 * Ec, 0])
|
|
64
|
+
elastic_concrete = GenericMaterial(
|
|
65
|
+
density=density,
|
|
66
|
+
constitutive_law=elastic_concrete_law,
|
|
67
|
+
name='elastic concrete',
|
|
68
|
+
)
|
|
62
69
|
geo._material = elastic_concrete
|
|
63
70
|
|
|
64
71
|
for pg in rotated_geometry.point_geometries:
|
|
65
|
-
Es = pg.material.get_tangent(eps=0)
|
|
66
|
-
|
|
72
|
+
Es = pg.material.constitutive_law.get_tangent(eps=0)
|
|
73
|
+
density = pg.material.density
|
|
74
|
+
elastic_steel = ElasticMaterial(
|
|
75
|
+
E=Es, density=density, name='elastic steel'
|
|
76
|
+
)
|
|
67
77
|
pg._material = elastic_steel
|
|
68
78
|
|
|
69
79
|
curv = -1e-5 # Any curvature should return the same mechanical properties.
|