floodmodeller-api 0.5.0.post1__py3-none-any.whl → 0.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- floodmodeller_api/__init__.py +11 -1
- floodmodeller_api/_base.py +55 -36
- floodmodeller_api/backup.py +15 -12
- floodmodeller_api/dat.py +191 -121
- floodmodeller_api/diff.py +4 -4
- floodmodeller_api/hydrology_plus/hydrology_plus_export.py +15 -14
- floodmodeller_api/ied.py +8 -10
- floodmodeller_api/ief.py +56 -42
- floodmodeller_api/ief_flags.py +1 -1
- floodmodeller_api/inp.py +7 -10
- floodmodeller_api/logs/lf.py +25 -26
- floodmodeller_api/logs/lf_helpers.py +20 -20
- floodmodeller_api/logs/lf_params.py +1 -5
- floodmodeller_api/mapping.py +11 -2
- floodmodeller_api/test/__init__.py +2 -2
- floodmodeller_api/test/conftest.py +2 -3
- floodmodeller_api/test/test_backup.py +2 -2
- floodmodeller_api/test/test_conveyance.py +13 -7
- floodmodeller_api/test/test_dat.py +168 -20
- floodmodeller_api/test/test_data/EX18_DAT_expected.json +164 -144
- floodmodeller_api/test/test_data/EX3_DAT_expected.json +6 -2
- floodmodeller_api/test/test_data/EX6_DAT_expected.json +12 -46
- floodmodeller_api/test/test_data/encoding_test_cp1252.dat +1081 -0
- floodmodeller_api/test/test_data/encoding_test_utf8.dat +1081 -0
- floodmodeller_api/test/test_data/integrated_bridge/AR_NoSP_NoBl_2O_NO_OneFRC.ied +33 -0
- floodmodeller_api/test/test_data/integrated_bridge/AR_vSP_25pc_1O.ied +32 -0
- floodmodeller_api/test/test_data/integrated_bridge/PL_vSP_25pc_1O.ied +34 -0
- floodmodeller_api/test/test_data/integrated_bridge/SBTwoFRCsStaggered.IED +32 -0
- floodmodeller_api/test/test_data/integrated_bridge/US_NoSP_NoBl_OR_RN.ied +28 -0
- floodmodeller_api/test/test_data/integrated_bridge/US_SP_NoBl_OR_frc_PT2-5_RN.ied +34 -0
- floodmodeller_api/test/test_data/integrated_bridge/US_fSP_NoBl_1O.ied +30 -0
- floodmodeller_api/test/test_data/integrated_bridge/US_nSP_NoBl_1O.ied +49 -0
- floodmodeller_api/test/test_data/integrated_bridge/US_vSP_NoBl_2O_Para.ied +35 -0
- floodmodeller_api/test/test_data/integrated_bridge.dat +40 -0
- floodmodeller_api/test/test_data/network.ied +2 -2
- floodmodeller_api/test/test_data/network_dat_expected.json +141 -243
- floodmodeller_api/test/test_data/network_ied_expected.json +2 -2
- floodmodeller_api/test/test_data/network_with_comments.ied +2 -2
- floodmodeller_api/test/test_data/structure_logs/EX17_expected.csv +4 -0
- floodmodeller_api/test/test_data/structure_logs/EX17_expected.json +69 -0
- floodmodeller_api/test/test_data/structure_logs/EX18_expected.csv +20 -0
- floodmodeller_api/test/test_data/structure_logs/EX18_expected.json +292 -0
- floodmodeller_api/test/test_data/structure_logs/EX6_expected.csv +4 -0
- floodmodeller_api/test/test_data/structure_logs/EX6_expected.json +35 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzn_flow.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzn_fr.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzn_mode.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzn_stage.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzn_state.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzn_velocity.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzx_left_fp_h.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzx_left_fp_mode.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzx_link_inflow.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzx_max.csv +87 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzx_right_fp_h.csv +182 -0
- floodmodeller_api/test/test_data/tabular_csv_outputs/network_zzx_right_fp_mode.csv +182 -0
- floodmodeller_api/test/test_flowtimeprofile.py +2 -2
- floodmodeller_api/test/test_hydrology_plus_export.py +4 -2
- floodmodeller_api/test/test_ied.py +3 -3
- floodmodeller_api/test/test_ief.py +12 -4
- floodmodeller_api/test/test_inp.py +2 -2
- floodmodeller_api/test/test_integrated_bridge.py +159 -0
- floodmodeller_api/test/test_json.py +14 -13
- floodmodeller_api/test/test_logs_lf.py +50 -29
- floodmodeller_api/test/test_read_file.py +1 -0
- floodmodeller_api/test/test_river.py +12 -12
- floodmodeller_api/test/test_tool.py +8 -5
- floodmodeller_api/test/test_toolbox_structure_log.py +148 -158
- floodmodeller_api/test/test_xml2d.py +14 -16
- floodmodeller_api/test/test_zz.py +143 -0
- floodmodeller_api/to_from_json.py +9 -9
- floodmodeller_api/tool.py +15 -11
- floodmodeller_api/toolbox/example_tool.py +5 -1
- floodmodeller_api/toolbox/model_build/add_siltation_definition.py +13 -9
- floodmodeller_api/toolbox/model_build/structure_log/structure_log.py +500 -194
- floodmodeller_api/toolbox/model_build/structure_log_definition.py +5 -1
- floodmodeller_api/units/__init__.py +15 -0
- floodmodeller_api/units/_base.py +87 -20
- floodmodeller_api/units/_helpers.py +343 -0
- floodmodeller_api/units/boundaries.py +59 -71
- floodmodeller_api/units/comment.py +1 -1
- floodmodeller_api/units/conduits.py +57 -54
- floodmodeller_api/units/connectors.py +112 -0
- floodmodeller_api/units/controls.py +107 -0
- floodmodeller_api/units/conveyance.py +1 -1
- floodmodeller_api/units/iic.py +2 -9
- floodmodeller_api/units/losses.py +44 -45
- floodmodeller_api/units/sections.py +52 -51
- floodmodeller_api/units/structures.py +361 -531
- floodmodeller_api/units/units.py +27 -26
- floodmodeller_api/units/unsupported.py +5 -7
- floodmodeller_api/units/variables.py +2 -2
- floodmodeller_api/urban1d/_base.py +13 -17
- floodmodeller_api/urban1d/conduits.py +11 -21
- floodmodeller_api/urban1d/general_parameters.py +1 -1
- floodmodeller_api/urban1d/junctions.py +7 -11
- floodmodeller_api/urban1d/losses.py +13 -17
- floodmodeller_api/urban1d/outfalls.py +18 -22
- floodmodeller_api/urban1d/raingauges.py +5 -10
- floodmodeller_api/urban1d/subsections.py +5 -4
- floodmodeller_api/urban1d/xsections.py +14 -17
- floodmodeller_api/util.py +23 -6
- floodmodeller_api/validation/parameters.py +7 -3
- floodmodeller_api/validation/urban_parameters.py +1 -4
- floodmodeller_api/validation/validation.py +11 -5
- floodmodeller_api/version.py +1 -1
- floodmodeller_api/xml2d.py +27 -31
- floodmodeller_api/xml2d_template.py +1 -1
- floodmodeller_api/zz.py +539 -0
- {floodmodeller_api-0.5.0.post1.dist-info → floodmodeller_api-0.5.2.dist-info}/LICENSE.txt +1 -1
- {floodmodeller_api-0.5.0.post1.dist-info → floodmodeller_api-0.5.2.dist-info}/METADATA +30 -16
- {floodmodeller_api-0.5.0.post1.dist-info → floodmodeller_api-0.5.2.dist-info}/RECORD +116 -83
- {floodmodeller_api-0.5.0.post1.dist-info → floodmodeller_api-0.5.2.dist-info}/WHEEL +1 -1
- floodmodeller_api/test/test_zzn.py +0 -36
- floodmodeller_api/units/helpers.py +0 -123
- floodmodeller_api/zzn.py +0 -414
- /floodmodeller_api/test/test_data/{network_from_tabularCSV.csv → tabular_csv_outputs/network_zzn_max.csv} +0 -0
- {floodmodeller_api-0.5.0.post1.dist-info → floodmodeller_api-0.5.2.dist-info}/entry_points.txt +0 -0
- {floodmodeller_api-0.5.0.post1.dist-info → floodmodeller_api-0.5.2.dist-info}/top_level.txt +0 -0
|
@@ -3,14 +3,15 @@ from pathlib import Path
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
5
|
from floodmodeller_api import XML2D
|
|
6
|
+
from floodmodeller_api.util import FloodModellerAPIError
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
@pytest.fixture
|
|
9
|
+
@pytest.fixture()
|
|
9
10
|
def xml_fp(test_workspace):
|
|
10
11
|
return Path(test_workspace, "Domain1_Q.xml")
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
@pytest.fixture
|
|
14
|
+
@pytest.fixture()
|
|
14
15
|
def data_before(xml_fp):
|
|
15
16
|
return XML2D(xml_fp)._write()
|
|
16
17
|
|
|
@@ -25,7 +26,7 @@ def test_xml2d_link_dtm_changes(xml_fp, data_before):
|
|
|
25
26
|
"""XML2D: Test changing and reverting link1d file and dtm makes no changes"""
|
|
26
27
|
x2d = XML2D(xml_fp)
|
|
27
28
|
prev_link = x2d.link1d[0]["link"]
|
|
28
|
-
domain =
|
|
29
|
+
domain = next(iter(x2d.domains))
|
|
29
30
|
prev_dtm = x2d.domains[domain]["topography"]
|
|
30
31
|
|
|
31
32
|
x2d.link1d[0]["link"] = ["new_link"]
|
|
@@ -56,10 +57,8 @@ def test_xml2d_change_revert_elem_topography():
|
|
|
56
57
|
"""XML2D: Check that when we change an existing element
|
|
57
58
|
that it is actually adding it and that it is being reverted."""
|
|
58
59
|
x2d = XML2D()
|
|
59
|
-
domain =
|
|
60
|
-
orig_topography = []
|
|
61
|
-
for item in x2d.domains[domain]["topography"]:
|
|
62
|
-
orig_topography.append(str(item))
|
|
60
|
+
domain = next(iter(x2d.domains))
|
|
61
|
+
orig_topography = [str(item) for item in x2d.domains[domain]["topography"]]
|
|
63
62
|
orig_xml = x2d._write()
|
|
64
63
|
x2d.domains[domain]["topography"][0] = "my/new/topography"
|
|
65
64
|
|
|
@@ -74,7 +73,7 @@ def test_xml2d_add_remove_branch_roughness():
|
|
|
74
73
|
"""XML2D: Check that we can actually add a branch and that
|
|
75
74
|
it is being added and passes validation (i.e write)"""
|
|
76
75
|
x2d = XML2D()
|
|
77
|
-
domain =
|
|
76
|
+
domain = next(iter(x2d.domains))
|
|
78
77
|
orig_xml = x2d._write()
|
|
79
78
|
x2d.domains[domain]["roughness"] = []
|
|
80
79
|
x2d.domains[domain]["roughness"].append(
|
|
@@ -91,7 +90,7 @@ def test_xml2d_append_remove_branch_roughness():
|
|
|
91
90
|
"""XML2D: Check that we can append an extra branch to preexisting branch
|
|
92
91
|
so that it passes validation"""
|
|
93
92
|
x2d = XML2D()
|
|
94
|
-
domain =
|
|
93
|
+
domain = next(iter(x2d.domains))
|
|
95
94
|
x2d.domains[domain]["roughness"] = []
|
|
96
95
|
x2d.domains[domain]["roughness"].append(
|
|
97
96
|
{"type": "file", "law": "manning", "value": "my/roughness/file.shp"},
|
|
@@ -115,7 +114,7 @@ def test_xml2d_append_remove_branch_roughness():
|
|
|
115
114
|
def test_xml2d_reorder_elem_computational_area_wrong_position():
|
|
116
115
|
"""XML2D: Check that if we add ??? in the wrong position does it reorder"""
|
|
117
116
|
x2d = XML2D()
|
|
118
|
-
domain =
|
|
117
|
+
domain = next(iter(x2d.domains))
|
|
119
118
|
x2d.domains[domain]["computational_area"] = {
|
|
120
119
|
"yll": ...,
|
|
121
120
|
"xll": ...,
|
|
@@ -132,20 +131,19 @@ def test_xml2d_reorder_elem_computational_area_wrong_position():
|
|
|
132
131
|
x2d.domains[domain]["computational_area"]["ncols"] = 12
|
|
133
132
|
x2d.domains[domain]["computational_area"]["nrows"] = 42
|
|
134
133
|
x2d.domains[domain]["computational_area"]["rotation"] = 3.14159
|
|
135
|
-
|
|
136
134
|
x2d.domains[domain]["run_data"]["upwind"] = "upwind value"
|
|
137
135
|
x2d.domains[domain]["run_data"]["wall"] = "Humpty Dumpty"
|
|
138
|
-
|
|
139
|
-
# TODO: Add check that this should fail validation if in the wrong order
|
|
140
|
-
# # how do I check that something fails?
|
|
141
|
-
|
|
142
136
|
assert x2d._write()
|
|
143
137
|
|
|
138
|
+
x2d.domains[domain]["run_data"]["upwind123"] = "upwind value"
|
|
139
|
+
with pytest.raises(FloodModellerAPIError):
|
|
140
|
+
assert x2d._write()
|
|
141
|
+
|
|
144
142
|
|
|
145
143
|
def test_xml2d_update_value(xml_fp, data_before):
|
|
146
144
|
"""XML2D: Test changing and reverting link1d file and dtm makes no changes"""
|
|
147
145
|
x2d = XML2D(xml_fp)
|
|
148
|
-
domain =
|
|
146
|
+
domain = next(iter(x2d.domains))
|
|
149
147
|
x2d.domains[domain]["run_data"]["scheme"] = "TVD"
|
|
150
148
|
|
|
151
149
|
assert x2d._write()
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# type: ignore
|
|
2
|
+
# ignored because the output from _ZZ.to_dataframe() is only a series in special cases
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from floodmodeller_api import IEF, ZZN, ZZX
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture()
|
|
13
|
+
def zzn(test_workspace: Path) -> ZZN:
|
|
14
|
+
path = test_workspace / "network.zzn"
|
|
15
|
+
return ZZN(path)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture()
|
|
19
|
+
def zzx(test_workspace: Path) -> ZZX:
|
|
20
|
+
path = test_workspace / "network.zzx"
|
|
21
|
+
return ZZX(path)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture()
|
|
25
|
+
def ief(test_workspace: Path) -> IEF:
|
|
26
|
+
path = test_workspace / "network.ief"
|
|
27
|
+
return IEF(path)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture()
|
|
31
|
+
def folder(test_workspace: Path) -> Path:
|
|
32
|
+
return test_workspace / "tabular_csv_outputs"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.mark.parametrize(
|
|
36
|
+
("csv", "file"),
|
|
37
|
+
[
|
|
38
|
+
("network_zzn_max.csv", "zzn"),
|
|
39
|
+
("network_zzx_max.csv", "zzx"),
|
|
40
|
+
],
|
|
41
|
+
)
|
|
42
|
+
def test_max(zzn: ZZN, zzx: ZZX, folder: Path, csv: str, file: str):
|
|
43
|
+
file_obj = zzn if file == "zzn" else zzx
|
|
44
|
+
expected = pd.read_csv(folder / csv, index_col=0)
|
|
45
|
+
|
|
46
|
+
actual = file_obj.to_dataframe(result_type="max")
|
|
47
|
+
pd.testing.assert_frame_equal(actual, expected, atol=1e-3, check_dtype=False)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@pytest.mark.parametrize(
|
|
51
|
+
("variable", "csv", "file"),
|
|
52
|
+
[
|
|
53
|
+
# zzn
|
|
54
|
+
("Flow", "network_zzn_flow.csv", "zzn"),
|
|
55
|
+
("Stage", "network_zzn_stage.csv", "zzn"),
|
|
56
|
+
("Froude", "network_zzn_fr.csv", "zzn"),
|
|
57
|
+
("Velocity", "network_zzn_velocity.csv", "zzn"),
|
|
58
|
+
("Mode", "network_zzn_mode.csv", "zzn"),
|
|
59
|
+
("State", "network_zzn_state.csv", "zzn"),
|
|
60
|
+
# zzx
|
|
61
|
+
("Left FP h", "network_zzx_left_fp_h.csv", "zzx"),
|
|
62
|
+
("Link inflow", "network_zzx_link_inflow.csv", "zzx"),
|
|
63
|
+
("Right FP h", "network_zzx_right_fp_h.csv", "zzx"),
|
|
64
|
+
("Right FP mode", "network_zzx_right_fp_mode.csv", "zzx"),
|
|
65
|
+
("Left FP mode", "network_zzx_left_fp_mode.csv", "zzx"),
|
|
66
|
+
],
|
|
67
|
+
)
|
|
68
|
+
def test_all_timesteps(zzn: ZZN, zzx: ZZX, folder: Path, variable: str, csv: str, file: str):
|
|
69
|
+
file_obj = zzn if file == "zzn" else zzx
|
|
70
|
+
suffix = f"_{variable}"
|
|
71
|
+
expected = pd.read_csv(folder / csv, index_col=0)
|
|
72
|
+
|
|
73
|
+
actual_1 = file_obj.to_dataframe(variable=variable)
|
|
74
|
+
actual_1.index = actual_1.index.round(3)
|
|
75
|
+
pd.testing.assert_frame_equal(actual_1, expected, atol=1e-3, check_dtype=False)
|
|
76
|
+
|
|
77
|
+
actual_2 = file_obj.to_dataframe()[variable]
|
|
78
|
+
actual_2.index = actual_2.index.round(3)
|
|
79
|
+
pd.testing.assert_frame_equal(actual_2, expected, atol=1e-3, check_dtype=False)
|
|
80
|
+
|
|
81
|
+
actual_3 = file_obj.to_dataframe(multilevel_header=False).filter(like=suffix, axis=1)
|
|
82
|
+
actual_3.index = actual_3.index.round(3)
|
|
83
|
+
actual_3.columns = [x.removesuffix(suffix) for x in actual_3.columns]
|
|
84
|
+
pd.testing.assert_frame_equal(actual_3, expected, atol=1e-3, check_dtype=False)
|
|
85
|
+
|
|
86
|
+
actual_4 = file_obj.to_dataframe(variable=variable, multilevel_header=False)
|
|
87
|
+
actual_4.index = actual_4.index.round(3)
|
|
88
|
+
actual_4.columns = [x.removesuffix(suffix) for x in actual_4.columns]
|
|
89
|
+
pd.testing.assert_frame_equal(actual_4, expected, atol=1e-3, check_dtype=False)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_zzn_include_time(zzn: ZZN):
|
|
93
|
+
zzn_df = zzn.to_dataframe(result_type="max", variable="flow", include_time=True)
|
|
94
|
+
actual = zzn_df.loc["resin", ["Max Flow", "Max Flow Time(hrs)"]].to_numpy()
|
|
95
|
+
assert actual[0] == pytest.approx(7.296, abs=0.001)
|
|
96
|
+
assert actual[1] == 9
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_zzn_from_ief(zzn: ZZN, ief: IEF):
|
|
100
|
+
zzn_df = zzn.to_dataframe()
|
|
101
|
+
zzn_from_ief = ief.get_results().to_dataframe()
|
|
102
|
+
pd.testing.assert_frame_equal(zzn_df, zzn_from_ief)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_zzn_to_csv(zzn: ZZN, tmp_path: Path, test_workspace: Path):
|
|
106
|
+
# default
|
|
107
|
+
zzn.export_to_csv()
|
|
108
|
+
path = test_workspace / "network.csv"
|
|
109
|
+
assert path.exists()
|
|
110
|
+
path.unlink()
|
|
111
|
+
|
|
112
|
+
# absolute
|
|
113
|
+
zzn.export_to_csv(tmp_path / "test.csv")
|
|
114
|
+
path = tmp_path / "test.csv"
|
|
115
|
+
assert path.exists()
|
|
116
|
+
path.unlink()
|
|
117
|
+
|
|
118
|
+
# relative
|
|
119
|
+
zzn.export_to_csv("test.csv")
|
|
120
|
+
path = zzn.filepath.parent / "test.csv"
|
|
121
|
+
assert path.exists()
|
|
122
|
+
path.unlink()
|
|
123
|
+
|
|
124
|
+
# folder
|
|
125
|
+
zzn.export_to_csv(tmp_path)
|
|
126
|
+
path = tmp_path / "network.csv"
|
|
127
|
+
assert path.exists()
|
|
128
|
+
path.unlink()
|
|
129
|
+
|
|
130
|
+
# doesn't exist
|
|
131
|
+
zzn.export_to_csv("test")
|
|
132
|
+
path = test_workspace / "test/network.csv"
|
|
133
|
+
assert path.exists()
|
|
134
|
+
path.unlink()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_meta_is_read_only(zzx: ZZN):
|
|
138
|
+
assert dict(zzx.meta) == zzx._meta
|
|
139
|
+
|
|
140
|
+
with pytest.raises(TypeError):
|
|
141
|
+
zzx.meta["variables"] = "hi"
|
|
142
|
+
|
|
143
|
+
zzx._meta["variables"] = "hi"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Flood Modeller Python API
|
|
3
|
-
Copyright (C)
|
|
3
|
+
Copyright (C) 2025 Jacobs U.K. Limited
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
|
6
6
|
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
@@ -162,15 +162,15 @@ def recursive_from_json(obj: dict | Any) -> Any:
|
|
|
162
162
|
return api_class_mapping[class_type].from_json(obj)
|
|
163
163
|
|
|
164
164
|
if "class" in obj and obj["class"] == "pandas.DataFrame":
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return
|
|
165
|
+
reconstructed_df = pd.DataFrame.from_dict(obj["object"])
|
|
166
|
+
reconstructed_df.index = convert_dataframe_index(reconstructed_df.index)
|
|
167
|
+
return reconstructed_df
|
|
168
168
|
if "class" in obj and obj["class"] == "pandas.Series":
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return
|
|
169
|
+
reconstructed_sr = pd.Series(obj["object"])
|
|
170
|
+
reconstructed_sr.index = convert_dataframe_index(reconstructed_sr.index)
|
|
171
|
+
reconstructed_sr.index.name = obj["index_name"]
|
|
172
|
+
reconstructed_sr.name = obj["variable_name"]
|
|
173
|
+
return reconstructed_sr
|
|
174
174
|
|
|
175
175
|
if "python_set" in obj:
|
|
176
176
|
return set(obj["python_set"])
|
floodmodeller_api/tool.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import logging
|
|
4
5
|
import sys
|
|
5
6
|
import tkinter as tk
|
|
6
7
|
from dataclasses import dataclass
|
|
8
|
+
from typing import ClassVar
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
@dataclass()
|
|
@@ -150,13 +152,11 @@ class Gui:
|
|
|
150
152
|
entry = tk.Entry(self.master, validate="key")
|
|
151
153
|
entry.config(validatecommand=(entry.register(validate_float), "%P"))
|
|
152
154
|
else:
|
|
153
|
-
|
|
155
|
+
msg = "Invalid data type"
|
|
156
|
+
raise ValueError(msg)
|
|
154
157
|
entry.pack()
|
|
155
158
|
self.root_entries[name] = entry
|
|
156
159
|
|
|
157
|
-
# TODO: Add a progress bar if appropriate
|
|
158
|
-
# TODO: Present some useful information: either tool outputs or logs
|
|
159
|
-
|
|
160
160
|
def run_gui_callback(self):
|
|
161
161
|
"""
|
|
162
162
|
Method to run the gui callback function.
|
|
@@ -209,28 +209,31 @@ class FMTool:
|
|
|
209
209
|
|
|
210
210
|
"""
|
|
211
211
|
|
|
212
|
-
parameters: list[Parameter] = []
|
|
212
|
+
parameters: ClassVar[list[Parameter]] = []
|
|
213
213
|
|
|
214
214
|
@property
|
|
215
215
|
def name(self):
|
|
216
216
|
"""
|
|
217
217
|
A property method to ensure a tool name is provided in child class. Overwritten by child.
|
|
218
218
|
"""
|
|
219
|
-
|
|
219
|
+
msg = "Tools need a name"
|
|
220
|
+
raise NotImplementedError(msg)
|
|
220
221
|
|
|
221
222
|
@property
|
|
222
223
|
def description(self):
|
|
223
224
|
"""
|
|
224
225
|
A property method to ensure a tool description is provided in child class. Overwritten by child.
|
|
225
226
|
"""
|
|
226
|
-
|
|
227
|
+
msg = "Tools need a description"
|
|
228
|
+
raise NotImplementedError(msg)
|
|
227
229
|
|
|
228
230
|
@property
|
|
229
231
|
def tool_function(self):
|
|
230
232
|
"""
|
|
231
233
|
A property method to ensure an tool_function is provided in child class. Overwritten by child.
|
|
232
234
|
"""
|
|
233
|
-
|
|
235
|
+
msg = "You must provide an entry point function"
|
|
236
|
+
raise NotImplementedError(msg)
|
|
234
237
|
|
|
235
238
|
def __init__(self):
|
|
236
239
|
self.check_parameters()
|
|
@@ -248,7 +251,8 @@ class FMTool:
|
|
|
248
251
|
params = []
|
|
249
252
|
for parameter in self.parameters:
|
|
250
253
|
if parameter.name in params:
|
|
251
|
-
|
|
254
|
+
msg = "Parameter names must be unique"
|
|
255
|
+
raise ValueError(msg)
|
|
252
256
|
params.append(parameter.name)
|
|
253
257
|
|
|
254
258
|
# This is defined as a class method because of the use of **kwargs
|
|
@@ -302,9 +306,9 @@ class FMTool:
|
|
|
302
306
|
value = getattr(args, input_param.name)
|
|
303
307
|
input_kwargs[input_param.name] = input_param.dtype(value)
|
|
304
308
|
|
|
305
|
-
|
|
309
|
+
logging.info("Running %s", self.name)
|
|
306
310
|
self.run(**input_kwargs)
|
|
307
|
-
|
|
311
|
+
logging.info("Completed")
|
|
308
312
|
# Return nothing
|
|
309
313
|
|
|
310
314
|
def generate_gui(self):
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
# Import the FMTool and Parameter classes to define the tool and parameters
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
2
6
|
from floodmodeller_api.tool import FMTool, Parameter
|
|
3
7
|
|
|
4
8
|
|
|
@@ -19,7 +23,7 @@ class SumTool(FMTool):
|
|
|
19
23
|
# Add the tool description (required)
|
|
20
24
|
description = "A basic tool to add two numbers together"
|
|
21
25
|
# Add the parameters (one per function argument):
|
|
22
|
-
parameters = [
|
|
26
|
+
parameters: ClassVar[list[Parameter]] = [
|
|
23
27
|
# Add parameters using the Parameter class
|
|
24
28
|
Parameter(
|
|
25
29
|
name="a",
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""This function allows you to raise the minimum bed level 300mm across all sections in a DAT file (i.e siltation)"""
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
5
6
|
|
|
6
7
|
from floodmodeller_api import DAT
|
|
7
8
|
from floodmodeller_api.tool import FMTool, Parameter
|
|
8
9
|
from floodmodeller_api.units import RIVER
|
|
9
10
|
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
# Define the function
|
|
12
16
|
def raise_section_bed_levels(dat_input: Path, dat_output: Path, siltation: float):
|
|
13
17
|
dat = DAT(dat_input) # Initialise DAT class
|
|
14
18
|
|
|
15
|
-
for
|
|
19
|
+
for section in dat.sections.values(): # iterate through all river sections
|
|
16
20
|
if not isinstance(section, RIVER):
|
|
17
21
|
# Skip any non river type units (e.g. interpolates)
|
|
18
22
|
continue
|
|
19
|
-
|
|
20
|
-
min_elevation =
|
|
23
|
+
section_data = section.data # get section data
|
|
24
|
+
min_elevation = section_data["Y"].min() # get minimum cross section elevation
|
|
21
25
|
raised_bed = min_elevation + siltation # define new lowest bed level
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
section_data.loc[
|
|
27
|
+
section_data["Y"] < raised_bed,
|
|
24
28
|
"Y",
|
|
25
29
|
] = raised_bed # Raise any levels lower than this to the new lowest level
|
|
26
30
|
|
|
@@ -70,7 +74,7 @@ class AddSiltation(FMTool):
|
|
|
70
74
|
description = (
|
|
71
75
|
"Tool to add a set amount of siltation to raise bed levels of river sections in a DAT file"
|
|
72
76
|
)
|
|
73
|
-
parameters = [
|
|
77
|
+
parameters: ClassVar[list[Parameter]] = [
|
|
74
78
|
Parameter(
|
|
75
79
|
name="dat_input",
|
|
76
80
|
dtype=str,
|