Skip to content

Commit e7d2378

Browse files
committed
docs: add dev section about constraints
1 parent 3a2b295 commit e7d2378

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Problem constraints
2+
3+
The [`Problem`](#engibench.core.Problem) class provides a [`check_constraints`](#engibench.core.Problem.check_constraints) method to validate input parameters.
4+
5+
So that it works, problems have to declare the constraints for their parameters in their `Conditions` class member (which itself is a [dataclass](https://docs.python.org/3/library/dataclasses.html)).
6+
7+
Constraints can have the following categories:
8+
9+
```{eval-rst}
10+
.. autodata:: engibench.constraint.THEORY
11+
```
12+
13+
```{eval-rst}
14+
.. autodata:: engibench.constraint.IMPL
15+
```
16+
17+
18+
A constraint can have more than one category. The `|` operator can be used to combine categories.
19+
20+
On top of categories, constraints have a criticality level ([`Error`](engibench.constraint.Criticality.Error) by default)
21+
22+
```{eval-rst}
23+
.. autoclass:: engibench.constraint.Criticality
24+
:members:
25+
:undoc-members:
26+
```
27+
28+
There are 2 ways to declare a constraint:
29+
30+
## Simple constraint, only constraining a single parameter
31+
32+
Use [typing.Annotated](https://docs.python.org/3/library/typing.html#typing.Annotated),
33+
where the annotation is one or multiple [`Constraint`](#engibench.constraint.Constraint) objects.
34+
35+
Predefined constraints are:
36+
37+
```{eval-rst}
38+
.. automethod:: engibench.constraint.bounded
39+
```
40+
41+
```{eval-rst}
42+
.. automethod:: engibench.constraint.less_than
43+
```
44+
45+
```{eval-rst}
46+
.. automethod:: engibench.constraint.greater_than
47+
```
48+
49+
Example:
50+
```py
51+
@dataclass
52+
class Conditions:
53+
"""Conditions."""
54+
55+
volfrac: Annotated[
56+
float,
57+
bounded(lower=0.0, upper=1.0).category(THEORY),
58+
bounded(lower=0.1, upper=0.9).warning().category(IMPL),
59+
] = 0.35
60+
```
61+
62+
Here, we declare a [`THEORY`](engibench.constraint.THEORY)/[`Error`](engibench.constraint.Criticality.Error) constraint and a [`IMPL`](engibench.constraint.IMPL)/[`Warning`](engibench.constraint.Criticality.Warning) constraint for the `volfrac` parameter.
63+
64+
## Constraint which also may affect more than one parameter
65+
Add a static method, decorated with the [`@constraint`](#engibench.constraint.constraint) decorator.
66+
67+
Example:
68+
```py
69+
@dataclass
70+
class Config(Conditions):
71+
"""Structured representation of conditions."""
72+
73+
rmin: float = 2.0
74+
nelx: int = 100
75+
nely: int = 50
76+
77+
@constraint
78+
@staticmethod
79+
def rmin_bound(rmin: float, nelx: int, nely: int) -> None:
80+
"""Constraint for rmin ∈ (0.0, max{ nelx, nely }]."""
81+
assert 0 < rmin <= max(nelx, nely), f"Params.rmin: {rmin} ∉ (0, max(nelx, nely)]"
82+
```
83+
84+
This declares a constraint for the 3 parameters (`rmin`, `nelx`, `nely`) with custom logic. This constraint does not have any category.
85+
If we would want to add a category, `@constraint` could be replaced by `@constraint(category=ERROR)` for example.
86+
87+
# API
88+
89+
```{eval-rst}
90+
.. autofunction:: engibench.constraint.constraint
91+
```
92+
93+
94+
```{eval-rst}
95+
.. autoclass:: engibench.constraint.Constraint
96+
:members:
97+
```

engibench/constraint.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ class Category(Flag):
2424

2525

2626
IMPL = Category.Implementation
27+
"""Violating the constraint, will cause runtime errors / undefined behavior
28+
due to the implementation."""
2729
THEORY = Category.Theory
30+
"""The constraint is not known to cause a runtime error, values outside of
31+
the constraint domain are unphysical and might lead to unphysical domains."""
2832
UNCATEGORIZED = Category(0)
2933

3034

0 commit comments

Comments
 (0)