Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ per-file-ignores = tests/*:S101,__init__.py:F401,post.py:C901
rst-roles = class,const,func,meth,mod,ref
rst-directives = deprecated
pytest-fixture-no-parentheses = True
pytest-mark-no-parentheses = True
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ __pycache__/

# Jupyter Notebook
.ipynb_checkpoints

# benchmark results
.benchmarks
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,22 @@ nox --session=tests
Unit tests are located in the _tests_ directory, and are written using the [pytest]
testing framework.

### Benchmarks

If the code you are modifying may affect the performance of `sectionproperties`, it is
recommended that you run the benchmarking tests to verify the performance before and
after your changes. There are three different benchmarking suites: `geometry`, `meshing`
and `analysis`. These can be run like this:

```shell
poetry run pytest -m benchmark_geom
poetry run pytest -m benchmark_mesh
poetry run pytest -m benchmark_analysis
```

Note that a plot of the results can be generated by adding the `--benchmark-histogram`
option to the above commands.

[pytest]: https://pytest.readthedocs.io/

## How to submit changes
Expand Down
17 changes: 17 additions & 0 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,23 @@ this:
Unit tests are located in the *tests* directory, and are written using
the `pytest <https://pytest.readthedocs.io/>`__ testing framework.

Benchmarks
^^^^^^^^^^

If the code you are modifying may affect the performance of ``sectionproperties``, it is
recommended that you run the benchmarking tests to verify the performance before and
after your changes. There are three different benchmarking suites: ``geometry``,
``meshing`` and ``analysis``. These can be run like this:

.. code:: shell

poetry run pytest -m benchmark_geom
poetry run pytest -m benchmark_mesh
poetry run pytest -m benchmark_analysis

Note that a plot of the results can be generated by adding the ``--benchmark-histogram``
option to the above commands.

How to submit changes
---------------------

Expand Down
11 changes: 10 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,16 @@ def tests(session: Session) -> None:
session.install("coverage[toml]", "pytest", "pygments", "pytest-check")

try:
session.run("coverage", "run", "--parallel", "-m", "pytest", *session.posargs)
session.run(
"coverage",
"run",
"--parallel",
"-m",
"pytest",
"-m",
"not benchmark",
*session.posargs,
)
finally:
if session.interactive:
session.notify("coverage", posargs=[])
Expand Down
63 changes: 62 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pre-commit = "^3.4.0"
pre-commit-hooks = "^4.5.0"
Pygments = "^2.16.1"
pytest = "^7.4.2"
pytest-benchmark = { extras = ["histogram"], version = "^4.0.0" }
pytest-check = "^2.2.2"
pyupgrade = "^3.15.0"
sphinx = "^7.2.6"
Expand Down Expand Up @@ -112,6 +113,13 @@ show_missing = true
profile = "black"
lines_after_imports = 2

[tool.pytest.ini_options]
markers = [
"benchmark_geom: geometry benchmark tests (select with '-m benchmark_geom')",
"benchmark_mesh: mesh benchmark tests (select with '-m benchmark_mesh')",
"benchmark_analysis: analysis benchmark tests (select with '-m benchmark_analysis')",
]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
1 change: 1 addition & 0 deletions tests/benchmarks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Benchmark tests for sectionproperties."""
127 changes: 127 additions & 0 deletions tests/benchmarks/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""pytest benchmark configurations."""

from __future__ import annotations

from typing import Callable

import pytest

from sectionproperties.pre import Geometry, Material
from sectionproperties.pre.library import (
circular_hollow_section,
circular_section,
concrete_column_section,
rectangular_section,
)


@pytest.fixture
def concrete() -> Material:
"""Creates a concrete material object.

Returns:
Concrete
"""
return Material(
name="Concrete",
elastic_modulus=30.1e3,
poissons_ratio=0.2,
yield_strength=32,
density=2.4e-6,
color="lightgrey",
)


@pytest.fixture
def steel() -> Material:
"""Creates a steel material object.

Returns:
Steel
"""
return Material(
name="Steel",
elastic_modulus=200e3,
poissons_ratio=0.3,
yield_strength=500,
density=7.85e-6,
color="grey",
)


@pytest.fixture
def rect_geom() -> Geometry:
"""Creates a rectangular geometry.

Returns:
Geometry
"""
return rectangular_section(d=100, b=50)


@pytest.fixture
def chs_geom() -> Geometry:
"""Creates a rectangular geometry.

Returns:
Geometry
"""
return circular_hollow_section(d=100, t=3, n=128)


@pytest.fixture
def concrete_column_with_hole(concrete, steel) -> Callable:
"""Creates a concrete column with a hole at its centre.

Args:
concrete: Concrete material
steel: Steel material

Returns:
Generator function
"""

def _generate_geom() -> Geometry:
geom = concrete_column_section(
d=600,
b=300,
dia_bar=25,
area_bar=500,
n_x=3,
n_y=6,
cover=35,
n_circle=4,
filled=False,
conc_mat=concrete,
steel_mat=steel,
)
hole = circular_section(d=100, n=32).shift_section(x_offset=150, y_offset=300)

return geom - hole

return _generate_geom


@pytest.fixture
def analysis_geometry() -> Callable:
"""Create a geometry to be used for analysis.

Returns:
Generator function
"""

def _generate_geom(num_elements: int) -> Geometry:
mat_a = Material("a", 1, 0, 1, 1, color="b")
mat_b = Material("b", 10, 0, 1, 1, color="g")
mat_c = Material("c", 5, 0, 1, 1, color="r")
mat_d = Material("d", 2, 0, 1, 1, color="y")

a = rectangular_section(20, 20, mat_a)
b = rectangular_section(20, 20, mat_b).align_to(a, "right")
c = rectangular_section(20, 20, mat_c).align_to(a, "top")
d = rectangular_section(20, 20, mat_d).align_to(a, "top").align_to(a, "right")
geom = a + b + c + d
mesh_area = geom.calculate_area() / num_elements * 1.6
return geom.create_mesh([mesh_area])

return _generate_geom
Loading