From 02cffbaf13e2bc063e1b6539a62abc7841495676 Mon Sep 17 00:00:00 2001 From: Diego Talledo <38036285+talledodiego@users.noreply.github.com> Date: Wed, 18 Mar 2026 06:57:30 +0100 Subject: [PATCH 1/3] Add InformationWarning --- structuralcodes/__init__.py | 3 ++- structuralcodes/core/errors.py | 14 ++++++++++++-- structuralcodes/sections/_generic.py | 8 ++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/structuralcodes/__init__.py b/structuralcodes/__init__.py index 2e12a34a..08101845 100644 --- a/structuralcodes/__init__.py +++ b/structuralcodes/__init__.py @@ -4,7 +4,7 @@ from . import codes, core, geometry, materials, sections from .codes import get_design_codes, set_design_code, set_national_annex -from .core.errors import StructuralCodesWarning +from .core.errors import InformationWarning, StructuralCodesWarning __version__ = '0.6.4' @@ -20,3 +20,4 @@ ] warnings.filterwarnings(action='error', category=StructuralCodesWarning) +warnings.filterwarnings(action='always', category=InformationWarning) diff --git a/structuralcodes/core/errors.py b/structuralcodes/core/errors.py index 059dd6af..ba985dc8 100644 --- a/structuralcodes/core/errors.py +++ b/structuralcodes/core/errors.py @@ -6,6 +6,16 @@ class StructuralCodesWarning(Warning): class NoConvergenceWarning(StructuralCodesWarning): - """A warning that indicates that no convergence was reached for an - iterative solver. + """Warning for lack of convergence. + + A warning that indicates that no convergence was reached for an + iterative solver. The solution should be inspected with care. + """ + + +class InformationWarning(StructuralCodesWarning): + """Warning for simple information. + + A warning that indicates that some information that should be taken care + by user, but the calculation is not invalid. """ diff --git a/structuralcodes/sections/_generic.py b/structuralcodes/sections/_generic.py index ccfe7ff9..8fdca4dc 100644 --- a/structuralcodes/sections/_generic.py +++ b/structuralcodes/sections/_generic.py @@ -14,7 +14,10 @@ import structuralcodes.core._section_results as s_res from structuralcodes.core.base import Section, SectionCalculator -from structuralcodes.core.errors import NoConvergenceWarning +from structuralcodes.core.errors import ( + InformationWarning, + NoConvergenceWarning, +) from structuralcodes.geometry import ( CompoundGeometry, PointGeometry, @@ -149,7 +152,8 @@ def _calculate_gross_section_properties(self) -> s_res.SectionProperties: if isinstance(polygon, MultiPolygon): gp.perimeter = 0.0 warnings.warn( - 'Perimiter computation for a multi polygon is not defined.' + 'Perimiter computation for a multi polygon is not defined.', + category=InformationWarning, ) gp.perimeter = polygon.exterior.length From 9193320934e8954725d8acb8020b2ae41ffb4bd7 Mon Sep 17 00:00:00 2001 From: Diego Talledo <38036285+talledodiego@users.noreply.github.com> Date: Wed, 18 Mar 2026 06:58:14 +0100 Subject: [PATCH 2/3] Add test showing failing raised by #329 --- tests/test_sections/test_generic_section.py | 30 ++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/test_sections/test_generic_section.py b/tests/test_sections/test_generic_section.py index e862a08e..f24c8056 100644 --- a/tests/test_sections/test_generic_section.py +++ b/tests/test_sections/test_generic_section.py @@ -7,9 +7,13 @@ from shapely import Polygon from structuralcodes.codes.ec2_2004 import reinforcement_duct_props -from structuralcodes.core.errors import NoConvergenceWarning +from structuralcodes.core.errors import ( + InformationWarning, + NoConvergenceWarning, +) from structuralcodes.geometry import ( CircularGeometry, + CompoundGeometry, RectangularGeometry, SurfaceGeometry, add_reinforcement, @@ -1993,3 +1997,27 @@ def test_section_mm_domain_warning(b, h, n_bars, diameter, fck, fyk): # Check that the results arrays have the same size assert len(res.m_y) == len(res_good.m_y) + + +def test_perimeter_multipolygon(): + """Test calculating the perimeter of a multipolygon. + + This resoves issue #329. + """ + mat = ElasticMaterial(E=210000, density=7850) + rect1 = SurfaceGeometry( + poly=Polygon([(0, 0), (100, 0), (100, 10), (0, 10)]), + material=mat, + ) + rect2 = SurfaceGeometry( + poly=Polygon([(0, 200), (100, 200), (100, 210), (0, 210)]), + material=mat, + ) + + compound = CompoundGeometry([rect1, rect2]) + section = GenericSection(compound, integrator='marin') + + with pytest.warns(InformationWarning): + gp = section.gross_properties + + assert math.isclose(gp.perimeter, 0) From b91f32858c0b61f16d919aa5b248cf5e7ba19123 Mon Sep 17 00:00:00 2001 From: Diego Talledo <38036285+talledodiego@users.noreply.github.com> Date: Wed, 18 Mar 2026 06:58:44 +0100 Subject: [PATCH 3/3] fix: correct perimeter assignment for MultiPolygon --- structuralcodes/sections/_generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/structuralcodes/sections/_generic.py b/structuralcodes/sections/_generic.py index 8fdca4dc..2eb31ec1 100644 --- a/structuralcodes/sections/_generic.py +++ b/structuralcodes/sections/_generic.py @@ -155,8 +155,8 @@ def _calculate_gross_section_properties(self) -> s_res.SectionProperties: 'Perimiter computation for a multi polygon is not defined.', category=InformationWarning, ) - - gp.perimeter = polygon.exterior.length + else: + gp.perimeter = polygon.exterior.length # Computation of area: this is taken directly from shapely gp.area = self.section.geometry.area