Skip to content

Commit b0f3694

Browse files
authored
Merge branch 'main' into reduce-size-test-cli
2 parents bf2273b + 80cfc4b commit b0f3694

16 files changed

+291
-61
lines changed

.github/workflows/publish.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
path: dist
6262

6363
- name: Generate artifact attestation for sdist and wheel
64-
uses: actions/attest-build-provenance@v1
64+
uses: actions/attest-build-provenance@v2
6565
with:
6666
subject-path: dist
6767

@@ -84,7 +84,7 @@ jobs:
8484
path: dist
8585

8686
- name: Generate artifact attestation for sdist and wheel
87-
uses: actions/attest-build-provenance@v1
87+
uses: actions/attest-build-provenance@v2
8888
with:
8989
subject-path: dist
9090

.pre-commit-config.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,33 @@ repos:
55
- id: check-merge-conflict
66
- id: debug-statements
77
- repo: https://github.com/astral-sh/ruff-pre-commit
8-
rev: "v0.8.3"
8+
rev: "v0.9.10"
99
hooks:
1010
- id: ruff
1111
args: [--fix, --exit-non-zero-on-fix]
1212
- id: ruff-format
1313
- repo: https://github.com/pre-commit/mirrors-mypy
14-
rev: "v1.13.0"
14+
rev: "v1.15.0"
1515
hooks:
1616
- id: mypy
1717
additional_dependencies:
1818
[types-requests, types-PyYAML]
1919
- repo: https://github.com/igorshubovych/markdownlint-cli
20-
rev: v0.43.0
20+
rev: v0.44.0
2121
hooks:
2222
- id: markdownlint
2323
args: ["--disable", "MD013", "--disable", "MD025", "--"]
2424

2525
- repo: https://github.com/codespell-project/codespell
26-
rev: v2.3.0
26+
rev: v2.4.1
2727
hooks:
2828
- id: codespell
2929
name: Check common misspellings in text files with codespell.
3030
additional_dependencies:
3131
- tomli
3232

3333
- repo: https://github.com/tox-dev/pyproject-fmt
34-
rev: v2.5.0
34+
rev: v2.5.1
3535
hooks:
3636
- id: pyproject-fmt
3737
name: Apply a consistent format to pyproject.toml

docs/config_guide.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@ parameter_overrides:
4949
max_street_length: 40
5050
```
5151
52-
Note that we must provide the parameter category for the parameter that we are
52+
Note that we must provide the parameter group for the parameter that we are
5353
changing (`subcatchment_derivation` above).
5454

55+
If you want to understand how parameters are implemented in more detail, and in particular if you are creating new behaviours and need to add your own parameters, see our [parameter guide](parameters_guide.md).
56+
5557
As our SWMManywhere paper [link preprint](https://doi.org/10.1016/j.envsoft.2025.106358) demonstrates, you can capture an enormously wide range of UDM behaviours through changing parameters. However, if your system is particularly unusual, or you are testing out new behaviours then you may need to adopt a more elaborate approach.
5658

5759
### Customise `graphfcns`

docs/index.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ derive a synthetic urban drainage network anywhere in the world.
66
## Table of contents
77
<!-- markdownlint-disable MD007 -->
88
- [Home](index.md)
9-
- [About](./paper/paper.pdf)
9+
- [About](./paper/paper.md)
1010
- [Quickstart](quickstart.md)
1111
- Guides:
1212
- [Configuration file](config_guide.md)
1313
- [Extended demo](./notebooks/extended_demo.py)
14+
- [Parameters guide](parameters_guide.md)
1415
- [Graph functions](graphfcns_guide.md)
1516
- [Metrics guide](metrics_guide.md)
1617
- [Contributing](CONTRIBUTING.md)

docs/parameters_guide.md

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Parameters guide
2+
3+
SWMManywhere is a deliberately highly parameterised workflow, with the goal of enabling users to create a diverse range of UDMs. This guide is to explain the logic of the implemented parameters and how to customise them, as what each parameter does is highly specific to the [`graphfcn`](graphfcns_guide.md) that uses it. Instead, to understand specific parameter purposes, you can view all available parameters at the [API](reference-parameters.md).
4+
5+
## Using parameters
6+
7+
Let's look at a [parameter group](reference-parameters.md#swmmanywhere.parameters.OutfallDerivation), which is a group of parameters related to identifying outfall locations.
8+
9+
:::swmmanywhere.parameters.OutfallDerivation
10+
handler: python
11+
options:
12+
members: no
13+
show_root_heading: false
14+
show_bases: false
15+
show_source: true
16+
show_root_toc_entry: false
17+
show_docstring_attributes: false
18+
show_docstring_description: false
19+
show_docstring_examples: false
20+
show_docstring_parameters: false
21+
show_docstring_returns: false
22+
show_docstring_raises: false
23+
24+
We can see here three related parameters and relevant metadata, grouped together in a [`pydantic.BaseModel`](https://docs.pydantic.dev/latest/api/base_model/) object. Parameters in SWMManywhere are grouped together because `graphfcns` that need one of them tend to need the others. Let's look at [`identify_outfalls`](reference-graph-utilities.md#swmmanywhere.graphfcns.outfall_graphfcns.identify_outfalls), which needs these parameters.
25+
26+
:::swmmanywhere.graphfcns.outfall_graphfcns.identify_outfalls
27+
handler: python
28+
options:
29+
members: no
30+
show_root_heading: false
31+
show_bases: false
32+
show_source: true
33+
show_root_toc_entry: false
34+
show_docstring_attributes: false
35+
show_docstring_description: false
36+
show_docstring_examples: false
37+
show_docstring_parameters: false
38+
show_docstring_returns: false
39+
show_docstring_raises: false
40+
41+
When calling [`iterate_graphfcns`](reference-graph-utilities.md#swmmanywhere.graph_utilities.iterate_graphfcns), for more information see [here](graphfcns_guide.md#lists-of-graph-functions), SWMManywhere will automatically provide any parameters that have been registered to any graphfcn.
42+
43+
## Registering parameters
44+
45+
When you create a new parameter, it will need to belong to an existing or new parameter group.
46+
47+
### Creating a new parameter group(s)
48+
49+
You create a new module(s) that can contain multiple parameter groups. See below as a template of such amodule.
50+
51+
```python
52+
{%
53+
include-markdown "../tests/test_data/custom_parameters.py"
54+
comments=false
55+
%}
56+
```
57+
58+
### Adjust config file
59+
60+
We will add the required lines to the
61+
[minimum viable config](config_guide.md#minimum-viable-configuration) template.
62+
63+
```yml
64+
{%
65+
include-markdown "snippets/minimum_viable_template.yml"
66+
comments=false
67+
%}
68+
custom_parameter_modules:
69+
- /path/to/custom_parameters.py
70+
```
71+
72+
Now when we run our `config` file, these parameters will be registered and any [custom graphfcns](graphfcns_guide.md#add-a-new-graph-function) will have access to them.
73+
74+
### Changing existing parameter groups
75+
76+
There may be cases where you want to change existing parameter groups, such as introducing new weights to the [`calculate_weights`](reference-graph-utilities.md#swmmanywhere.graphfcns.topology_graphfcns.calculate_weights) step so that they are minimized during the shortest path optimization. In this example, we want the [`TopologyDerivation`](reference-parameters.md#swmmanywhere.parameters.TopologyDerviation) group to include some new parameters. We can do this in a similar way to [above](#creating-a-new-parameter-groups), but being mindful to inherit from `TopologyDerivation` rather than `BaseModel`:
77+
78+
```python
79+
from swmmanywhere.parameters import register_parameter_group, TopologyDerivation, Field
80+
81+
@register_parameter_group("topology_derivation")
82+
class NewTopologyDerivation(TopologyDerivation):
83+
new_weight_scaling: float = Field(
84+
default=1,
85+
le=1,
86+
ge=0,
87+
)
88+
new_weight_exponent: float = Field(
89+
default=1,
90+
le=2,
91+
ge=0,
92+
)
93+
```
94+
95+
Now the `calculate_weights` function will have access to these new weighting parameters, as well as existing ones.
96+
97+
Note, in this specific example of adding custom weights, you will also have to:
98+
99+
- Update the `weights` parameter in your `config` file, for example:
100+
101+
```yaml
102+
parameter_overrides:
103+
topology_derviation:
104+
weights:
105+
- new_weight
106+
- length
107+
```
108+
109+
- [Create and register a `graphfcn`](graphfcns_guide.md#add-a-new-graph-function) that adds the `new_weight` parameter to the graph.

mkdocs.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ extra_javascript:
4141

4242
nav:
4343
- Home: index.md
44-
- About: ./paper/paper.pdf
44+
- About: ./paper/paper.md
4545
- Quickstart: quickstart.md
4646
- Guides:
4747
- Configuration guide: config_guide.md
4848
- Extended demo: ./notebooks/extended_demo.py
49+
- Parameters guide: parameters_guide.md
4950
- Graph functions: graphfcns_guide.md
5051
- Metrics guide: metrics_guide.md
5152
- Contributing: CONTRIBUTING.md

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ lint.pydocstyle.convention = "google"
114114

115115
[tool.codespell]
116116
skip = "src/swmmanywhere/defs/iso_converter.yml,*.inp,docs/paper/*"
117-
ignore-words-list = "gage,gages,Carrer"
117+
ignore-words-list = "gage,gages,Carrer,anc"
118118

119119
[tool.pytest.ini_options]
120120
addopts = "-v --cov=src/swmmanywhere --cov-report=xml --doctest-modules --ignore=src/swmmanywhere/logging.py"

src/netcomp/distance/exact.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,7 @@ def lambda_dist(A1, A2, k=None, p=2, kind="laplacian"):
192192
evals1, evals2 = [evals[::-1] for evals in [evals1, evals2]]
193193
else:
194194
raise InputError(
195-
"Invalid type, choose from 'laplacian', "
196-
"'laplacian_norm', and 'adjacency'."
195+
"Invalid type, choose from 'laplacian', 'laplacian_norm', and 'adjacency'."
197196
)
198197
dist = la.norm(evals1[:k] - evals2[:k], ord=p)
199198
return dist

src/netcomp/linalg/resistance.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def resistance_matrix(A, check_connected=True):
7171
G = nx.from_numpy_array(A)
7272
if not nx.is_connected(G):
7373
raise UndefinedException(
74-
"Graph is not connected. " "Resistance matrix is undefined."
74+
"Graph is not connected. Resistance matrix is undefined."
7575
)
7676
L = laplacian_matrix(A)
7777
with suppress(Exception):

src/swmmanywhere/defs/schema.yml

+1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ properties:
3333
parameter_overrides: {type: ['object', 'null']}
3434
custom_metric_modules: {type: array, items: {type: string}}
3535
custom_graphfcn_modules: {type: array, items: {type: string}}
36+
custom_parameters_modules: {type: array, items: {type: string}}
3637
required: [base_dir, project, bbox]

src/swmmanywhere/parameters.py

+29-7
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,36 @@
22

33
from __future__ import annotations
44

5+
from typing import Callable
6+
57
import numpy as np
68
from pydantic import BaseModel, Field, model_validator
79

10+
from swmmanywhere.logging import logger
11+
12+
parameter_register = {}
13+
14+
15+
def register_parameter_group(name: str) -> Callable:
16+
"""Register a parameter group.
17+
18+
Args:
19+
name (str): Name of the parameter group that it will be keyed to in
20+
parameter_register.
21+
"""
22+
23+
def wrapper(cls: BaseModel) -> BaseModel:
24+
if name in parameter_register:
25+
logger.warning(f"{name} already in parameter register, overwriting.")
26+
parameter_register[name] = cls()
27+
return cls
28+
29+
return wrapper
30+
831

932
def get_full_parameters():
1033
"""Get the full set of parameters."""
11-
return {
12-
"subcatchment_derivation": SubcatchmentDerivation(),
13-
"outfall_derivation": OutfallDerivation(),
14-
"topology_derivation": TopologyDerivation(),
15-
"hydraulic_design": HydraulicDesign(),
16-
"metric_evaluation": MetricEvaluation(),
17-
}
34+
return parameter_register
1835

1936

2037
def get_full_parameters_flat():
@@ -32,6 +49,7 @@ def get_full_parameters_flat():
3249
return parameters_flat
3350

3451

52+
@register_parameter_group(name="subcatchment_derivation")
3553
class SubcatchmentDerivation(BaseModel):
3654
"""Parameters for subcatchment derivation."""
3755

@@ -86,6 +104,7 @@ class SubcatchmentDerivation(BaseModel):
86104
)
87105

88106

107+
@register_parameter_group(name="outfall_derivation")
89108
class OutfallDerivation(BaseModel):
90109
"""Parameters for outfall derivation."""
91110

@@ -113,6 +132,7 @@ class OutfallDerivation(BaseModel):
113132
)
114133

115134

135+
@register_parameter_group(name="topology_derivation")
116136
class TopologyDerivation(BaseModel):
117137
"""Parameters for topology derivation."""
118138

@@ -212,6 +232,7 @@ def check_weights(cls, values):
212232
return values
213233

214234

235+
@register_parameter_group("hydraulic_design")
215236
class HydraulicDesign(BaseModel):
216237
"""Parameters for hydraulic design."""
217238

@@ -273,6 +294,7 @@ class HydraulicDesign(BaseModel):
273294
)
274295

275296

297+
@register_parameter_group(name="metric_evaluation")
276298
class MetricEvaluation(BaseModel):
277299
"""Parameters for metric evaluation."""
278300

0 commit comments

Comments
 (0)