Developer guide¶
This page covers the project layout, testing practices, and contribution guidelines.
Project layout¶
gensec/
├── src/gensec/ # package source
│ ├── materials/ # constitutive laws and property tables
│ │ ├── base.py
│ │ ├── concrete.py
│ │ ├── steel.py
│ │ ├── tabulated.py
│ │ ├── ec2_properties.py
│ │ ├── en10025_properties.py
│ │ └── ec2_bridge.py
│ ├── geometry/ # section definition and meshing
│ │ ├── fiber.py
│ │ ├── geometry.py
│ │ ├── primitives.py
│ │ └── section.py
│ ├── solver/ # numerical core
│ │ ├── integrator.py
│ │ ├── capacity.py
│ │ └── check.py
│ ├── output/ # plotting, export, reporting
│ │ ├── plots.py
│ │ ├── export.py
│ │ └── report.py
│ ├── io_yaml.py # YAML input loader
│ ├── cli.py # command-line interface
│ └── __main__.py # python -m gensec
├── tests/ # test suite
├── docs/ # Sphinx documentation
├── examples/ # YAML input files
└── pyproject.toml
Running the test suite¶
# With pytest (recommended)
uv run python -m pytest tests/ -v
# With unittest
uv run python -m unittest discover -s tests -v
The suite contains 106 tests organized in four files:
Writing tests¶
Each development phase must include a validation suite. Follow these principles:
Analytical reference cases: whenever possible, compare against hand-calculated or textbook results, not just against GenSec’s own output. Typical cases: pure axial compression/tension (closed-form), symmetric sections (symmetry checks), rebar-only sections (steel stress × area).
Tolerances: use relative tolerances of 1–2 % for integration-based results (fiber discretization introduces mesh-dependent error). Use tight tolerances (< 0.01 %) for material law evaluations.
Round-trip consistency: for the inverse solver, verify that
solve_equilibriumfollowed bycompute_forcesrecovers the original targets within tolerance.Edge cases: zero curvature, zero axial force, single-fiber sections, sections with only rebars.
Documentation standards¶
All code is documented in English, in numpydoc style, ready for Sphinx with LaTeX math formulas.
Every public class, method, and function must have a complete docstring with
Parameters,Returns, andRaisessections as appropriate.Use raw docstrings (
r""") when LaTeX math is present.Mathematical formulas use the
:math:role for inline expressions and.. math::directives for display equations.Cross-reference other classes and modules using Sphinx roles:
:class:`~gensec.materials.Concrete`,:func:`~gensec.materials.concrete_from_ec2`, etc.
Adding a new material¶
Create a new module in
materials/that subclassesMaterial.Implement
stress(eps),stress_array(eps),eps_min, andeps_max. Thestress_arraymethod must accept arrays of any shape (1-D, 2-D, …).Recommended: implement
tangent(eps)andtangent_array(eps)with the closed-form derivative of the constitutive law. If omitted, the base class provides a finite-difference fallback, but the analytical form is faster and more accurate.Optional: if the constitutive law is computationally intensive, consider adding a Numba JIT kernel guarded by a
try: import numbablock. Seeconcrete.pyfor the pattern.Register the new
typestring inio_yaml.pyso that YAML files can reference it.Add pointwise tests in
test_materials.py, including tests fortangent_arrayconsistency with finite differences.Update the API docs in
docs/api/gensec.materials.rst.
Adding a new parametric shape¶
Write a factory function in
primitivesthat returns ashapely.geometry.Polygon.Register the
shapename inio_yaml.py.Add a test and an example YAML file.
Update YAML input reference with the new shape parameters.