structuralcodes 0.6.1__tar.gz → 0.6.3__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.
Files changed (86) hide show
  1. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/PKG-INFO +1 -1
  2. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/__init__.py +1 -1
  3. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2004/__init__.py +18 -0
  4. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2004/_concrete_material_properties.py +169 -2
  5. structuralcodes-0.6.3/structuralcodes/codes/ec2_2004/_cracking_restraint_imposed_deformations.py +41 -0
  6. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/core/_section_results.py +19 -0
  7. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/basic/_elastic.py +12 -1
  8. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/concrete/_concreteEC2_2004.py +2 -2
  9. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/__init__.py +2 -0
  10. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_elastic.py +31 -17
  11. structuralcodes-0.6.3/structuralcodes/materials/constitutive_laws/_parallel.py +232 -0
  12. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_userdefined.py +25 -16
  13. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/_generic.py +98 -54
  14. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/_rc_utils.py +63 -43
  15. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/section_integrators/_fiber_integrator.py +8 -8
  16. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/section_integrators/_marin_integrator.py +165 -38
  17. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/LICENSE +0 -0
  18. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/README.md +0 -0
  19. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/pyproject.toml +0 -0
  20. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/__init__.py +0 -0
  21. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2004/_concrete_creep_and_shrinkage.py +0 -0
  22. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2004/_reinforcement_material_properties.py +0 -0
  23. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2004/_section_7_3_crack_control.py +0 -0
  24. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2004/shear.py +0 -0
  25. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2023/__init__.py +0 -0
  26. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2023/_annexB_time_dependent.py +0 -0
  27. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2023/_section5_materials.py +0 -0
  28. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/ec2_2023/_section9_sls.py +0 -0
  29. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/__init__.py +0 -0
  30. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_concrete_creep_and_shrinkage.py +0 -0
  31. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_concrete_interface_different_casting_times.py +0 -0
  32. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_concrete_material_properties.py +0 -0
  33. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_concrete_punching.py +0 -0
  34. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_concrete_shear.py +0 -0
  35. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_concrete_torsion.py +0 -0
  36. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_interface_concrete_steel_rebar.py +0 -0
  37. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2010/_reinforcement_material_properties.py +0 -0
  38. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/codes/mc2020/__init__.py +0 -0
  39. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/core/__init__.py +0 -0
  40. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/core/_marin_integration.py +0 -0
  41. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/core/base.py +0 -0
  42. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/__init__.py +0 -0
  43. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/_circular.py +0 -0
  44. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/_geometry.py +0 -0
  45. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/_rectangular.py +0 -0
  46. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/_reinforcement.py +0 -0
  47. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/__init__.py +0 -0
  48. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_base_profile.py +0 -0
  49. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_common_functions.py +0 -0
  50. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_hd.py +0 -0
  51. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_he.py +0 -0
  52. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_hp.py +0 -0
  53. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_ipe.py +0 -0
  54. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_ipn.py +0 -0
  55. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_l.py +0 -0
  56. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_li.py +0 -0
  57. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_u.py +0 -0
  58. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_ub.py +0 -0
  59. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_ubp.py +0 -0
  60. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_uc.py +0 -0
  61. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_upe.py +0 -0
  62. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_upn.py +0 -0
  63. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/geometry/profiles/_w.py +0 -0
  64. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/__init__.py +0 -0
  65. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/basic/__init__.py +0 -0
  66. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/basic/_elasticplastic.py +0 -0
  67. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/basic/_generic.py +0 -0
  68. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/concrete/__init__.py +0 -0
  69. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/concrete/_concrete.py +0 -0
  70. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/concrete/_concreteEC2_2023.py +0 -0
  71. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/concrete/_concreteMC2010.py +0 -0
  72. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_bilinearcompression.py +0 -0
  73. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_elasticplastic.py +0 -0
  74. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_initial_strain.py +0 -0
  75. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_parabolarectangle.py +0 -0
  76. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_popovics.py +0 -0
  77. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/constitutive_laws/_sargin.py +0 -0
  78. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/reinforcement/__init__.py +0 -0
  79. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/reinforcement/_reinforcement.py +0 -0
  80. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/reinforcement/_reinforcementEC2_2004.py +0 -0
  81. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/reinforcement/_reinforcementEC2_2023.py +0 -0
  82. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/materials/reinforcement/_reinforcementMC2010.py +0 -0
  83. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/__init__.py +0 -0
  84. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/section_integrators/__init__.py +0 -0
  85. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/section_integrators/_factory.py +0 -0
  86. {structuralcodes-0.6.1 → structuralcodes-0.6.3}/structuralcodes/sections/section_integrators/_section_integrator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structuralcodes
3
- Version: 0.6.1
3
+ Version: 0.6.3
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.9
@@ -3,7 +3,7 @@
3
3
  from . import codes, core, geometry, materials, sections
4
4
  from .codes import get_design_codes, set_design_code, set_national_annex
5
5
 
6
- __version__ = '0.6.1'
6
+ __version__ = '0.6.3'
7
7
 
8
8
  __all__ = [
9
9
  'set_design_code',
@@ -31,6 +31,10 @@ from ._concrete_creep_and_shrinkage import (
31
31
  )
32
32
  from ._concrete_material_properties import (
33
33
  Ecm,
34
+ Ecm_time,
35
+ beta_cc,
36
+ beta_ct,
37
+ beta_E,
34
38
  eps_c1,
35
39
  eps_c2,
36
40
  eps_c3,
@@ -39,11 +43,17 @@ from ._concrete_material_properties import (
39
43
  eps_cu3,
40
44
  fcd,
41
45
  fcm,
46
+ fcm_time,
42
47
  fctk_5,
43
48
  fctk_95,
44
49
  fctm,
50
+ fctm_time,
45
51
  k_sargin,
46
52
  n_parabolic_rectangular,
53
+ s_time_development,
54
+ )
55
+ from ._cracking_restraint_imposed_deformations import (
56
+ eps_sm_eps_cm_restraint_end,
47
57
  )
48
58
  from ._reinforcement_material_properties import (
49
59
  epsud,
@@ -94,6 +104,7 @@ __all__ = [
94
104
  'Asw_s_required',
95
105
  'alpha_e',
96
106
  'eps_sm_eps_cm',
107
+ 'eps_sm_eps_cm_restraint_end',
97
108
  'hc_eff',
98
109
  'k',
99
110
  'k1',
@@ -160,6 +171,13 @@ __all__ = [
160
171
  'phi_RH',
161
172
  't0_adj',
162
173
  't_T',
174
+ 'beta_cc',
175
+ 'beta_ct',
176
+ 'beta_E',
177
+ 's_time_development',
178
+ 'fcm_time',
179
+ 'fctm_time',
180
+ 'Ecm_time',
163
181
  ]
164
182
 
165
183
  __title__: str = 'EUROCODE 2 1992-1-1:2004'
@@ -1,9 +1,21 @@
1
1
  """Concrete material properties according to Tab. 3.1."""
2
2
 
3
+ from __future__ import annotations # To have clean hints of ArrayLike in docs
4
+
3
5
  import math
6
+ import typing as t
7
+
8
+ import numpy as np
9
+ from numpy.typing import ArrayLike
4
10
 
5
11
  from structuralcodes.codes import mc2010
6
12
 
13
+ S_TIME_DEVELOPMENT_DICT = {
14
+ 'R': 0.20,
15
+ 'N': 0.25,
16
+ 'S': 0.38,
17
+ } # As defined in Eq. (3.2)
18
+
7
19
 
8
20
  def fcm(fck: float, delta_f: float = 8) -> float:
9
21
  """The mean compressive strength of concrete.
@@ -124,7 +136,7 @@ def k_sargin(
124
136
  ) -> float:
125
137
  """Computation of k parameter for Sargin constitutive Law.
126
138
 
127
- EN 1992-1-1:2004, Eq. (3.14)
139
+ EN 1992-1-1:2004, Eq. (3.14).
128
140
 
129
141
  Args:
130
142
  Ecm (float): the mean elastic modulus of concrete in MPa.
@@ -225,7 +237,7 @@ def eps_cu3(fck: float) -> float:
225
237
  def fcd(fck: float, alpha_cc: float, gamma_c: float) -> float:
226
238
  """The design compressive strength of concrete.
227
239
 
228
- EN 1992-1-1:2004, Eq. (3.15)
240
+ EN 1992-1-1:2004, Eq. (3.15).
229
241
 
230
242
  Args:
231
243
  fck (float): The characteristic compressive strength in MPa.
@@ -237,3 +249,158 @@ def fcd(fck: float, alpha_cc: float, gamma_c: float) -> float:
237
249
  float: The design compressive strength of concrete in MPa
238
250
  """
239
251
  return abs(alpha_cc) * abs(fck) / abs(gamma_c)
252
+
253
+
254
+ def beta_cc(t: ArrayLike, s: float) -> ArrayLike:
255
+ """The time development function for compressive strength of concrete.
256
+
257
+ EN 1992-1-1:2004, Eq. (3.2).
258
+
259
+ Args:
260
+ t (ArrayLike): The time in days to evaluate the development function
261
+ for.
262
+ s (float): The scale factor in the exponent for the time development
263
+ function. s = 0.20 for class R, 0.25 for class N, and 0.38 for
264
+ class N.
265
+
266
+ Returns:
267
+ ArrayLike: The value of the time development function.
268
+ """
269
+ return np.exp(s * (1 - np.sqrt(28 / t)))
270
+
271
+
272
+ def beta_ct(t: ArrayLike, s: float) -> ArrayLike:
273
+ """The time development function for tensile strength of concrete.
274
+
275
+ EN 1992-1-1:2004, part of Eq. (3.4).
276
+
277
+ Args:
278
+ t (ArrayLike): The time in days to evaluate the development function
279
+ for.
280
+ s (float): The scale factor in the exponent for the time development
281
+ function. s = 0.20 for class R, 0.25 for class N, and 0.38 for
282
+ class N.
283
+
284
+ Returns:
285
+ ArrayLike: The value of the time development function.
286
+ """
287
+ if np.isscalar(t):
288
+ beta = beta_cc(t, s)
289
+ if t < 28:
290
+ return beta
291
+ return np.pow(beta, 2 / 3)
292
+ t = np.atleast_1d(t)
293
+ beta = beta_cc(t, s)
294
+ beta[t >= 28] = np.pow(beta[t >= 28], 2 / 3)
295
+ return beta
296
+
297
+
298
+ def beta_E(t: ArrayLike, s: float) -> ArrayLike:
299
+ """The time development function for Young's modulus of concrete.
300
+
301
+ EN 1992-1-1:2004, part of Eq. (3.5).
302
+
303
+ Args:
304
+ t (ArrayLike): The time in days to evaluate the development function
305
+ for.
306
+ s (float): The scale factor in the exponent for the time development
307
+ function. s = 0.20 for class R, 0.25 for class N, and 0.38 for
308
+ class N.
309
+
310
+ Returns:
311
+ ArrayLike: The value of the time development function.
312
+ """
313
+ return np.pow(beta_cc(t, s), 0.3)
314
+
315
+
316
+ def s_time_development(cement_class: t.Literal['S', 'N', 'R']) -> float:
317
+ """Return the scale factor for the exponent for the time development
318
+ function.
319
+
320
+ EN 1992-1-1:2004, Eq. (3.2).
321
+
322
+ Args:
323
+ cement_class (str): The cement class, either 'S', 'N' or 'R'.
324
+
325
+ Returns:
326
+ float: The scale factor that depends on the cement type.
327
+
328
+ Raises:
329
+ ValueError: If an invalid cement class is provided.
330
+
331
+ """
332
+ cement_class = (
333
+ cement_class.upper().strip() if cement_class is not None else ''
334
+ )
335
+ s = S_TIME_DEVELOPMENT_DICT.get(cement_class)
336
+
337
+ if s is None:
338
+ raise ValueError(
339
+ (
340
+ f'"{cement_class}" is not a valid cement class. '
341
+ 'Use either S, N or R.'
342
+ )
343
+ )
344
+ return s
345
+
346
+
347
+ def fcm_time(fcm: float, beta_cc: ArrayLike) -> ArrayLike:
348
+ """Calculate the compressive strength as function of time.
349
+
350
+ EN 1992-1-1:2004, Eq. (3.1).
351
+
352
+ Args:
353
+ fcm (float): The reference value for the compressive strength.
354
+ beta_cc (ArrayLike): The value(s) of the time development function.
355
+
356
+ Returns:
357
+ ArrayLike: The calculated value(s) of the compressive strength.
358
+
359
+ Note:
360
+ The value of beta_cc should be calculated with the function beta_cc.
361
+ """
362
+ return fcm * beta_cc
363
+
364
+
365
+ def fctm_time(fctm: float, beta_cc: ArrayLike, alpha: ArrayLike) -> ArrayLike:
366
+ """Calculate the tensile strength as function of time.
367
+
368
+ EN 1992-1-1:2004, Eq. (3.4).
369
+
370
+ Args:
371
+ fctm (float): The reference value for the tensile strength.
372
+ beta_cc (ArrayLike): The value(s) of the time development function.
373
+ alpha (ArrayLike): An exponent for the time development function. It
374
+ should be set to 1 for t < 28, and 2/3 else.
375
+
376
+ Returns:
377
+ ArrayLike: The calculated value(s) of the tensile strength.
378
+
379
+ Note:
380
+ The value of beta_cc should be calculated with the function beta_cc.
381
+ Alternatively, the time development function for the tensile strength
382
+ could be calculated directly with the function beta_ct.
383
+ """
384
+ return np.pow(beta_cc, alpha) * fctm
385
+
386
+
387
+ def Ecm_time(fcm: float, fcm_time: ArrayLike, Ecm: float) -> ArrayLike:
388
+ """Calculate the Young's modulus as function of time.
389
+
390
+ EN 1992-1-1:2004, Eq. (3.5).
391
+
392
+ Args:
393
+ fcm (float): The reference value for the compressive strength.
394
+ fcm_time (float): The value(s) of the compressive strength at the
395
+ point(s) in time.
396
+ Ecm (float): The reference value for the Young's modulus.
397
+
398
+ Returns:
399
+ ArrayLike: The calculated value(s) of the Young's modulus.
400
+
401
+ Note:
402
+ The value of fcm_time should be calculated with the function fcm_time.
403
+ Alternatively, the time development function for the Young's modulus
404
+ could be calculated directly with the function beta_E.
405
+ """
406
+ return np.pow(fcm_time / fcm, 0.3) * Ecm
@@ -0,0 +1,41 @@
1
+ """Collection of functions from EUROCODE 1992-3:2006."""
2
+
3
+
4
+ def eps_sm_eps_cm_restraint_end(
5
+ alpha_e: float,
6
+ rho_p_eff: float,
7
+ kc: float,
8
+ k: float,
9
+ fct_eff: float,
10
+ Es: float,
11
+ ) -> float:
12
+ """Returns the strain difference (epsilon_sm - epsilon_cm) needed to
13
+ compute the crack width for restraint member at its end.
14
+
15
+ EN 1992-3:2006, Eq. (M.1).
16
+
17
+ Args:
18
+ alpha_e (float): Is the ratio Es/Ecm.
19
+ rho_p_eff (float): Effective bond ratio between areas given by Eq.
20
+ (7.10).
21
+ kc (float): is a coefficient which takes account of the stress
22
+ distribution within the section immediately prior to cracking and
23
+ the change of the lever arm.
24
+ k (float): is the coefficient which allow for the effect of
25
+ non-uniform self-equilibrating stresses, which lead to a
26
+ reduction of restraint forces.
27
+ k=1 for webs w<=300mm or flanges widths less than 300mm
28
+ k=0.65 for webs w>=800mm or flanges with widths greater than 800mm
29
+ Intermediate values may be interpolated.
30
+ fct_eff (float): Is the mean value of the tensile strength in MPa of
31
+ the concrete effective at the time when the cracks may first be
32
+ expected to occur: fct_eff=fctm or fctm(t) if crack is expected
33
+ earlier than 28 days.
34
+ Es (float): Steel elastic modulus in MPa.
35
+
36
+ Returns:
37
+ float: The calculated strain difference.
38
+ """
39
+ return (
40
+ 0.5 * alpha_e * kc * k * fct_eff * (1 + 1 / (alpha_e * rho_p_eff)) / Es
41
+ )
@@ -4,6 +4,7 @@ from __future__ import annotations # To have clean hints of ArrayLike in docs
4
4
 
5
5
  from dataclasses import dataclass, field, fields
6
6
 
7
+ import numpy as np
7
8
  from numpy.typing import ArrayLike
8
9
 
9
10
 
@@ -125,6 +126,24 @@ class SectionProperties:
125
126
  """
126
127
  return f'{self}'
127
128
 
129
+ def isclose(self, other, rtol=1e-5, atol=1e-8):
130
+ """Check if two SectionProperties are close to each other.
131
+
132
+ Arguments:
133
+ other (SectionProperties): The other SectionProperties to compare.
134
+ rtol (float): The relative tolerance.
135
+ atol (float): The absolute tolerance.
136
+
137
+ Returns:
138
+ bool: True if the two SectionProperties are close, False otherwise.
139
+ """
140
+ if not isinstance(other, self.__class__):
141
+ return NotImplemented
142
+
143
+ a = np.array(list(vars(self).values()))
144
+ b = np.array(list(vars(other).values()))
145
+ return np.allclose(a, b, rtol=rtol, atol=atol)
146
+
128
147
 
129
148
  @dataclass
130
149
  class MomentCurvatureResults:
@@ -15,6 +15,9 @@ class ElasticMaterial(Material):
15
15
  self,
16
16
  E: float,
17
17
  density: float,
18
+ ultimate_strain: t.Optional[
19
+ t.Union[float, t.Tuple[float, float]]
20
+ ] = None,
18
21
  initial_strain: t.Optional[float] = None,
19
22
  initial_stress: t.Optional[float] = None,
20
23
  strain_compatibility: t.Optional[float] = None,
@@ -25,6 +28,13 @@ class ElasticMaterial(Material):
25
28
  Arguments:
26
29
  E (float): The Young's modulus.
27
30
  density (float): The density.
31
+ ultimate_strain (Optional[float, Tuple[float, float]]): The
32
+ ultimate strain of the material. If a single float is given,
33
+ it is used for both the positive and negative directions. If a
34
+ tuple of two floats is given, the first value is used for the
35
+ negative direction and the second value is used for the
36
+ positive direction. If None, the material has no ultimate
37
+ strain. Default value is None.
28
38
  initial_strain (Optional[float]): Initial strain of the material.
29
39
  initial_stress (Optional[float]): Initial stress of the material.
30
40
  strain_compatibility (Optional[bool]): Only relevant if
@@ -42,6 +52,7 @@ class ElasticMaterial(Material):
42
52
  name=name if name else 'ElasticMaterial',
43
53
  )
44
54
  self._E = E
55
+ self._ultimate_strain = ultimate_strain
45
56
  self._constitutive_law = create_constitutive_law('elastic', self)
46
57
  self._apply_initial_strain()
47
58
 
@@ -52,7 +63,7 @@ class ElasticMaterial(Material):
52
63
 
53
64
  def __elastic__(self) -> dict:
54
65
  """Returns kwargs for creating an elastic constitutive law."""
55
- return {'E': self.E}
66
+ return {'E': self.E, 'eps_u': self._ultimate_strain}
56
67
 
57
68
  @classmethod
58
69
  def from_material(cls, other_material: Material):
@@ -392,11 +392,11 @@ class ConcreteEC2_2004(Concrete): # noqa: N801
392
392
  float: The maximum strength at failure of concrete.
393
393
 
394
394
  Note:
395
- The returned value is derived from fcm if eps_cu1 is not manually
395
+ The returned value is derived from fck if eps_cu1 is not manually
396
396
  provided when initializing the object.
397
397
  """
398
398
  if self._eps_cu1 is None:
399
- return ec2_2004.eps_cu1(self.fcm)
399
+ return ec2_2004.eps_cu1(self.fck)
400
400
  return self._eps_cu1
401
401
 
402
402
  @property
@@ -8,6 +8,7 @@ from ._elastic import Elastic
8
8
  from ._elasticplastic import ElasticPlastic
9
9
  from ._initial_strain import InitialStrain
10
10
  from ._parabolarectangle import ParabolaRectangle
11
+ from ._parallel import Parallel
11
12
  from ._popovics import Popovics
12
13
  from ._sargin import Sargin
13
14
  from ._userdefined import UserDefined
@@ -21,6 +22,7 @@ __all__ = [
21
22
  'Sargin',
22
23
  'UserDefined',
23
24
  'InitialStrain',
25
+ 'Parallel',
24
26
  'get_constitutive_laws_list',
25
27
  'create_constitutive_law',
26
28
  ]
@@ -19,7 +19,12 @@ class Elastic(ConstitutiveLaw):
19
19
  'rebars',
20
20
  )
21
21
 
22
- def __init__(self, E: float, name: t.Optional[str] = None) -> None:
22
+ def __init__(
23
+ self,
24
+ E: float,
25
+ name: t.Optional[str] = None,
26
+ eps_u: t.Optional[t.Union[float, t.Tuple[float, float]]] = None,
27
+ ) -> None:
23
28
  """Initialize an Elastic Material.
24
29
 
25
30
  Arguments:
@@ -27,11 +32,20 @@ class Elastic(ConstitutiveLaw):
27
32
 
28
33
  Keyword Arguments:
29
34
  name (str): A descriptive name for the constitutive law.
35
+ eps_u (float or (float, float)): Defining ultimate strain. If a
36
+ single value is provided the same is adopted for both negative
37
+ and positive strains. If a tuple is provided, it should be
38
+ given as (negative, positive). Default value = None.
30
39
  """
31
40
  name = name if name is not None else 'ElasticLaw'
32
41
  super().__init__(name=name)
33
42
  self._E = E
34
- self._eps_su = None
43
+ if E <= 0:
44
+ raise ValueError('Elastic modulus should be greater than 0')
45
+ if eps_u is not None:
46
+ self._set_ultimate_strain(eps_u)
47
+ else:
48
+ self._eps_u = None
35
49
 
36
50
  def get_stress(
37
51
  self, eps: t.Union[float, ArrayLike]
@@ -91,12 +105,12 @@ class Elastic(ConstitutiveLaw):
91
105
  def get_ultimate_strain(self, **kwargs) -> t.Tuple[float, float]:
92
106
  """Return the ultimate strain (negative and positive)."""
93
107
  # There is no real strain limit, so set it to very large values
94
- # unlesse specified by the user differently
108
+ # unless specified by the user differently
95
109
  del kwargs
96
- return self._eps_su or (-100, 100)
110
+ return self._eps_u or (-100, 100)
97
111
 
98
- def set_ultimate_strain(
99
- self, eps_su=t.Union[float, t.Tuple[float, float]]
112
+ def _set_ultimate_strain(
113
+ self, eps_u=t.Union[float, t.Tuple[float, float]]
100
114
  ) -> None:
101
115
  """Set ultimate strains for Elastic Material if needed.
102
116
 
@@ -106,26 +120,26 @@ class Elastic(ConstitutiveLaw):
106
120
  and positive strains. If a tuple is provided, it should be
107
121
  given as (negative, positive).
108
122
  """
109
- if isinstance(eps_su, float):
110
- self._eps_su = (-abs(eps_su), abs(eps_su))
111
- elif isinstance(eps_su, tuple):
112
- if len(eps_su) < 2:
123
+ if isinstance(eps_u, float):
124
+ self._eps_u = (-abs(eps_u), abs(eps_u))
125
+ elif isinstance(eps_u, tuple):
126
+ if len(eps_u) < 2:
113
127
  raise ValueError(
114
128
  'Two values need to be provided when setting the tuple'
115
129
  )
116
- eps_su_n = eps_su[0]
117
- eps_su_p = eps_su[1]
118
- if eps_su_p < eps_su_n:
119
- eps_su_p, eps_su_n = eps_su_n, eps_su_p
120
- if eps_su_p < 0:
130
+ eps_u_n = eps_u[0]
131
+ eps_u_p = eps_u[1]
132
+ if eps_u_p < eps_u_n:
133
+ eps_u_p, eps_u_n = eps_u_n, eps_u_p
134
+ if eps_u_p < 0:
121
135
  raise ValueError(
122
136
  'Positive ultimate strain should be non-negative'
123
137
  )
124
- if eps_su_n > 0:
138
+ if eps_u_n > 0:
125
139
  raise ValueError(
126
140
  'Negative utimate strain should be non-positive'
127
141
  )
128
- self._eps_su = (eps_su_n, eps_su_p)
142
+ self._eps_u = (eps_u_n, eps_u_p)
129
143
  else:
130
144
  raise ValueError(
131
145
  'set_ultimate_strain requires a single value or a tuple \