mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
506
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
012408d19e | ||
|
|
f7e563e71a | ||
|
|
81c6d39c1a | ||
|
|
d682443e1d | ||
|
|
c065b19ef8 | ||
|
|
b20a4c3c3d | ||
|
|
d66e75c183 | ||
|
|
31b4c47379 | ||
|
|
71bba499e0 | ||
|
|
7a08fa42d9 | ||
|
|
18a008462a | ||
|
|
d81da59398 | ||
|
|
3ab1eabe75 | ||
|
|
cf4f860db8 | ||
|
|
c68e3337ef | ||
|
|
db1ae613d6 | ||
|
|
a800816cda | ||
|
|
d4ef06c7c1 | ||
|
|
95d1d231c9 | ||
|
|
10b278e26f | ||
|
|
0550eef2eb | ||
|
|
73eb9919eb | ||
|
|
9116009b0b | ||
|
|
4e4ceb5074 | ||
|
|
d79e2ff187 | ||
|
|
d4a2594239 | ||
|
|
b666162bdf | ||
|
|
d705accaed | ||
|
|
d93917b081 | ||
|
|
ceff5f3083 | ||
|
|
97762756f8 | ||
|
|
2c49e991b4 | ||
|
|
c2a8f38ef5 | ||
|
|
f8a41fce08 | ||
|
|
624ae826eb | ||
|
|
d47dc0687e | ||
|
|
117e5222e4 | ||
|
|
b1c7a77f37 | ||
|
|
7b833390f1 | ||
|
|
ae08642116 | ||
|
|
c1905aa7e1 | ||
|
|
97ece018aa | ||
|
|
7f0102a881 | ||
|
|
786923bdbf | ||
|
|
deb9b2069f | ||
|
|
9308a73e8e | ||
|
|
869e116ad0 | ||
|
|
a2f3d22001 | ||
|
|
2e360943b2 | ||
|
|
8976f054c7 | ||
|
|
7bce725c63 | ||
|
|
5c83d67865 | ||
|
|
6e52b1681e | ||
|
|
f27b2cc586 | ||
|
|
1ed5d69bf4 | ||
|
|
5bb6cc40fe | ||
|
|
4c0a12dcf9 | ||
|
|
a308af41e0 | ||
|
|
02db91f3d7 | ||
|
|
4cf4015579 | ||
|
|
291b97ac9b | ||
|
|
b04e367e72 | ||
|
|
81d58122d6 | ||
|
|
874f592cf4 | ||
|
|
9b0bdd1e63 | ||
|
|
d934b5e381 | ||
|
|
14549330b9 | ||
|
|
2487bec6d6 | ||
|
|
4e1acfecdc | ||
|
|
c63c776989 | ||
|
|
44a8be6be3 | ||
|
|
a5a64f2080 | ||
|
|
16ee5a90e4 | ||
|
|
7ca6e69526 | ||
|
|
279fa0bf5e | ||
|
|
abe24611b3 | ||
|
|
17a18dde18 | ||
|
|
044818072e | ||
|
|
8bd791b2c4 | ||
|
|
c8d0d0c212 | ||
|
|
d31be61af8 | ||
|
|
a8a408b5d5 | ||
|
|
ff9d25412c | ||
|
|
de7f3e63b1 | ||
|
|
879c151524 | ||
|
|
7990a60d8b | ||
|
|
8aa0e25da2 | ||
|
|
1e6a578890 | ||
|
|
1dca9b98df | ||
|
|
de180b3635 | ||
|
|
5ca763ac8c | ||
|
|
188486f33a | ||
|
|
bc08d06bb1 | ||
|
|
05e039011a | ||
|
|
7640123299 | ||
|
|
e6dd983f97 | ||
|
|
002ebc5928 | ||
|
|
84486c03ed | ||
|
|
dc7dfb2414 | ||
|
|
ee01beb844 | ||
|
|
a31e2127e7 | ||
|
|
68b62a5630 | ||
|
|
990d44dd07 | ||
|
|
819ae41c00 | ||
|
|
bf95b7f7e6 | ||
|
|
861b78b928 | ||
|
|
a29df8f904 | ||
|
|
08c414a66e | ||
|
|
97ebf9324a | ||
|
|
0112ad63d9 | ||
|
|
bcbb440ad4 | ||
|
|
57a80d00aa | ||
|
|
70eae5f7d2 | ||
|
|
e2a65e2cdd | ||
|
|
f03b74614e | ||
|
|
532b3fd7fd | ||
|
|
64df4129d4 | ||
|
|
f6e35e2045 | ||
|
|
a97717a624 | ||
|
|
3f650de52f | ||
|
|
1f4bda7976 | ||
|
|
a4423e45f8 | ||
|
|
1386c592bf | ||
|
|
016f3fc73c | ||
|
|
7ef3184699 | ||
|
|
5f6c823301 | ||
|
|
a42c46f4d2 | ||
|
|
fb09cf254e | ||
|
|
315b913fd0 | ||
|
|
0383dc18ae | ||
|
|
f16856d23b | ||
|
|
e640fa1bc0 | ||
|
|
df3b3b604d | ||
|
|
21e6c410e2 | ||
|
|
19045329dc | ||
|
|
4586ef79f7 | ||
|
|
bc4557e21f | ||
|
|
f97d4ce3c5 | ||
|
|
f6e08f203c | ||
|
|
5dcbc6b4e1 | ||
|
|
ebe906fce0 | ||
|
|
cd4f626218 | ||
|
|
c1eb2cf447 | ||
|
|
5fec95cc4d | ||
|
|
46b943c800 | ||
|
|
fa8fe508a7 | ||
|
|
911a2bbbff | ||
|
|
2a926a8d73 | ||
|
|
d222842313 | ||
|
|
2942b6e442 | ||
|
|
926cade437 | ||
|
|
13b4413b36 | ||
|
|
706a900c8e | ||
|
|
da03f39425 | ||
|
|
f516db0e48 | ||
|
|
8744e1d73e | ||
|
|
6113d9f4cd | ||
|
|
1dd92cb089 | ||
|
|
8f6255c2cd | ||
|
|
6c4f6e269c | ||
|
|
82b0837d8c | ||
|
|
137489cc1f | ||
|
|
4dc4dfdda0 | ||
|
|
7d42c164fc | ||
|
|
ae15311471 | ||
|
|
dbcdace348 | ||
|
|
9375827949 | ||
|
|
739f401fac | ||
|
|
5f5a47679d | ||
|
|
26d1d63edb | ||
|
|
1b2f98494b | ||
|
|
381bc37d13 | ||
|
|
e7b63fe270 | ||
|
|
80ae4c36ad | ||
|
|
936bfc753a | ||
|
|
f0ccf1f4f7 | ||
|
|
3a3c4d9d73 | ||
|
|
41cffd13e0 | ||
|
|
9270dd0ff1 | ||
|
|
ba8a50e0b9 | ||
|
|
9c69f2ce6d | ||
|
|
e7a27c798a | ||
|
|
ddc612328e | ||
|
|
d05d1e6914 | ||
|
|
8bcf776813 | ||
|
|
589e591d3b | ||
|
|
e2e8c5ec9e | ||
|
|
fce034419d | ||
|
|
d9aea9eb3c | ||
|
|
4cddd43f5a | ||
|
|
becc1696cb | ||
|
|
cf4957551f | ||
|
|
794b06d55a | ||
|
|
f51f742e00 | ||
|
|
31fe765e51 | ||
|
|
40cc188815 | ||
|
|
303f6bb35b | ||
|
|
9043b6e2a3 | ||
|
|
0608b9175e | ||
|
|
ea7fda6b28 | ||
|
|
090326b75c | ||
|
|
b582e133a1 | ||
|
|
78e6f7e5a7 | ||
|
|
8173eb8de9 | ||
|
|
591cd8950c | ||
|
|
7c4c772f43 | ||
|
|
3a78d6d6f7 | ||
|
|
bbf85a6048 | ||
|
|
6dfa876809 | ||
|
|
aff86a2ffa | ||
|
|
1eb925f3dd | ||
|
|
701d76240e | ||
|
|
37ea9e9083 | ||
|
|
6457b3ad25 | ||
|
|
cba5b948de | ||
|
|
4ba232a7e4 | ||
|
|
05f3f0fc7e | ||
|
|
89a5d78ced | ||
|
|
5fc4e3903a | ||
|
|
1b70e22a58 | ||
|
|
22aeda105e | ||
|
|
7181122a3a | ||
|
|
76ce34c4ea | ||
|
|
c58620fdc2 | ||
|
|
a6341dedd2 | ||
|
|
ba7171326c | ||
|
|
78b4269a69 | ||
|
|
a30bf8e364 | ||
|
|
bd1edbaf30 | ||
|
|
bdf9264963 | ||
|
|
befe1a550d | ||
|
|
f4d3f2b28f | ||
|
|
2a1c8c1e57 | ||
|
|
a3da09cf5b | ||
|
|
017f26c03d | ||
|
|
1e2a123693 | ||
|
|
2916afb974 | ||
|
|
37963b7b21 | ||
|
|
e5b4c998cb | ||
|
|
4bf0ad40b1 | ||
|
|
420d766ae5 | ||
|
|
645a76b0e8 | ||
|
|
6288f039d2 | ||
|
|
3585b29b03 | ||
|
|
96bac8ee1f | ||
|
|
e7d14e7aa3 | ||
|
|
6b14ed7efe | ||
|
|
3d40f599d6 | ||
|
|
6ec677a047 | ||
|
|
7bb0c9d57e | ||
|
|
ec2a1da6b6 | ||
|
|
a072a28929 | ||
|
|
fc7d732e0a | ||
|
|
cc5d86328b | ||
|
|
e3cbe3cf1f | ||
|
|
9482aaf523 | ||
|
|
e0cee0fbef | ||
|
|
f9a8512477 | ||
|
|
1457db721b | ||
|
|
7774d2d7af | ||
|
|
e6d3564d9b | ||
|
|
d62e703439 | ||
|
|
0346080e16 | ||
|
|
76559f6af8 | ||
|
|
04ce79462c | ||
|
|
ffa065a3e6 | ||
|
|
0e1e3665a6 | ||
|
|
c64bcd1ff7 | ||
|
|
dd84b83302 | ||
|
|
084223037c | ||
|
|
072840a18c | ||
|
|
3ef13666dc | ||
|
|
e344678ac5 | ||
|
|
1f79e6510d | ||
|
|
b94c37dd3b | ||
|
|
b61c4da8f1 | ||
|
|
ba60585550 | ||
|
|
0ed7660e72 | ||
|
|
8b4ff41b96 | ||
|
|
8769fa260d | ||
|
|
2667737490 | ||
|
|
7cb3982a1f | ||
|
|
2336dd22f3 | ||
|
|
f13ab03192 | ||
|
|
0df813b0d2 | ||
|
|
2faebfd402 | ||
|
|
7094ff3e62 | ||
|
|
c6ab2647c1 | ||
|
|
b62d1429c0 | ||
|
|
23a0bc33fa | ||
|
|
93340a48b1 | ||
|
|
0379a8ee02 | ||
|
|
6cce02650b | ||
|
|
6e79fe4cd5 | ||
|
|
f66d8c7a34 | ||
|
|
826e532605 | ||
|
|
fc35f2fbcc | ||
|
|
216239bfce | ||
|
|
739eb56006 | ||
|
|
468405d4ea | ||
|
|
31af83ba02 | ||
|
|
45fddb9459 | ||
|
|
05dcd3bcca | ||
|
|
89a898410f | ||
|
|
4a0456cbce | ||
|
|
a525d8a2b0 | ||
|
|
d7fcf62e12 | ||
|
|
4ac86b9acb | ||
|
|
00c9ecde52 | ||
|
|
ae49908a42 | ||
|
|
37cf42c524 | ||
|
|
c43a26870e | ||
|
|
5a6574921a | ||
|
|
7fa86c29e7 | ||
|
|
a3f20796d7 | ||
|
|
835d73789e | ||
|
|
f0ac170d2f | ||
|
|
b154e3d03b | ||
|
|
633e5a53dc | ||
|
|
3f98cf8625 | ||
|
|
36fe9a51c4 | ||
|
|
74ab3aa522 | ||
|
|
cfdf175f9d | ||
|
|
c07a863018 | ||
|
|
243941db51 | ||
|
|
d6c1316178 | ||
|
|
f35048b89f | ||
|
|
24d92b2ac0 | ||
|
|
c702862bc4 | ||
|
|
400f6be9e3 | ||
|
|
5fc6951060 | ||
|
|
5ba38d5cd6 | ||
|
|
3e8132646d | ||
|
|
5aef0bbf3c | ||
|
|
bb3dadc0c7 | ||
|
|
7bb176e7c7 | ||
|
|
8c16e4ed58 | ||
|
|
e9315d9be7 | ||
|
|
46738cec6b | ||
|
|
e576bb15f1 | ||
|
|
26d18d26e9 | ||
|
|
8bac416ab5 | ||
|
|
e6aa840633 | ||
|
|
4b976d3b5f | ||
|
|
e3315c8f81 | ||
|
|
6bcbd006f1 | ||
|
|
c60a0938eb | ||
|
|
4d026afb2c | ||
|
|
4e888d9db0 | ||
|
|
440996b636 | ||
|
|
ed1a1a71ac | ||
|
|
cbe3ad0084 | ||
|
|
46935fde45 | ||
|
|
ca8dc19c83 | ||
|
|
e4a31b3497 | ||
|
|
406dc2bdd4 | ||
|
|
c325f61fce | ||
|
|
d3729cfe77 | ||
|
|
fa8f07b97e | ||
|
|
52c153fa84 | ||
|
|
21bd87f74b | ||
|
|
4d08f3c271 | ||
|
|
e44bbd5a3c | ||
|
|
f827f6bf13 | ||
|
|
4be68ba98d | ||
|
|
e47edea63b | ||
|
|
8daf89d1c4 | ||
|
|
0fa3ca5fad | ||
|
|
e3229c8183 | ||
|
|
c8606cf445 | ||
|
|
09029dc993 | ||
|
|
0a97070b90 | ||
|
|
4f57179a2e | ||
|
|
d0d7d91ab7 | ||
|
|
8497d151ab | ||
|
|
8a98f2bbca | ||
|
|
181aea2805 | ||
|
|
6a762275b6 | ||
|
|
a64430691c | ||
|
|
3cd6d31731 | ||
|
|
af30fde81a | ||
|
|
589b8dcd23 | ||
|
|
4e87135bf4 | ||
|
|
f636236935 | ||
|
|
c3d732b426 | ||
|
|
8913a774ea | ||
|
|
36c3785cde | ||
|
|
5ed905df71 | ||
|
|
ea4fa81cc4 | ||
|
|
8862be991e | ||
|
|
8aea55909e | ||
|
|
1289967abb | ||
|
|
41d1fb9d59 | ||
|
|
8d9a196059 | ||
|
|
558085705f | ||
|
|
1b8f9b2abc | ||
|
|
f3ad4414b6 | ||
|
|
8930c39fbe | ||
|
|
7c2908569e | ||
|
|
5598464081 | ||
|
|
40d90424a3 | ||
|
|
bb33e8077a | ||
|
|
2859d0f4ff | ||
|
|
cab1bceae8 | ||
|
|
48c389a27c | ||
|
|
4199eb6ac5 | ||
|
|
02c6430ed2 | ||
|
|
05ee0e86b1 | ||
|
|
1ed6274f8b | ||
|
|
7857a2ea61 | ||
|
|
c01effbf4c | ||
|
|
a2ff3ecd9a | ||
|
|
a5ecc2383c | ||
|
|
e73f76024e | ||
|
|
cd7a81d828 | ||
|
|
81264fa63e | ||
|
|
5e3dbc18c3 | ||
|
|
e43c20c1e6 | ||
|
|
f65039d748 | ||
|
|
d0e70ddddc | ||
|
|
3de96a8d9d | ||
|
|
b3fd673f33 | ||
|
|
fb12f498a7 | ||
|
|
fd54116d55 | ||
|
|
83ecdc9a88 | ||
|
|
be1e868fc4 | ||
|
|
a1e6e646f9 | ||
|
|
29df56c8b4 | ||
|
|
064b3efa13 | ||
|
|
5cc5628956 | ||
|
|
8afa3d1e30 | ||
|
|
8f0535dc5c | ||
|
|
a412f2f18f | ||
|
|
8f4d233965 | ||
|
|
cc84b96024 | ||
|
|
4ff81a0b63 | ||
|
|
9b40b7eb39 | ||
|
|
5c3464a303 | ||
|
|
71bea2eea4 | ||
|
|
ed0a549027 | ||
|
|
267f30849f | ||
|
|
b8ed3d8954 | ||
|
|
b634acec67 | ||
|
|
3035ea8d8b | ||
|
|
abe7046d4f | ||
|
|
b60b922fef | ||
|
|
85d3345043 | ||
|
|
60ee889794 | ||
|
|
9ec21d815d | ||
|
|
ac32995e01 | ||
|
|
8c99268bb8 | ||
|
|
237b2670f6 | ||
|
|
d50f617a85 | ||
|
|
1cfc7e6638 | ||
|
|
8b9bb68ac5 | ||
|
|
71b631fbe4 | ||
|
|
7274ff5e2d | ||
|
|
770ecdfa99 | ||
|
|
4023ae73ba | ||
|
|
7f87d22249 | ||
|
|
6225f8940e | ||
|
|
6a5183cc0c | ||
|
|
037f5ecfa5 | ||
|
|
63657151ea | ||
|
|
c4e1a4c485 | ||
|
|
4222503961 | ||
|
|
af779a1880 | ||
|
|
84a5bed66d | ||
|
|
fa9ffccb19 | ||
|
|
4a333ff988 | ||
|
|
ce8c4ebd91 | ||
|
|
bc157fcde7 | ||
|
|
9a0476aa46 | ||
|
|
c7b5b40eda | ||
|
|
74c61262b7 | ||
|
|
2290e2eb6d | ||
|
|
0d33072a7e | ||
|
|
19d9a29459 | ||
|
|
d2e5eecf22 | ||
|
|
b9ca6bf4a9 | ||
|
|
aa68acea3d | ||
|
|
bf7b18f158 | ||
|
|
3675dc5b9d | ||
|
|
1dfdcb0413 | ||
|
|
32cda58064 | ||
|
|
4081f96d68 | ||
|
|
16350b4dec | ||
|
|
d8fe1d8b81 | ||
|
|
5525fff1fe | ||
|
|
328f5656bf | ||
|
|
9ec080a107 | ||
|
|
1bae755f1c | ||
|
|
9deccb465e | ||
|
|
2ff635d0cd | ||
|
|
9f4b297d23 | ||
|
|
aea308a5a2 | ||
|
|
5c4948bd6d | ||
|
|
d78d9167a0 | ||
|
|
9c9fcc3dd8 | ||
|
|
4271fbb85f | ||
|
|
ba4603e850 | ||
|
|
f2bc31c97b | ||
|
|
62a1726ef1 | ||
|
|
f19941f6da | ||
|
|
3917b84b56 | ||
|
|
3ecf97ac82 |
No files matched your search
+9
-3
@@ -41,8 +41,14 @@ __old__
|
|||||||
|
|
||||||
*-venv
|
*-venv
|
||||||
|
|
||||||
mage8
|
mage8/
|
||||||
adists
|
adists/
|
||||||
|
rubarbe/
|
||||||
|
|
||||||
|
linux/
|
||||||
|
windows/
|
||||||
|
|
||||||
|
install/
|
||||||
|
|
||||||
### END CUSTOM ###
|
### END CUSTOM ###
|
||||||
|
|
||||||
@@ -624,7 +630,7 @@ TSWLatexianTemp*
|
|||||||
|
|
||||||
# auto folder when using emacs and auctex
|
# auto folder when using emacs and auctex
|
||||||
./auto/*
|
./auto/*
|
||||||
*.el
|
# *.el
|
||||||
|
|
||||||
# expex forward references with \gathertags
|
# expex forward references with \gathertags
|
||||||
*-tags.tex
|
*-tags.tex
|
||||||
|
|||||||
+91
-19
@@ -1,5 +1,5 @@
|
|||||||
# .gitlab-ci.yml -- Pamhyr gitlab-ci
|
# .gitlab-ci.yml -- Pamhyr gitlab-ci
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,12 +24,21 @@ stages:
|
|||||||
- antivirus
|
- antivirus
|
||||||
- release
|
- release
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# PYINSTALLER VARIABLES #
|
||||||
|
#########################
|
||||||
|
|
||||||
|
variables:
|
||||||
|
HIDDEN_IMPORTS: "--hiddenimport rasterio --collect-submodules rasterio"
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# DOWNLOADS #
|
# DOWNLOADS #
|
||||||
#############
|
#############
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
MAGE_8_VERSION: "v8.3.6"
|
MAGE_8_VERSION: "permalink/latest"
|
||||||
|
ADISTS_VERSION: "permalink/latest"
|
||||||
|
RUBAR_VERSION: "permalink/latest"
|
||||||
|
|
||||||
dl-mage8-doc:
|
dl-mage8-doc:
|
||||||
stage: downloads
|
stage: downloads
|
||||||
@@ -40,7 +49,7 @@ dl-mage8-doc:
|
|||||||
script:
|
script:
|
||||||
- mkdir -p doc
|
- mkdir -p doc
|
||||||
- cd doc
|
- cd doc
|
||||||
- curl -L -o mage8.pdf https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/documents/Mage-8_Documentation.pdf
|
- curl -L -o mage8.pdf https://forge.inrae.fr/river-hydraulics/mage/-/releases/$MAGE_8_VERSION/downloads/documents/Mage-8_Documentation.pdf
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- doc/mage8.pdf
|
- doc/mage8.pdf
|
||||||
@@ -52,17 +61,13 @@ dl-mage8-linux:
|
|||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
script:
|
script:
|
||||||
- curl -L -o mage8.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_linux.tgz
|
- curl -L -o mage8.tgz https://forge.inrae.fr/river-hydraulics/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_linux.tgz
|
||||||
- mkdir -p mage8-linux
|
- mkdir -p mage8-linux
|
||||||
- cd mage8-linux
|
- cd mage8-linux
|
||||||
- tar xvf ../mage8.tgz
|
- tar xvf ../mage8.tgz
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- mage8-linux/mage
|
- mage8-linux/mage
|
||||||
- mage8-linux/mage_as7
|
|
||||||
- mage8-linux/mage_extraire
|
|
||||||
- mage8-linux/mailleurTT
|
|
||||||
- mage8-linux/libbief.so
|
|
||||||
|
|
||||||
dl-mage8-windows:
|
dl-mage8-windows:
|
||||||
stage: downloads
|
stage: downloads
|
||||||
@@ -71,17 +76,13 @@ dl-mage8-windows:
|
|||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
script:
|
script:
|
||||||
- curl -L -o mage8.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_windows.tgz
|
- curl -L -o mage8.tgz https://forge.inrae.fr/river-hydraulics/mage/-/releases/$MAGE_8_VERSION/downloads/packages/mage_windows.tgz
|
||||||
- mkdir -p mage8-windows
|
- mkdir -p mage8-windows
|
||||||
- cd mage8-windows
|
- cd mage8-windows
|
||||||
- tar xvf ../mage8.tgz
|
- tar xvf ../mage8.tgz
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- mage8-windows/mage.exe
|
- mage8-windows/mage.exe
|
||||||
- mage8-windows/mage_as7.exe
|
|
||||||
- mage8-windows/mage_extraire.exe
|
|
||||||
- mage8-windows/mailleurTT.exe
|
|
||||||
- mage8-windows/libbief.dll
|
|
||||||
|
|
||||||
dl-adists-linux:
|
dl-adists-linux:
|
||||||
stage: downloads
|
stage: downloads
|
||||||
@@ -92,7 +93,7 @@ dl-adists-linux:
|
|||||||
script:
|
script:
|
||||||
- mkdir -p adists-linux
|
- mkdir -p adists-linux
|
||||||
- cd adists-linux
|
- cd adists-linux
|
||||||
- curl -L -o adists https://gitlab.irstea.fr/jean-baptiste.faure/adists/-/releases/v1.0.1/downloads/executables/adists
|
- curl -L -o adists https://forge.inrae.fr/river-hydraulics/adists/-/releases/$ADISTS_VERSION/downloads/executables/adists
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- adists-linux/adists
|
- adists-linux/adists
|
||||||
@@ -106,11 +107,41 @@ dl-adists-windows:
|
|||||||
script:
|
script:
|
||||||
- mkdir -p adists-windows
|
- mkdir -p adists-windows
|
||||||
- cd adists-windows
|
- cd adists-windows
|
||||||
- curl -L -o adists.exe https://gitlab.irstea.fr/jean-baptiste.faure/adists/-/releases/v1.0.1/downloads/executables/adists_win64.exe
|
- curl -L -o adists.exe https://forge.inrae.fr/river-hydraulics/adists/-/releases/$ADISTS_VERSION/downloads/executables/adists_win64.exe
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- adists-windows/adists.exe
|
- adists-windows/adists.exe
|
||||||
|
|
||||||
|
dl-rubar-linux:
|
||||||
|
stage: downloads
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
script:
|
||||||
|
- mkdir -p rubar-linux
|
||||||
|
- cd rubar-linux
|
||||||
|
- curl -L -o rubar.tgz https://forge.inrae.fr/river-hydraulics/rubarbe/-/releases/$RUBAR_VERSION/downloads/packages/rubar_linux.tgz
|
||||||
|
- tar xf rubar.tgz
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- rubar-linux/rubarbe
|
||||||
|
|
||||||
|
dl-rubar-windows:
|
||||||
|
stage: downloads
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
script:
|
||||||
|
- mkdir -p rubar-windows
|
||||||
|
- cd rubar-windows
|
||||||
|
- curl -L -o rubar.tgz https://forge.inrae.fr/river-hydraulics/rubarbe/-/releases/$RUBAR_VERSION/downloads/packages/rubar_windows.tgz
|
||||||
|
- tar xf rubar.tgz
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- rubar-windows/rubarbe.exe
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# CONFIGURE #
|
# CONFIGURE #
|
||||||
#############
|
#############
|
||||||
@@ -273,6 +304,8 @@ build-linux:
|
|||||||
needs:
|
needs:
|
||||||
- job: dl-adists-linux
|
- job: dl-adists-linux
|
||||||
artifacts: true
|
artifacts: true
|
||||||
|
- job: dl-rubar-linux
|
||||||
|
artifacts: true
|
||||||
- job: dl-mage8-linux
|
- job: dl-mage8-linux
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: dl-mage8-doc
|
- job: dl-mage8-doc
|
||||||
@@ -299,7 +332,7 @@ build-linux:
|
|||||||
- pip3 install -r ../requirements.txt
|
- pip3 install -r ../requirements.txt
|
||||||
- pip3 install -U -r ../requirements.txt
|
- pip3 install -U -r ../requirements.txt
|
||||||
# Run Pyinstaller
|
# Run Pyinstaller
|
||||||
- pyinstaller -y --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
|
- pyinstaller -y $HIDDEN_IMPORTS --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
|
||||||
# Create directory
|
# Create directory
|
||||||
- mkdir -p pamhyr
|
- mkdir -p pamhyr
|
||||||
- mkdir -p pamhyr/_internal
|
- mkdir -p pamhyr/_internal
|
||||||
@@ -314,6 +347,9 @@ build-linux:
|
|||||||
# Copy adists
|
# Copy adists
|
||||||
- mkdir -p pamhyr/adists
|
- mkdir -p pamhyr/adists
|
||||||
- cp -v ../adists-linux/* pamhyr/adists/
|
- cp -v ../adists-linux/* pamhyr/adists/
|
||||||
|
# Copy rubar
|
||||||
|
- mkdir -p pamhyr/rubar
|
||||||
|
- cp -v ../rubar-linux/* pamhyr/rubar/
|
||||||
# Copy Pamhyr
|
# Copy Pamhyr
|
||||||
- cp -r dist/pamhyr/* pamhyr/
|
- cp -r dist/pamhyr/* pamhyr/
|
||||||
# Pamhyr script to force x11
|
# Pamhyr script to force x11
|
||||||
@@ -363,7 +399,7 @@ build-linux:
|
|||||||
- cp ../doc/users/TP_AdisTS_Vieux_Rhone/Vieux_Rhone_TP_AdisTS.pamhyr pamhyr/doc/TP_AdisTS_Vieux_Rhone/Vieux_Rhone_TP_AdisTS.pamhyr
|
- cp ../doc/users/TP_AdisTS_Vieux_Rhone/Vieux_Rhone_TP_AdisTS.pamhyr pamhyr/doc/TP_AdisTS_Vieux_Rhone/Vieux_Rhone_TP_AdisTS.pamhyr
|
||||||
# Copy TP charriage
|
# Copy TP charriage
|
||||||
- mkdir -p pamhyr/doc/TP_charriage/
|
- mkdir -p pamhyr/doc/TP_charriage/
|
||||||
- cp ../doc/users/TP_charriage/* pamhyr/doc/TP_charriage
|
- cp -r ../doc/users/TP_charriage/* pamhyr/doc/TP_charriage
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- linux/pamhyr
|
- linux/pamhyr
|
||||||
@@ -379,6 +415,8 @@ build-windows:
|
|||||||
artifacts: true
|
artifacts: true
|
||||||
- job: dl-adists-windows
|
- job: dl-adists-windows
|
||||||
artifacts: true
|
artifacts: true
|
||||||
|
- job: dl-rubar-windows
|
||||||
|
artifacts: true
|
||||||
- job: dl-mage8-doc
|
- job: dl-mage8-doc
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: set-version
|
- job: set-version
|
||||||
@@ -402,7 +440,7 @@ build-windows:
|
|||||||
- python -m pip install -U -r ..\requirements.txt
|
- python -m pip install -U -r ..\requirements.txt
|
||||||
# Run Pyinstaller
|
# Run Pyinstaller
|
||||||
# - pyinstaller --noconsole -y ..\src\pamhyr.py
|
# - pyinstaller --noconsole -y ..\src\pamhyr.py
|
||||||
- pyinstaller -i ../src/View/ui/ressources/icon.ico --hide-console hide-early -y ..\src\pamhyr.py
|
- pyinstaller -i ../src/View/ui/ressources/icon.ico $HIDDEN_IMPORTS --hide-console hide-early -y ..\src\pamhyr.py
|
||||||
# Create directory
|
# Create directory
|
||||||
- mkdir pamhyr
|
- mkdir pamhyr
|
||||||
- dir
|
- dir
|
||||||
@@ -581,6 +619,40 @@ pkg-check-clamav:
|
|||||||
# RELEASE #
|
# RELEASE #
|
||||||
###########
|
###########
|
||||||
|
|
||||||
|
shadow-release:
|
||||||
|
stage: release
|
||||||
|
tags:
|
||||||
|
- release
|
||||||
|
- linux
|
||||||
|
needs:
|
||||||
|
- job: linux-package-tar
|
||||||
|
artifacts: true
|
||||||
|
- job: windows-package-zip
|
||||||
|
artifacts: true
|
||||||
|
- job: windows-package-exe
|
||||||
|
artifacts: true
|
||||||
|
# - job: build-users-doc
|
||||||
|
# artifacts: true
|
||||||
|
- job: build-developers-doc
|
||||||
|
artifacts: true
|
||||||
|
- job: pkg-hash
|
||||||
|
artifacts: true
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH != 'master' && $CI_COMMIT_TAG
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- linux/pamhyr-gnulinux.tar.xz
|
||||||
|
- windows/pamhyr-windows.zip
|
||||||
|
- windows/pamhyr-windows.exe
|
||||||
|
- linux/pamhyr-gnulinux.tar.xz.sha256
|
||||||
|
- windows/pamhyr-windows.zip.sha256
|
||||||
|
- windows/pamhyr-windows.exe.sha256
|
||||||
|
- doc/dev/documentation.pdf
|
||||||
|
# - doc/users/documentation.pdf
|
||||||
|
script:
|
||||||
|
- cd packages
|
||||||
|
|
||||||
|
|
||||||
tag-release:
|
tag-release:
|
||||||
stage: release
|
stage: release
|
||||||
tags:
|
tags:
|
||||||
@@ -600,7 +672,7 @@ tag-release:
|
|||||||
- job: pkg-hash
|
- job: pkg-hash
|
||||||
artifacts: true
|
artifacts: true
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'master' && $CI_COMMIT_TAG
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- linux/pamhyr-gnulinux.tar.xz
|
- linux/pamhyr-gnulinux.tar.xz
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
Sylvain COULIBALY, INRAE, 2020 - 2022
|
Sylvain COULIBALY, INRAE, 2020 - 2022
|
||||||
Théophile TERRAZ, INRAE, 2022 - 2024
|
Théophile TERRAZ, INRAE, 2022 - 2024
|
||||||
Pierre-Antoine ROUBY, INRAE, 2023 - 2024
|
Pierre-Antoine ROUBY, INRAE, 2023 - 2025
|
||||||
@@ -18,6 +18,7 @@ modelling of rivers.
|
|||||||
+ Define river sedimentary layers
|
+ Define river sedimentary layers
|
||||||
+ Save the study in a unique file
|
+ Save the study in a unique file
|
||||||
+ Run Mage 8 on a study and visualize results
|
+ Run Mage 8 on a study and visualize results
|
||||||
|
+ Create and edit study alternative scenario tree
|
||||||
|
|
||||||
Let see the
|
Let see the
|
||||||
[documentation](https://gitlab.irstea.fr/theophile.terraz/pamhyr/-/wikis/home)
|
[documentation](https://gitlab.irstea.fr/theophile.terraz/pamhyr/-/wikis/home)
|
||||||
|
|||||||
+20
-15
@@ -1,18 +1,23 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
|
||||||
echo " PDF documentation.org"
|
FILES="documentation.org scenario.org"
|
||||||
emacs -nw --batch \
|
|
||||||
--eval "(require 'org)" \
|
|
||||||
--eval "(require 'ox-latex)" \
|
|
||||||
--eval "(load-file \"../tools/setup.el\")" \
|
|
||||||
--file ./documentation.org \
|
|
||||||
-f org-latex-export-to-pdf
|
|
||||||
|
|
||||||
echo " HTML documentation.org"
|
for file in $FILES
|
||||||
emacs -nw --batch \
|
do
|
||||||
--eval "(require 'org)" \
|
echo " PDF $file"
|
||||||
--eval "(require 'ox-latex)" \
|
emacs -nw --batch \
|
||||||
--eval "(require 'ox-html)" \
|
--eval "(require 'org)" \
|
||||||
--eval "(load-file \"../tools/setup.el\")" \
|
--eval "(require 'ox-latex)" \
|
||||||
--file ./documentation.org \
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
-f org-html-export-to-html
|
--file ./$file \
|
||||||
|
-f org-latex-export-to-pdf \
|
||||||
|
|
||||||
|
echo " HTML $file"
|
||||||
|
emacs -nw --batch \
|
||||||
|
--eval "(require 'org)" \
|
||||||
|
--eval "(require 'ox-latex)" \
|
||||||
|
--eval "(require 'ox-html)" \
|
||||||
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
|
--file ./$file \
|
||||||
|
-f org-html-export-to-html
|
||||||
|
done
|
||||||
@@ -1375,7 +1375,7 @@ contribution.
|
|||||||
#+INCLUDE: "../../AUTHORS" src text
|
#+INCLUDE: "../../AUTHORS" src text
|
||||||
|
|
||||||
[fn:p2-gitlab] The {{{pamhyr2}}} Gitlab project page:
|
[fn:p2-gitlab] The {{{pamhyr2}}} Gitlab project page:
|
||||||
https://gitlab.irstea.fr/theophile.terraz/pamhyr
|
https://gitlab.com/pamhyr/pamhyr2
|
||||||
[fn:inrae] The INRAE web site: https://www.inrae.fr/
|
[fn:inrae] The INRAE web site: https://www.inrae.fr/
|
||||||
|
|
||||||
** Translate
|
** Translate
|
||||||
|
|||||||
@@ -0,0 +1,661 @@
|
|||||||
|
# senario.org -- Pamhyr developers documentation
|
||||||
|
# Copyright (C) 2023-2024 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#+STARTUP: indent show2levels
|
||||||
|
|
||||||
|
#+INCLUDE: ../tools/macro.org
|
||||||
|
#+INCLUDE: ../tools/latex.org
|
||||||
|
|
||||||
|
#+TITLE: Scenario implementation in Pamhyr2: \textbf{Preparatory work}
|
||||||
|
#+SUBTITLE: Version: {{{version}}}
|
||||||
|
#+AUTHOR: {{{INRAE}}}
|
||||||
|
|
||||||
|
#+OPTIONS: toc:t
|
||||||
|
#+LANGUAGE: UKenglish
|
||||||
|
|
||||||
|
#+latex: \newpage
|
||||||
|
|
||||||
|
* COMMENT tools
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp :export none
|
||||||
|
(add-to-list 'org-structure-template-alist
|
||||||
|
'("p" "#+begin_src python :python python3 :results output\n\n#+end_src"))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
#+begin_example
|
||||||
|
((p #+begin_src python :python python3 :results output
|
||||||
|
|
||||||
|
,#+end_src) (d . #+name: graph-XXX
|
||||||
|
,#+header: :results drawer
|
||||||
|
,#+header: :exports results
|
||||||
|
,#+header: :post attr_wrap(width="12cm", data=*this*, name="graph-XXX", caption="Graph XXX", float="t")
|
||||||
|
,#+begin_src dot :file "images/graph-XXX.png" :cache no
|
||||||
|
digraph {
|
||||||
|
bgcolor="transparent";
|
||||||
|
node[colorscheme=set19,shape=box,style="filled",fillcolor=9];
|
||||||
|
}
|
||||||
|
,#+end_src) (p . src python :python python3 :results output :noweb yes
|
||||||
|
|
||||||
|
src) (t . EXPORT latex
|
||||||
|
\begin{table}
|
||||||
|
\centering
|
||||||
|
\resizebox{0.6\linewidth}{!}{
|
||||||
|
|
||||||
|
}
|
||||||
|
%\vspace{0.5pt}
|
||||||
|
%\caption{Number of tests by errors types}
|
||||||
|
\end{table}
|
||||||
|
,#+E) (B . src shell :session *shell* :results output :exports both) (a . export ascii) (c . center) (C . comment) (e . example) (E . export) (h . export html) (l . export latex) (q . quote) (s . src) (v . verse))
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
#+name: dbg-execute
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def execute(db, query):
|
||||||
|
print(query)
|
||||||
|
return db.execute(query)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS: dbg-execute
|
||||||
|
|
||||||
|
#+name: execute
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def execute(db, query):
|
||||||
|
return db.execute(query)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS: execute
|
||||||
|
|
||||||
|
* Principe
|
||||||
|
|
||||||
|
** Scenario
|
||||||
|
|
||||||
|
A scenario is defined by a name, a description and a parent
|
||||||
|
scenario. If a scenario as no parent, parent value is =None=. So, in
|
||||||
|
Pamhyr2 the list of scenario must by a tree with a root defined by a
|
||||||
|
default scenarios with no parent.
|
||||||
|
|
||||||
|
#+begin_src sql
|
||||||
|
CREATE TABLE scenario(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL, -- Name of the scenario
|
||||||
|
description TEXT NOT NULL, -- Rich text description
|
||||||
|
parent_id INTEGER REFERENCES scenario(id) -- Recursive references
|
||||||
|
-- for parent scenario
|
||||||
|
)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Data
|
||||||
|
|
||||||
|
Each data is associated with one and only one scenario. This senario
|
||||||
|
is defined by the =id=. So, each data structure who can saved in DB
|
||||||
|
must add the following lines in table définition:
|
||||||
|
|
||||||
|
#+begin_src sql
|
||||||
|
scenario_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
To avoid, at least, memory usage exploitation, by default, a scenario
|
||||||
|
must saved only the modified data from its parent. This contrains
|
||||||
|
require to wrap any data modification to update the data scenario id
|
||||||
|
to current scenario id in source code. In addition, we need to modify
|
||||||
|
the data loading méthode to take in considération this recursive
|
||||||
|
dependencies.
|
||||||
|
|
||||||
|
#+CAPTION: Recursive loading method
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def rec_load(cls, db, current_scenario):
|
||||||
|
# Default case, end of recursion
|
||||||
|
if current_scenario is None:
|
||||||
|
return [] # Default value
|
||||||
|
|
||||||
|
table = db.execute(f"<MY SELECT> WHERE scenario_id = {current_scenario}")
|
||||||
|
|
||||||
|
# If no data for this scenario, recursion
|
||||||
|
if len(table) == 0:
|
||||||
|
parent_id = db.get_parent_id(current_scenario)
|
||||||
|
return cls.rec_load(db, parent_id)
|
||||||
|
|
||||||
|
# Otherelse, parse data and return...
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
With this method, modify a data in parent scenario, modify this data
|
||||||
|
in child scenario too. Unless is value has been previously modified in
|
||||||
|
the child scenario. Deny tree node modification, except for leaf.
|
||||||
|
|
||||||
|
This method work, but it dont allow to delete data un child scenarios,
|
||||||
|
because if we dont found data for this scenario we search for parent
|
||||||
|
scenario. So, we need a condition to stop recursion in case of data
|
||||||
|
deletion in child scenario. To stop the recurtion, we can use a dummy
|
||||||
|
data flag. By default, this flags is =false=, but if this flags is
|
||||||
|
=true= the data is ignored at loading.
|
||||||
|
|
||||||
|
So, we can use this flags for each data structure who can saved in DB:
|
||||||
|
|
||||||
|
#+begin_src sql
|
||||||
|
is_dummy BOOLEAN, -- True if this data as been deleted
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Modify the loading method:
|
||||||
|
|
||||||
|
#+CAPTION: Recursive loading method with possible dummy data
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def rec_load_2(cls, db, current_scenario):
|
||||||
|
# Default case, end of recursion
|
||||||
|
if current_scenario is None:
|
||||||
|
return [] # Default value
|
||||||
|
|
||||||
|
table = db.execute(f"<MY SELECT> WHERE scenario_id = {current_scenario}")
|
||||||
|
|
||||||
|
# If no data for this scenario, recursion
|
||||||
|
if len(table) == 0:
|
||||||
|
parent_id = db.get_parent_id(current_scenario)
|
||||||
|
return cls.rec_load(db, parent_id)
|
||||||
|
|
||||||
|
for data in table:
|
||||||
|
if is_dummy(data):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Otherelse, parse data ...
|
||||||
|
|
||||||
|
# return ...
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
|
||||||
|
And add a data reduction method:
|
||||||
|
|
||||||
|
#+caption: Data reduction method for data subtree
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def reduce_change(self):
|
||||||
|
# Get the greater scenario
|
||||||
|
scenar = reduce(
|
||||||
|
lambda acc, x: max(acc, x._scenario),
|
||||||
|
self._values,
|
||||||
|
self._scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
# Apply change on this subtree
|
||||||
|
self._scenario = scenar
|
||||||
|
|
||||||
|
if is_dummy(self): # There are no more subtree
|
||||||
|
self.values = []
|
||||||
|
else: # Update data subtree scenario id
|
||||||
|
for value in self._values:
|
||||||
|
value.set_scenario(self._scenario)
|
||||||
|
# Dummy data is no more necessary in this subtree
|
||||||
|
self._values = list(
|
||||||
|
filter(
|
||||||
|
lambda v: not is_dummy(v),
|
||||||
|
self._values
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Keep data id unique for all subtree
|
||||||
|
self.get_new_db_id()
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
|
||||||
|
#+latex: \newpage
|
||||||
|
|
||||||
|
* Prototype
|
||||||
|
|
||||||
|
** Scenario
|
||||||
|
|
||||||
|
#+name: scenario
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
class Scenario():
|
||||||
|
def __init__(self, id, name, parent):
|
||||||
|
self._id = id
|
||||||
|
self._name = name
|
||||||
|
self._parent = parent
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_db(cls, db):
|
||||||
|
execute(
|
||||||
|
db, """
|
||||||
|
CREATE TABLE scenario(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
parent_id INTEGER REFERENCES scenario(id)
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_db(cls, db):
|
||||||
|
cur = execute(
|
||||||
|
db, f"SELECT * FROM scenario"
|
||||||
|
)
|
||||||
|
table = cur.fetchall()
|
||||||
|
|
||||||
|
new = []
|
||||||
|
for values in table:
|
||||||
|
new.append(
|
||||||
|
cls(
|
||||||
|
values[0], values[1], values[2],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def save(self, db):
|
||||||
|
sid = 'NULL' if self._parent is None else self._parent
|
||||||
|
|
||||||
|
execute(
|
||||||
|
db,
|
||||||
|
"INSERT INTO scenario (id, name, parent_id) " +
|
||||||
|
f"VALUES ({self._id}, '{self._name}', {sid})"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Scenario {{ {self._id}, {self._name}, parent {self._parent} }}"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self._name}({self._id})"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS: scenario
|
||||||
|
|
||||||
|
** Data
|
||||||
|
|
||||||
|
#+name: data-b
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
class B():
|
||||||
|
def __init__(self, value, scenario):
|
||||||
|
self._value = value
|
||||||
|
self._scenario = scenario
|
||||||
|
self._dummy = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_db(cls, db):
|
||||||
|
execute(db, """
|
||||||
|
CREATE TABLE b(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
dummy_data BOOLEAN,
|
||||||
|
x INTEGER,
|
||||||
|
a_id INTEGER NOT NULL,
|
||||||
|
scenario_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(a_id) REFERENCES a(id),
|
||||||
|
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
def save(self, db, a_id):
|
||||||
|
execute(
|
||||||
|
db,
|
||||||
|
"INSERT INTO b (x, dummy_data, a_id, scenario_id) " +
|
||||||
|
f"VALUES ({self._value}, {self._dummy}, {a_id}, {self._scenario})"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_db(cls, db, a_id, senar):
|
||||||
|
if senar is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
cur = execute(
|
||||||
|
db,
|
||||||
|
"SELECT x, scenario_id, dummy_data FROM b " +
|
||||||
|
f"WHERE scenario_id = {senar} AND a_id = {a_id}"
|
||||||
|
)
|
||||||
|
table = cur.fetchall()
|
||||||
|
|
||||||
|
if len(table) == 0:
|
||||||
|
parent = execute(
|
||||||
|
db,
|
||||||
|
f"SELECT parent_id FROM scenario WHERE id = {senar}"
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
return cls.load_db(db, parent[0])
|
||||||
|
|
||||||
|
new = []
|
||||||
|
for values in table:
|
||||||
|
if values[2]: # Is dummy
|
||||||
|
continue
|
||||||
|
|
||||||
|
new.append(cls(values[0], values[1]))
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def set_value(self, value, scenario):
|
||||||
|
self._value = value
|
||||||
|
self._scenario = scenario
|
||||||
|
|
||||||
|
def set_dummy(self, scenario):
|
||||||
|
self._scenario = scenario
|
||||||
|
self._dummy = True
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self._dummy:
|
||||||
|
return ""
|
||||||
|
return f"{self._value}"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self._dummy:
|
||||||
|
return ""
|
||||||
|
return f"{self._value}"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS: data-b
|
||||||
|
|
||||||
|
#+name: data-a
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
class A():
|
||||||
|
def __init__(self, id, values, scenario):
|
||||||
|
self._id = id
|
||||||
|
self._values = values
|
||||||
|
self._scenario = scenario
|
||||||
|
self._dummy = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_db(cls, db):
|
||||||
|
execute(db, """
|
||||||
|
CREATE TABLE a(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
dummy_data BOOLEAN,
|
||||||
|
scenario_id INTEGER,
|
||||||
|
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
def save(self, db):
|
||||||
|
self.reduce_change()
|
||||||
|
|
||||||
|
execute(db, f"DELETE FROM a WHERE scenario_id = {self._scenario}")
|
||||||
|
execute(
|
||||||
|
db,
|
||||||
|
"INSERT INTO a (id, dummy_data, scenario_id) " +
|
||||||
|
f"VALUES ({self._id}, {self._dummy}, {self._scenario})"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
db,
|
||||||
|
"DELETE FROM b " +
|
||||||
|
f"WHERE scenario_id = {self._scenario} " +
|
||||||
|
f"AND a_id = {self._id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for value in self._values:
|
||||||
|
value.save(db, self._id)
|
||||||
|
|
||||||
|
def reduce_change(self):
|
||||||
|
diff_scenar = reduce(
|
||||||
|
lambda acc, x: max(acc, x._scenario),
|
||||||
|
self._values,
|
||||||
|
self._scenario
|
||||||
|
)
|
||||||
|
print(f" ~> Reduce: {self._scenario} to {diff_scenar}")
|
||||||
|
self._scenario = diff_scenar
|
||||||
|
|
||||||
|
# Reduce new scenario value on each value
|
||||||
|
for value in self._values:
|
||||||
|
value._scenario = self._scenario
|
||||||
|
|
||||||
|
# Delete useless dummy data
|
||||||
|
self._values = list(
|
||||||
|
filter(
|
||||||
|
lambda v: not v._dummy,
|
||||||
|
self._values
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# HACK: keep id unique
|
||||||
|
self._id = self._id * 100 + diff_scenar
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_db(cls, db, senar):
|
||||||
|
if senar is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
cur = execute(
|
||||||
|
db,
|
||||||
|
f"SELECT id, scenario_id, dummy_data FROM a WHERE scenario_id = {senar}"
|
||||||
|
)
|
||||||
|
table = cur.fetchall()
|
||||||
|
|
||||||
|
if len(table) == 0:
|
||||||
|
parent = execute(
|
||||||
|
db,
|
||||||
|
f"SELECT parent_id FROM scenario WHERE id = {senar}"
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
return cls.load_db(db, parent[0])
|
||||||
|
|
||||||
|
new = []
|
||||||
|
for values in table:
|
||||||
|
if values[2]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
bb = B.load_db(db, values[0], senar)
|
||||||
|
new.append(cls(values[0], bb, values[1]))
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def set_dummy(self, scenario):
|
||||||
|
self._scenario = scenario
|
||||||
|
self._dummy = True
|
||||||
|
|
||||||
|
def add(self, b):
|
||||||
|
self._values.append(b)
|
||||||
|
|
||||||
|
def delete(self, index, scenario):
|
||||||
|
self._values[index].set_dummy(scenario)
|
||||||
|
self._scenario = scenario
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self._dummy:
|
||||||
|
return "{ }"
|
||||||
|
return f"{{ {self._values}, ({self._scenario}) }}"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self._dummy:
|
||||||
|
return "{ }"
|
||||||
|
return f"{{ {list(map(str, self._values))}, ({self._scenario}) }}"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS: data-a
|
||||||
|
|
||||||
|
** Full prototype
|
||||||
|
|
||||||
|
#+begin_src python :python python3 :results output :exports both :noweb yes :cache yes
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
def execute(db, query):
|
||||||
|
# print(query)
|
||||||
|
return db.execute(query)
|
||||||
|
|
||||||
|
def get_tree(db):
|
||||||
|
from treelib import Node, Tree
|
||||||
|
|
||||||
|
tree = Tree()
|
||||||
|
|
||||||
|
for senar in db.execute("SELECT * FROM scenario").fetchall():
|
||||||
|
if senar[1] is None:
|
||||||
|
tree.create_node(
|
||||||
|
str(Scenario(senar[0], senar[1], senar[2])) +
|
||||||
|
" : " + str(A.load_db(db, senar[0])[0]),
|
||||||
|
senar[0]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tree.create_node(
|
||||||
|
str(Scenario(senar[0], senar[1], senar[2])) +
|
||||||
|
" : " + str(A.load_db(db, senar[0])[0]),
|
||||||
|
senar[0],
|
||||||
|
parent=senar[2]
|
||||||
|
)
|
||||||
|
|
||||||
|
return tree
|
||||||
|
|
||||||
|
### --- Scenario ---
|
||||||
|
<<scenario>>
|
||||||
|
|
||||||
|
### --- class B ---
|
||||||
|
<<data-b>>
|
||||||
|
|
||||||
|
### --- class A ---
|
||||||
|
<<data-a>>
|
||||||
|
|
||||||
|
### --- Script ---
|
||||||
|
import sqlite3
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
pp = pprint.PrettyPrinter(width=79, compact=True, depth=6)
|
||||||
|
|
||||||
|
with sqlite3.connect(":memory:") as db:
|
||||||
|
cur = db.cursor()
|
||||||
|
|
||||||
|
Scenario.create_db(cur)
|
||||||
|
A.create_db(cur)
|
||||||
|
B.create_db(cur)
|
||||||
|
|
||||||
|
print("--- Default scenario (s0) ---")
|
||||||
|
|
||||||
|
# One scenario
|
||||||
|
|
||||||
|
s0 = Scenario(0, "s0", None)
|
||||||
|
a0 = A(
|
||||||
|
1,
|
||||||
|
[
|
||||||
|
B(0, s0._id),
|
||||||
|
B(1, s0._id),
|
||||||
|
B(2, s0._id),
|
||||||
|
],
|
||||||
|
s0._id
|
||||||
|
)
|
||||||
|
|
||||||
|
s0.save(cur)
|
||||||
|
a0.save(cur)
|
||||||
|
|
||||||
|
print("--- New scenario (s1) -- copy without modification ---")
|
||||||
|
|
||||||
|
# New scenario
|
||||||
|
|
||||||
|
s1 = Scenario(1, "s1", s0._id)
|
||||||
|
s1.save(cur)
|
||||||
|
|
||||||
|
print("--- New scenario (s2) -- data modification ---")
|
||||||
|
|
||||||
|
# New scenario 2 with data
|
||||||
|
|
||||||
|
s2 = Scenario(2, "s2", s0._id)
|
||||||
|
s2.save(cur)
|
||||||
|
|
||||||
|
a2 = a0
|
||||||
|
bb = list(map(
|
||||||
|
lambda b: b.set_value(b._value + 1, s2._id),
|
||||||
|
a2._values
|
||||||
|
))
|
||||||
|
|
||||||
|
a2.save(cur)
|
||||||
|
|
||||||
|
print("--- New scenario (s3) -- delete data ---")
|
||||||
|
|
||||||
|
# New scenario 3 with data
|
||||||
|
|
||||||
|
s3 = Scenario(3, "s3", s0._id)
|
||||||
|
s3.save(cur)
|
||||||
|
|
||||||
|
a3 = A.load_db(cur, s3._id)[0]
|
||||||
|
a3._values[0].set_dummy(s3._id)
|
||||||
|
a3.save(cur)
|
||||||
|
|
||||||
|
print("--- New scenario (s4) -- new data ---")
|
||||||
|
|
||||||
|
s4 = Scenario(4, "s4", s3._id)
|
||||||
|
s4.save(cur)
|
||||||
|
|
||||||
|
a4 = A.load_db(cur, s3._id)[0]
|
||||||
|
a4.add(B(666, s4._id))
|
||||||
|
a4.save(cur)
|
||||||
|
|
||||||
|
print("--- Scenario tree ---")
|
||||||
|
|
||||||
|
tree = get_tree(db)
|
||||||
|
print(tree)
|
||||||
|
|
||||||
|
print("--- Modify s0 data ---")
|
||||||
|
|
||||||
|
aa = A.load_db(db, s0._id)[0]
|
||||||
|
bb = list(map(
|
||||||
|
lambda b: b.set_value(b._value * 100 - 1, s0._id),
|
||||||
|
aa._values
|
||||||
|
))
|
||||||
|
aa.save(db)
|
||||||
|
|
||||||
|
print("--- Scenario tree ---")
|
||||||
|
|
||||||
|
tree = get_tree(db)
|
||||||
|
print(tree)
|
||||||
|
|
||||||
|
print("--- DB ---")
|
||||||
|
|
||||||
|
ss = db.execute("SELECT * FROM scenario").fetchall()
|
||||||
|
print(f"+ scenario ({len(ss)}):")
|
||||||
|
pp.pprint(ss)
|
||||||
|
|
||||||
|
aa = db.execute("SELECT * FROM a").fetchall()
|
||||||
|
print(f"+ a ({len(aa)}):")
|
||||||
|
pp.pprint(aa)
|
||||||
|
|
||||||
|
bb = db.execute("SELECT * FROM b").fetchall()
|
||||||
|
print(f"+ b ({len(bb)}):")
|
||||||
|
pp.pprint(bb)
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[96c84f23be557425ae2822ef7f174175ef69f9b9]:
|
||||||
|
#+begin_example
|
||||||
|
--- Default scenario (s0) ---
|
||||||
|
~> Reduce: 0 to 0
|
||||||
|
--- New scenario (s1) -- copy without modification ---
|
||||||
|
--- New scenario (s2) -- data modification ---
|
||||||
|
~> Reduce: 0 to 2
|
||||||
|
--- New scenario (s3) -- delete data ---
|
||||||
|
~> Reduce: 0 to 3
|
||||||
|
--- New scenario (s4) -- new data ---
|
||||||
|
~> Reduce: 3 to 4
|
||||||
|
--- Scenario tree ---
|
||||||
|
s0(0) : { ['0', '1', '2'], (0) }
|
||||||
|
├── s1(1) : { ['0', '1', '2'], (0) }
|
||||||
|
├── s2(2) : { ['1', '2', '3'], (2) }
|
||||||
|
└── s3(3) : { ['1', '2'], (3) }
|
||||||
|
└── s4(4) : { ['1', '2', '666'], (4) }
|
||||||
|
|
||||||
|
--- Modify s0 data ---
|
||||||
|
~> Reduce: 0 to 0
|
||||||
|
--- Scenario tree ---
|
||||||
|
s0(0) : { ['-1', '99', '199'], (0) }
|
||||||
|
├── s1(1) : { ['-1', '99', '199'], (0) }
|
||||||
|
├── s2(2) : { ['1', '2', '3'], (2) }
|
||||||
|
└── s3(3) : { ['1', '2'], (3) }
|
||||||
|
└── s4(4) : { ['1', '2', '666'], (4) }
|
||||||
|
|
||||||
|
--- DB ---
|
||||||
|
+ scenario (5):
|
||||||
|
[(0, 's0', None), (1, 's1', 0), (2, 's2', 0), (3, 's3', 0), (4, 's4', 3)]
|
||||||
|
+ a (4):
|
||||||
|
[(10000, 0, 0), (10002, 0, 2), (10003, 0, 3), (1000304, 0, 4)]
|
||||||
|
+ b (14):
|
||||||
|
[(1, 0, 0, 100, 0), (2, 0, 1, 100, 0), (3, 0, 2, 100, 0), (4, 0, 1, 10002, 2),
|
||||||
|
(5, 0, 2, 10002, 2), (6, 0, 3, 10002, 2), (7, 0, 1, 10003, 3),
|
||||||
|
(8, 0, 2, 10003, 3), (9, 0, 1, 1000304, 4), (10, 0, 2, 1000304, 4),
|
||||||
|
(11, 0, 666, 1000304, 4), (12, 0, -1, 10000, 0), (13, 0, 99, 10000, 0),
|
||||||
|
(14, 0, 199, 10000, 0)]
|
||||||
|
#+end_example
|
||||||
Whitespace-only changes.
@@ -0,0 +1,525 @@
|
|||||||
|
# presentation.org -- Pamhyr
|
||||||
|
# Copyright (C) 2023 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#+STARTUP: indent hideblocks content beamer
|
||||||
|
|
||||||
|
#+TITLE: \textbf{Pamhyr2}
|
||||||
|
#+SUBTITLE: Scenarios managements
|
||||||
|
|
||||||
|
# #+AUTHOR: Pierre-Antoine Rouby
|
||||||
|
#+LATEX_HEADER: \author[Pierre-Antoine Rouby]{\textbf{Pierre-Antoine Rouby}}
|
||||||
|
#+EMAIL: pierre-antoine.rouby@inrae.fr
|
||||||
|
#+INSTITUTE: INRAE Lyon-Villerbanne, teams River Hydraulics
|
||||||
|
#+LATEX_HEADER: \institute{INRAE Lyon-Villerbanne, River Hydraulics team}
|
||||||
|
#+DATE: 9th November
|
||||||
|
|
||||||
|
#+KEYWORDS: g ui, hydraulics, sedimentary, hydro-sedimentary, 1D modelling, freesoftware, foss
|
||||||
|
|
||||||
|
#+OPTIONS: H:2 toc:t num:t author:nil
|
||||||
|
#+LATEX_CLASS: beamer
|
||||||
|
#+LATEX_CLASS_OPTIONS: [slideopt,A4,showboxes,svgnames,aspectratio=169]
|
||||||
|
# #+LATEX_CLASS_OPTIONS: [presentation]
|
||||||
|
#+BEAMER_THEME: default
|
||||||
|
#+COLUMNS: %45ITEM %10BEAMER_ENV(Env) %10BEAMER_ACT(Act) %4BEAMER_COL(Col)
|
||||||
|
|
||||||
|
#+LANGUAGE: fr
|
||||||
|
#+LATEX_HEADER: \usepackage[frenchb]{babel}
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp :results silent :exports none
|
||||||
|
(setq org-latex-pdf-process (list
|
||||||
|
"latexmk -pdflatex='lualatex -shell-escape -interaction nonstopmode' -pdf -f %f"))
|
||||||
|
|
||||||
|
(add-to-list 'org-latex-packages-alist '("" "minted"))
|
||||||
|
(setq org-latex-listings 'minted)
|
||||||
|
(setq org-src-fontify-natively t)
|
||||||
|
|
||||||
|
(org-add-link-type
|
||||||
|
"cite" 'ebib
|
||||||
|
(lambda (path desc format)
|
||||||
|
(cond
|
||||||
|
((eq format 'html)
|
||||||
|
(format "(<cite>%s</cite>)" path))
|
||||||
|
((eq format 'text)
|
||||||
|
(format "[%s]" path))
|
||||||
|
((eq format 'latex)
|
||||||
|
(if (or (not desc) (equal 0 (search "cite:" desc)))
|
||||||
|
(format "\\cite{%s}" path)
|
||||||
|
(format "\\cite[%s][%s]{%s}"
|
||||||
|
(cadr (split-string desc ";"))
|
||||||
|
(car (split-string desc ";")) path))))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
# Wrapper
|
||||||
|
#+NAME: attr_wrap
|
||||||
|
#+HEADER: :var width="\\textwidth"
|
||||||
|
#+HEADER: :var caption=""
|
||||||
|
#+HEADER: :var smallcaption=""
|
||||||
|
#+HEADER: :var name=""
|
||||||
|
#+HEADER: :var data=""
|
||||||
|
#+HEADER: :var float="nil"
|
||||||
|
#+BEGIN_SRC sh :results output :exports none
|
||||||
|
echo "#+CAPTION[$smallcaption]: $caption"
|
||||||
|
echo "#+NAME: $name"
|
||||||
|
echo "#+ATTR_LATEX: :width $width :float $float"
|
||||||
|
echo "$data"
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \setbeamertemplate{footline}[frame number]
|
||||||
|
#+LATEX_HEADER: \setbeamertemplate{headline}{}
|
||||||
|
#+LATEX_HEADER: \usepackage{multirow}
|
||||||
|
#+LATEX_HEADER: \usepackage{fontawesome5}
|
||||||
|
#+LATEX_HEADER: \usepackage{tcolorbox}
|
||||||
|
#+LATEX_HEADER: \usepackage{tikz}
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \logo{\includegraphics[width=.1\textwidth]{../../../src/View/ui/ressources/Logo-INRAE.png}}
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \newcommand{\R}[1]{\rotatebox[origin=c]{90}{#1}}
|
||||||
|
|
||||||
|
# Beamer colors
|
||||||
|
#+LATEX_HEADER: \setbeamersize{text margin left=0.5cm,text margin right=0.5cm}
|
||||||
|
#+LATEX_HEADER: \setbeamerfont{alerted text}{series=\bfseries}
|
||||||
|
#+LATEX_HEADER: \setbeamerfont{example text}{series=\bfseries}
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \definecolor{inrae_1}{RGB}{102,193,191}
|
||||||
|
#+LATEX_HEADER: \definecolor{inrae_2}{RGB}{0,150,152}
|
||||||
|
#+LATEX_HEADER: \definecolor{inrae_3}{RGB}{39,86,98}
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \setbeamercolor{alerted text}{fg=inrae_1}
|
||||||
|
#+LATEX_HEADER: \setbeamercolor{structure}{fg=inrae_2}
|
||||||
|
#+LATEX_HEADER: \setbeamercolor{normal text}{fg=inrae_3}
|
||||||
|
#+LATEX_HEADER: \setbeamercolor*{author}{fg=inrae_3}
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \usepackage[absolute,showboxes,overlay]{textpos}
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \TPshowboxesfalse
|
||||||
|
#+LATEX_HEADER: \textblockorigin{5mm}{0mm}
|
||||||
|
|
||||||
|
# Biblio
|
||||||
|
#+LATEX_HEADER: \usepackage{natbib}
|
||||||
|
# #+LATEX_HEADER: \bibliographystyle{apalike}
|
||||||
|
#+LATEX_HEADER: \setbeamertemplate{bibliography item}{}
|
||||||
|
#+LATEX_HEADER: \renewcommand\bibfont{\scriptsize}
|
||||||
|
#+LATEX_HEADER: \setbeamertemplate{frametitle continuation}[from second]
|
||||||
|
#+LATEX_HEADER: \setbeamercolor*{bibliography entry title}{fg=inrae_3}
|
||||||
|
#+LATEX_HEADER: \setbeamercolor*{bibliography entry author}{fg=inrae_3}
|
||||||
|
#+LATEX_HEADER: \setbeamercolor*{bibliography entry location}{fg=inrae_3}
|
||||||
|
|
||||||
|
#+LATEX_HEADER: \usepackage{bbding}
|
||||||
|
#+LATEX_HEADER: \usepackage{pdfpages}
|
||||||
|
|
||||||
|
# Renew title page
|
||||||
|
#+LATEX_HEADER: \defbeamertemplate*{title page}{customized}[1][]
|
||||||
|
#+LATEX_HEADER: {
|
||||||
|
# #+LATEX_HEADER: {
|
||||||
|
# #+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}
|
||||||
|
# #+LATEX_HEADER: \tikz[overlay,remember picture]
|
||||||
|
# #+LATEX_HEADER: \node[xshift=-1cm,yshift=-1cm,text width=10cm] at (current page.north east) {
|
||||||
|
# #+LATEX_HEADER: 7$^{th}$ International Conference\\
|
||||||
|
# #+LATEX_HEADER: 8TH-10TH November\\
|
||||||
|
# #+LATEX_HEADER: EDF Lab - CHATOU, FRANCE
|
||||||
|
# #+LATEX_HEADER: }
|
||||||
|
# #+LATEX_HEADER: }
|
||||||
|
#+LATEX_HEADER: {
|
||||||
|
#+LATEX_HEADER: \usebeamerfont{title}\inserttitle\par
|
||||||
|
#+LATEX_HEADER: \usebeamerfont{title}\usebeamercolor[fg]{title}
|
||||||
|
#+LATEX_HEADER: }
|
||||||
|
#+LATEX_HEADER: \bigskip
|
||||||
|
#+LATEX_HEADER: \begin{center}
|
||||||
|
#+LATEX_HEADER: \usebeamerfont{subtitle}\usebeamercolor[fg]{subtitle}
|
||||||
|
#+LATEX_HEADER: {
|
||||||
|
#+LATEX_HEADER: \LARGE\insertsubtitle\par
|
||||||
|
#+LATEX_HEADER: }
|
||||||
|
#+LATEX_HEADER: \bigskip
|
||||||
|
#+LATEX_HEADER: \usebeamerfont{author}\usebeamercolor[fg]{author}\insertauthor\par
|
||||||
|
#+LATEX_HEADER: \bigskip
|
||||||
|
#+LATEX_HEADER: \usebeamerfont{institute}\usebeamercolor[fg]{institute}\insertinstitute\par
|
||||||
|
#+LATEX_HEADER: \bigskip
|
||||||
|
#+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}\insertdate\par
|
||||||
|
#+LATEX_HEADER: \usebeamercolor[fg]{titlegraphic}\inserttitlegraphic
|
||||||
|
#+LATEX_HEADER: \end{center}
|
||||||
|
#+LATEX_HEADER: }
|
||||||
|
|
||||||
|
# #+LATEX_HEADER: \newcommand{\tred}[1]{\textcolor{rouge_inrae}{#1}}
|
||||||
|
|
||||||
|
#+TODO: TODO WIP TOREVIEW | DONE
|
||||||
|
|
||||||
|
#+MACRO: pamhyr \textsc{PAMHyR}
|
||||||
|
#+MACRO: pamhyr2 \textsc{Pamhyr2}
|
||||||
|
|
||||||
|
#+MACRO: pause \pause
|
||||||
|
#+MACRO: framebreak \framebreak
|
||||||
|
#+MACRO: no
|
||||||
|
# #+MACRO: OK \checkmark
|
||||||
|
#+MACRO: OK \faIcon{check}
|
||||||
|
#+MACRO: bf \textbf{$1}
|
||||||
|
|
||||||
|
# #+latex: \frame{\tocpage}
|
||||||
|
|
||||||
|
* Problématique
|
||||||
|
|
||||||
|
** Problématique
|
||||||
|
|
||||||
|
*** Utilisateur
|
||||||
|
|
||||||
|
- Définire une version modifier de l'étude (changement dans les
|
||||||
|
données)
|
||||||
|
- Comparé des résultats entre une variante et l'étude
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
**** COMMENT Développeur
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
|
||||||
|
- Un unique fichier
|
||||||
|
- Limité la duplication de donnée à sauvegarder
|
||||||
|
- Garder une bonne cohérence entre données et résultats
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
*** Scénarios
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 1
|
||||||
|
:BEAMER_ENV: definition
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Un scénario est une variate d'une étude.
|
||||||
|
|
||||||
|
** Problématique -- Avancer
|
||||||
|
|
||||||
|
*** Utilisateur
|
||||||
|
|
||||||
|
- Définire une version modifier d'un senarios
|
||||||
|
- Comparé des résultats entre plusieurs senarios
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
**** COMMENT Développeur
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
|
||||||
|
- Un unique fichier
|
||||||
|
- Limité la duplication de donnée à sauvegarder
|
||||||
|
- Garder une bonne cohérence entre données et résultats
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
*** Scénarios
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 1
|
||||||
|
:BEAMER_ENV: definition
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Un scénario peut être l'étude ou une variate d'un autre scénario.
|
||||||
|
|
||||||
|
** Problématique -- Encore plus avancer
|
||||||
|
|
||||||
|
*** Utilisateur
|
||||||
|
|
||||||
|
- Définire un ensemble fini de variante correspondant a un ensemble de
|
||||||
|
valeur pour un(des) paramètre(s) et executer un solveur sur
|
||||||
|
l'ensemble des variantes
|
||||||
|
- Pouvoir comparé des metrics sur un ensemble de résultats trop grand
|
||||||
|
pour une comparaisont à la mains
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
**** COMMENT Développeur
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
|
||||||
|
- Un unique fichier
|
||||||
|
- Limité la duplication de donnée à sauvegarder
|
||||||
|
- Garder une bonne cohérence entre données et résultats
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
*** Scénarios
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 1
|
||||||
|
:BEAMER_ENV: definition
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Un scénario peut être l'étude, une variate d'un scénarios ou un
|
||||||
|
ensemble fini de variantes d'un scénarios.
|
||||||
|
|
||||||
|
** Problématique -- Encore plus plus avancer
|
||||||
|
|
||||||
|
*** Utilisateur
|
||||||
|
|
||||||
|
- Définire un ensemble fini de variante correspondant a un ensemble de
|
||||||
|
valeur pour un(des) paramètre(s) et faire un nombre fini de tirage
|
||||||
|
aléatoire dans ces paramètre pour executer un solveur ces paramètres
|
||||||
|
- Pouvoir comparé des metrics sur un ensemble de résultats trop grand
|
||||||
|
pour une comparaisont à la mains
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
*** Scénarios
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 1
|
||||||
|
:BEAMER_ENV: definition
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Un scénario peut être l'étude, une variate d'un scénarios ou un
|
||||||
|
ensemble fini ou un tirage aléatoire dans un ensemble de variantes
|
||||||
|
d'un scénarios.
|
||||||
|
|
||||||
|
** Problématique -- Développeur
|
||||||
|
|
||||||
|
*** Développeur
|
||||||
|
|
||||||
|
- Permetre a l'utilisateur de *garder une bonne cohérence entre
|
||||||
|
données et résultats* de façon claire
|
||||||
|
- Permetre a l'utilisateur de *géré les scénarios* de façon claire
|
||||||
|
(représentation graphique)
|
||||||
|
- Garder *un unique fichier* (=.pamhyr=)
|
||||||
|
- *Limité la duplication* de donnée à sauvegarder
|
||||||
|
- Permetre à l'utilisateur de garder les *résultats pertinant* sans
|
||||||
|
exploser la mémoire de l'ordinateur
|
||||||
|
|
||||||
|
* Proposition
|
||||||
|
|
||||||
|
** Proposition -- Concept
|
||||||
|
|
||||||
|
*** {{{no}}}
|
||||||
|
\vspace{-1.2cm}
|
||||||
|
**** Deux type de scénarios
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
|
||||||
|
- Scénarios simple
|
||||||
|
- Scénarios d'éxecution d'ensemble
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
**** Scénarios simple
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Est composer:
|
||||||
|
- d'un identifiant unique
|
||||||
|
- d'un nom (définie par l'utilisateur)
|
||||||
|
- d'une description (définie par l'utilisateur)
|
||||||
|
- d'un parent (définie par l'utilisateur)
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
\vspace{-0.5cm}
|
||||||
|
|
||||||
|
*** Scénarios d'ensembles
|
||||||
|
|
||||||
|
**** {{{no}}}
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
\vspace{-1cm}
|
||||||
|
Est composer:
|
||||||
|
- d'un identifiant unique
|
||||||
|
- d'un nom (définie par l'utilisateur)
|
||||||
|
- d'une description (définie par l'utilisateur)
|
||||||
|
- d'un parent (définie par l'utilisateur)
|
||||||
|
- d'un ou plusieurs ensemble de valeur
|
||||||
|
|
||||||
|
**** {{{no}}}
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
\vspace{-0.5cm}
|
||||||
|
Un ensemble de valeurs est definie par:
|
||||||
|
- une valeurs de départ
|
||||||
|
- une valeurs de fin
|
||||||
|
- un pas de valeur
|
||||||
|
- un élément d'origine (élément définie dans l'étude)
|
||||||
|
- une fonctions (modification de l'élément à l'aide d'une valeur de
|
||||||
|
l'ensemble)
|
||||||
|
|
||||||
|
** Proposition -- Limitation
|
||||||
|
|
||||||
|
*** Scénarios simple
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Si le scénarios est le *parent d'un autre scénarios*, il ne *peut plus
|
||||||
|
être modifier* sans risquer des comportement difficilement
|
||||||
|
comprehensible pour l'utilisateur.
|
||||||
|
|
||||||
|
{{{pause}}}
|
||||||
|
|
||||||
|
*** Scénarios d'ensembles
|
||||||
|
:PROPERTIES:
|
||||||
|
:BEAMER_COL: 0.5
|
||||||
|
:BEAMER_ENV: block
|
||||||
|
:END:
|
||||||
|
|
||||||
|
- Un scénarios d'ensemble *ne peut pas être parent* d'un autre
|
||||||
|
scénarios
|
||||||
|
- Le nombre d'exécution peut très rapidement grossir
|
||||||
|
|
||||||
|
** Proposition -- Affichage
|
||||||
|
|
||||||
|
#+name: graph-scenarios
|
||||||
|
#+header: :results drawer
|
||||||
|
#+header: :exports results
|
||||||
|
#+header: :post attr_wrap(width="7cm", data=*this*, name="graph-scenarios", caption="Exemple of scenarios graph", float="t")
|
||||||
|
#+begin_src dot :file "images/graph-scenarios.png" :cache no
|
||||||
|
digraph {
|
||||||
|
bgcolor="transparent";
|
||||||
|
node[colorscheme=pastel19,shape=ellipse,style="filled",fillcolor=9];
|
||||||
|
|
||||||
|
b[fillcolor=2];
|
||||||
|
|
||||||
|
aa[shape=box,fillcolor=2];
|
||||||
|
aa2[label="aa'", shape=box, fillcolor=2];
|
||||||
|
ad[shape=box, fillcolor=2];
|
||||||
|
re[shape=box, fillcolor=2];
|
||||||
|
rf[shape=box, fillcolor=2];
|
||||||
|
|
||||||
|
default -> a;
|
||||||
|
default -> b;
|
||||||
|
default -> c;
|
||||||
|
|
||||||
|
a -> aa;
|
||||||
|
a -> aa2;
|
||||||
|
a -> f -> rf;
|
||||||
|
c -> d -> ad;
|
||||||
|
c -> e -> re;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[80ed2484b9cc71143f800ff23c10846fd04697c3]: graph-scenarios
|
||||||
|
:results:
|
||||||
|
#+CAPTION[]: Exemple of scenarios graph
|
||||||
|
#+NAME: graph-scenarios
|
||||||
|
#+ATTR_LATEX: :width 7cm :float t
|
||||||
|
[[file:images/graph-scenarios.png]]
|
||||||
|
:end:
|
||||||
|
|
||||||
|
* Solution technique
|
||||||
|
|
||||||
|
** Technique -- scénarios
|
||||||
|
|
||||||
|
#+begin_src sql
|
||||||
|
CREATE TABLE scenario(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL, -- Name of the scenario
|
||||||
|
description TEXT NOT NULL, -- Rich text description
|
||||||
|
parent_id INTEGER REFERENCES scenario(id) -- Recursive references
|
||||||
|
-- for parent scenario
|
||||||
|
)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Technique -- Données -- Enregistrement
|
||||||
|
|
||||||
|
#+begin_src sql
|
||||||
|
-- Unique ID (Must be unused, to delete)
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
-- New ID (not unique)
|
||||||
|
pamhyr_id INTEGER NOT NULL,
|
||||||
|
-- (Optional) Flag for set there is no data in this scenario and
|
||||||
|
-- ignore parent scenario
|
||||||
|
dummy BOOLEAN NOT NULL,
|
||||||
|
-- Corresponding scenario
|
||||||
|
scenario_id INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario_id),
|
||||||
|
FOREIGN KEY(scenario_id) REFERENCES scenario(id),
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Technique -- Données -- Chargement
|
||||||
|
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def load(cls, db, current_scenario):
|
||||||
|
# Default case, end of recursion
|
||||||
|
if current_scenario is None:
|
||||||
|
return [] # Default value
|
||||||
|
|
||||||
|
table = db.execute(f"<MY SELECT> WHERE scenario_id = {current_scenario}")
|
||||||
|
|
||||||
|
# If no data for this scenario, recursion
|
||||||
|
if len(table) == 0:
|
||||||
|
parent_id = db.get_parent_id(current_scenario)
|
||||||
|
return cls.load(db, parent_id)
|
||||||
|
|
||||||
|
# Otherelse, parse data and return...
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Technique -- Données -- Modification
|
||||||
|
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def set_modified(self, current_scenario):
|
||||||
|
self.scenario = current_scenario
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
|
def delete(self, current_scenario):
|
||||||
|
self.deleted = True
|
||||||
|
self.set_modified(current_scenario)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Technique -- Exécution d'ensemble
|
||||||
|
|
||||||
|
#+begin_src sql
|
||||||
|
CREATE TABLE range_set(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
start REAL NOT NULL, -- Range start
|
||||||
|
end REAL NOT NULL, -- Range end
|
||||||
|
step REAL NOT NULL, -- Range step
|
||||||
|
generator_name TEXT NOT NULL, -- Generator function name (ex:
|
||||||
|
-- 'minor_strickler')
|
||||||
|
original_data_id INTEGER, -- (optional) Ref to data who apply
|
||||||
|
-- this range (ex: a strickler id)
|
||||||
|
scenario_id INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
|
||||||
|
)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Sauvegarde des résultats
|
||||||
|
|
||||||
|
** Sauvegarde des résultats
|
||||||
|
|
||||||
|
*** Scénarios simple
|
||||||
|
|
||||||
|
Sauvegarde d'un seul résultats complet par scénarios (et par solver).
|
||||||
|
|
||||||
|
*** Scénarios d'ensemble
|
||||||
|
|
||||||
|
Sauvegarde de metrics récupéré sur un ensemble de résultats (pas de
|
||||||
|
sauvegarde de tous les résultats) ou certain résultats particuliers.
|
||||||
|
|
||||||
|
* Question & remarque
|
||||||
|
|
||||||
|
** Question & remarque
|
||||||
|
|
||||||
|
- Solution satisfaisante ?
|
||||||
|
- Cas d'usage intéressent non couvert ?
|
||||||
|
- Contre exemple ?
|
||||||
|
- Meilleur solution ?
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 196 KiB |
@@ -424,7 +424,7 @@ Create a new version of {{{pamhyr}}} called {{{pamhyr2}}}
|
|||||||
|
|
||||||
** Contribution
|
** Contribution
|
||||||
#+LaTeX: \begin{center}
|
#+LaTeX: \begin{center}
|
||||||
\faIcon{gitlab} https://gitlab.irstea.fr/theophile.terraz/pamhyr/
|
\faIcon{gitlab} https://gitlab.com/pamhyr/pamhyr2/
|
||||||
#+LaTeX: \end{center}
|
#+LaTeX: \end{center}
|
||||||
|
|
||||||
*** For users
|
*** For users
|
||||||
@@ -462,7 +462,7 @@ Create a new version of {{{pamhyr}}} called {{{pamhyr2}}}
|
|||||||
# #+END_EXPORT
|
# #+END_EXPORT
|
||||||
|
|
||||||
#+LaTeX: \begin{center}
|
#+LaTeX: \begin{center}
|
||||||
\faIcon{gitlab} https://gitlab.irstea.fr/theophile.terraz/pamhyr/
|
\faIcon{gitlab} https://gitlab.com/pamhyr/pamhyr2/
|
||||||
#+LaTeX: \end{center}
|
#+LaTeX: \end{center}
|
||||||
|
|
||||||
#+LaTeX: \begin{center}
|
#+LaTeX: \begin{center}
|
||||||
|
|||||||
@@ -179,13 +179,13 @@ Ouvrez la fen
|
|||||||
\par\end{center}
|
\par\end{center}
|
||||||
|
|
||||||
Éditez la condition aux limites \textit{Fines} en la mettant en surbrillance et en cliquant sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/edit.png}.\\
|
Éditez la condition aux limites \textit{Fines} en la mettant en surbrillance et en cliquant sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/edit.png}.\\
|
||||||
Créez une condition aux limites de type concentration constante de 60 $kg/m³$ en insérant deux lignes \textit{Temps/Concentration} à l'aide du bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png}.
|
Créez une condition aux limites de type concentration constante de 0.060 $kg/m³$ en insérant deux lignes \textit{Temps/Concentration} à l'aide du bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png}.
|
||||||
|
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\includegraphics[width=15cm]{img/CL_edit.jpeg}
|
\includegraphics[width=15cm]{img/CL_edit.jpeg}
|
||||||
\par\end{center}
|
\par\end{center}
|
||||||
|
|
||||||
Procédez de la même façon pour la classe de sédiments \textit{Sables}, mais avec une concentration de 30 $kg/m³$.\\
|
Procédez de la même façon pour la classe de sédiments \textit{Sables}, mais avec une concentration de 0.030 $kg/m³$.\\
|
||||||
\\
|
\\
|
||||||
Fermez les fenêtres d'éditions des conditions aux limites et des polluants.
|
Fermez les fenêtres d'éditions des conditions aux limites et des polluants.
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ Auteurs : & Céline Berni & celine.berni@inrae.fr\tabularnewline
|
|||||||
% \pagebreak{}
|
% \pagebreak{}
|
||||||
|
|
||||||
|
|
||||||
\section{Préambule}
|
\section*{Préambule}
|
||||||
|
|
||||||
Dans ce document, nous expliciterons les fonctionnalités de PamHyr utiles à la modélisation de scénarii d'aménagement de la rivière Hogneau comme décrit dans le document de TP.
|
Dans ce document, nous expliciterons les fonctionnalités de PamHyr utiles à la modélisation de scénarii d'aménagement de la rivière Hogneau comme décrit dans le document de TP.
|
||||||
Il est utile au préalable d'avoir suivi le tutoriel pour la modélisation de la rivière Hogneau fourni avec le logiciel (Tuto1-fr.pdf).
|
Il est utile au préalable d'avoir suivi le tutoriel pour la modélisation de la rivière Hogneau fourni avec le logiciel (Tuto1-fr.pdf).
|
||||||
@@ -121,16 +121,36 @@ Suivre le tutoriel 1 vous permettra de construire le modèle avec le scénario d
|
|||||||
Notez que l'outil PamHyr ne permet pas au stade actuel de comparer plusieurs scenarii.
|
Notez que l'outil PamHyr ne permet pas au stade actuel de comparer plusieurs scenarii.
|
||||||
Vous devrez pour ce faire exporter les vos résultats à partir de la fenêtre \textit{Résultats} qui s'ouvre en cliquant sur \texttt{[Résultats] => [Visualiser les derniers résultats]} à partir de la fenêtre principale.
|
Vous devrez pour ce faire exporter les vos résultats à partir de la fenêtre \textit{Résultats} qui s'ouvre en cliquant sur \texttt{[Résultats] => [Visualiser les derniers résultats]} à partir de la fenêtre principale.
|
||||||
|
|
||||||
Le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/export.png} vous permet d'exporter les résultats au format CSV pour une utilisation en dehors de Pamhyr2.
|
|
||||||
Vous pouvez soit vous placer en un point kilométrique (PK) donné (celui marqué en rouge sur la visualisation du profil en long ou sélectionné dans le tableau) et exporter la hauteur d'eau, le niveau d'eau le débit ou autre en fonction du temps (sélectionnez alors \texttt{Temps (s)} pour l'axe X), soit vous placer à un instant donné et exporter la grandeur de votre choix pour tous les points kilométriques de votre maillage (sélectionnez alors \texttt{Point Kilométrique (m)} pour l'axe X).
|
|
||||||
Si vous choisissez cette seconde option, cocher \texttt{envelop} vous permettra d'exporter en plus la valeur maximale au cours du temps pour la grandeur choisie.
|
|
||||||
|
|
||||||
Ainsi dans l'exemple ci-dessous, les données exportées le seront au point kilométrique 34000\,m, à l'instant $t=1$ jour et 12h.
|
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\includegraphics[width=15cm]{img/export_resultats.png}
|
\includegraphics[width=15cm]{img/export_resultats_commentee.png}
|
||||||
\includegraphics[width=12cm]{img/export_resultats2.png}
|
%\includegraphics[width=12cm]{../../../src/View/ui/ressources/export_resultats2.png}
|
||||||
\par\end{center}
|
\par\end{center}
|
||||||
|
|
||||||
|
Le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/export.png} vous permet d'exporter les résultats au format CSV pour une utilisation en dehors de Pamhyr2.
|
||||||
|
|
||||||
|
Deux options s'offrent à vous :
|
||||||
|
\begin{itemize}
|
||||||
|
\item Vous souhaitez avoir une vue d'ensemble du cours d'eau (et tracer une courbe de remous par exemple). Vous allez exporter une variable en un instant donné tout le long du cours d'eau. Il faut alors vous placer à un instant donné (à l'aide du curseur en bas à gauche) et exporter la grandeur de votre choix pour tous les points kilométriques de votre maillage. Dans la fenêtre d'export, vous devrez sélectionner \texttt{Point Kilométrique (m)} pour l'axe X, et la variable que vous souhaitez exporter pour l'axe Y.
|
||||||
|
|
||||||
|
Cocher \texttt{enveloppe} vous permettra d'exporter en plus les valeurs minimale et maximale au cours du temps pour la grandeur choisie.
|
||||||
|
|
||||||
|
Par exemple, vous choisissez d'exporter la cote du fond et la cote de l'eau et vous cochez \texttt{enveloppe}. Vous obtiendrez un tableau avec les colonnes suivantes :
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{Point Kilométrique (m)} : toutes les valeurs de PK le long de votre bief
|
||||||
|
\item \texttt{Cote du fond (m)} : la cote du fond correspondante à chaque PK
|
||||||
|
\item \texttt{Cote de l'eau (m)} : la cote de l'eau correspondante à chaque PK à l'instant sélectionné (voir figure ci-dessous)
|
||||||
|
\item \texttt{Cote de l'eau min (m)} : la cote de l'eau minimale atteinte correspondante à chaque PK
|
||||||
|
\item \texttt{Cote de l'eau max (m)} : la cote de l'eau maximale atteinte correspondante à chaque PK
|
||||||
|
\end{itemize}
|
||||||
|
ces deux dernières colonnes constituant l'enveloppe de la cote de l'eau.
|
||||||
|
\item Vous souhaitez regarder l'évolution au cours du temps de ce qu'il se passe en un point précis du cours d'eau (regarder l'hydrogramme de crue à l'aval d'un aménagement par exemple). Vous devez alors vous placer au point kilométrique (PK) qui vous intéresse (le PK sélectionné est marqué en rouge sur la visualisation du profil en long ou sélectionné dans le tableau) et exporter la hauteur d'eau, le niveau d'eau, le débit ou autre en fonction du temps. Dans la fenêtre d'export, vous devrez sélectionner \texttt{Temps (s)} pour l'axe X.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Ainsi dans l'exemple ci-dessus, les données exportées le seront au point kilométrique 34000\,m, à l'instant $t=1$ jour et 12h.
|
||||||
|
|
||||||
|
|
||||||
|
\pagebreak{}
|
||||||
|
|
||||||
\section{Premier scénario d'aménagement : abaissement du seuil}
|
\section{Premier scénario d'aménagement : abaissement du seuil}
|
||||||
|
|
||||||
Parmi les 3 options d'aménagement évoquées par la collectivité locale, jouer sur le contrôle aval en abaissant le seuil qui marque la jonction avec le canal de Condé-Pommeroeul peut faire baisser le niveau à l’amont.
|
Parmi les 3 options d'aménagement évoquées par la collectivité locale, jouer sur le contrôle aval en abaissant le seuil qui marque la jonction avec le canal de Condé-Pommeroeul peut faire baisser le niveau à l’amont.
|
||||||
@@ -156,6 +176,8 @@ Sur quelle distance le seuil aval influence-t-il la hauteur d'eau ?
|
|||||||
Est-ce suffisant pour limiter la hauteur d'eau au niveau du pont de l'A2 ($PK \approx 33000$\,m) ?
|
Est-ce suffisant pour limiter la hauteur d'eau au niveau du pont de l'A2 ($PK \approx 33000$\,m) ?
|
||||||
\end{remark}
|
\end{remark}
|
||||||
|
|
||||||
|
\pagebreak{}
|
||||||
|
|
||||||
\section{Second scénario d'aménagement : élargissement du lit moyen}
|
\section{Second scénario d'aménagement : élargissement du lit moyen}
|
||||||
|
|
||||||
Ce scénario d'aménagement consiste à essayer d’augmenter le laminage en créant un lit moyen en rive droite entre les PKs 32 015 et 33 920\,m. Pour rappel, cette localisation est imposée pour des raisons de disponibilité des terrains et on ne peut pas envisager une largeur du lit moyen supérieure à 50 mètres.
|
Ce scénario d'aménagement consiste à essayer d’augmenter le laminage en créant un lit moyen en rive droite entre les PKs 32 015 et 33 920\,m. Pour rappel, cette localisation est imposée pour des raisons de disponibilité des terrains et on ne peut pas envisager une largeur du lit moyen supérieure à 50 mètres.
|
||||||
@@ -166,8 +188,9 @@ Pourquoi élargir le lit moyen peut-il avoir un effet sur le niveau d'eau durant
|
|||||||
|
|
||||||
Pour élargir le lit moyen, la géométrie doit être modifiée.
|
Pour élargir le lit moyen, la géométrie doit être modifiée.
|
||||||
Il est judicieux d'enregistrer votre étude sous un autre nom avant de procéder à ces modifications (cliquez sur \texttt{[Fichier] => [Sauvegarder sous]}).
|
Il est judicieux d'enregistrer votre étude sous un autre nom avant de procéder à ces modifications (cliquez sur \texttt{[Fichier] => [Sauvegarder sous]}).
|
||||||
Le plus simple est de repartir de la géométrie avant maillage avant de modifier les transects.
|
|
||||||
Vous pouvez supprimer les sections interpolées en les sélectionnant dans la fenêtre \textit{Géométrie} et en appuyant sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/del.png}.
|
Vous aurez un certain nombre de sections à modifier. Pour limiter leur nombre, le plus simple est de repartir de la géométrie initiale (avant maillage) avant de modifier les transects et de mailler à nouveau après les modifications.
|
||||||
|
Vous pouvez supprimer les sections interpolées (notées interpol\textit{i}) en les sélectionnant dans la fenêtre \textit{Géométrie} et en appuyant sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/del.png}.
|
||||||
|
|
||||||
Cliquez sur \texttt{[Géométrie] => [Modifier la géométrie]} ou sur l'icône \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/geometry.png} pour définir la géométrie du bief.
|
Cliquez sur \texttt{[Géométrie] => [Modifier la géométrie]} ou sur l'icône \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/geometry.png} pour définir la géométrie du bief.
|
||||||
Sélectionnez la section en travers que vous souhaitez modifier.
|
Sélectionnez la section en travers que vous souhaitez modifier.
|
||||||
@@ -197,6 +220,8 @@ Quel est l'effet de cet aménagement sur l'hydrogramme de crue ?
|
|||||||
Peut-on s'attendre à ce résultat compte tenu du volume qu'il est possible de stocker en lit moyen et du volume total de la crue ?
|
Peut-on s'attendre à ce résultat compte tenu du volume qu'il est possible de stocker en lit moyen et du volume total de la crue ?
|
||||||
\end{remark}
|
\end{remark}
|
||||||
|
|
||||||
|
\pagebreak{}
|
||||||
|
|
||||||
\section{Troisième scénario d'aménagement : casier de stockage}
|
\section{Troisième scénario d'aménagement : casier de stockage}
|
||||||
|
|
||||||
Ce troisième scénario consiste à faire baisser le débit dans la rivière en créant un déversement vers un casier de stockage en rive gauche juste en aval du pont de l'A2.
|
Ce troisième scénario consiste à faire baisser le débit dans la rivière en créant un déversement vers un casier de stockage en rive gauche juste en aval du pont de l'A2.
|
||||||
@@ -216,7 +241,7 @@ Cliquez sur \texttt{[Réseau] => [Modifier le réseau]} ou sur l'icône \include
|
|||||||
Le réseau pour la configuration de référence ne comportait qu'un seul bief entre deux noeuds.
|
Le réseau pour la configuration de référence ne comportait qu'un seul bief entre deux noeuds.
|
||||||
Pour ajouter un casier, il faut ajouter un noeud pour la diffluence, un noeud en amont du casier et un noeud en aval du casier.
|
Pour ajouter un casier, il faut ajouter un noeud pour la diffluence, un noeud en amont du casier et un noeud en aval du casier.
|
||||||
Le casier ne peut en effet pas être en limite aval du modèle ni directement au niveau de la confluence.
|
Le casier ne peut en effet pas être en limite aval du modèle ni directement au niveau de la confluence.
|
||||||
Pour ajouter un noeud, cliquez \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} pour sélectionner l'outil ``d'addition'' et cliquez ensuite dans la fenêtre grise à l'endroit ou vous souhaitez ajouter un noeud.
|
Pour ajouter un noeud, cliquez sur \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} pour sélectionner l'outil ``d'addition'' et cliquez ensuite dans la fenêtre grise à l'endroit ou vous souhaitez ajouter un noeud.
|
||||||
De la même façon vous pourrez avec cet outil ajouter un bief entre deux noeuds en cliquant successivement sur l'un puis sur l'autre.
|
De la même façon vous pourrez avec cet outil ajouter un bief entre deux noeuds en cliquant successivement sur l'un puis sur l'autre.
|
||||||
Vous pourrez alors créer un réseau tel que celui ci-dessous où DevLat est le noeud marquant la diffluence.
|
Vous pourrez alors créer un réseau tel que celui ci-dessous où DevLat est le noeud marquant la diffluence.
|
||||||
\begin{center}
|
\begin{center}
|
||||||
@@ -236,6 +261,11 @@ Il vous faudra supprimer les sections dans l'un que vous implémenterez dans l'a
|
|||||||
L'outil d'import de géométrie pourra vous aider.
|
L'outil d'import de géométrie pourra vous aider.
|
||||||
Il faudra le cas échéant réimplémenter également les ouvrages.
|
Il faudra le cas échéant réimplémenter également les ouvrages.
|
||||||
|
|
||||||
|
Vous devrez ensuite implémenter le casier sur le noeud nommé casier. Cliquez sur \texttt{[Hydraulique] => [Casiers]}. Vous pouvez ajouter un casier en cliquant sur \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png}. Vous devrez ensuite configurer le casier en cliquant sur l'icône \includegraphics[width=0.5cm]{"../../../src/View/ui/ressources/edit.png"}. Pour chaque altitude, vous pouvez définir l'aire de stockage (en ha). Vous pourrez ainsi configurer votre casier de la façon suivante :
|
||||||
|
\begin{center}
|
||||||
|
\includegraphics[width=10cm]{img/Casier.png}
|
||||||
|
\par\end{center}
|
||||||
|
|
||||||
Lancez le calcul pour chacune des crues proposées avec ce nouvel aménagement.
|
Lancez le calcul pour chacune des crues proposées avec ce nouvel aménagement.
|
||||||
|
|
||||||
\begin{remark}
|
\begin{remark}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 155 KiB |
@@ -101,7 +101,7 @@ Authors : & Pierre-Antoine Rouby & pierre-antoine.rouby@inrae.fr\tabularnewline
|
|||||||
|
|
||||||
\section{Install Pamhyr2}
|
\section{Install Pamhyr2}
|
||||||
|
|
||||||
Pamhyr2 can be downloaded from \url{https://gitlab.irstea.fr/theophile.terraz/pamhyr}.
|
Pamhyr2 can be downloaded from \url{https://gitlab.com/pamhyr/pamhyr2}.
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\includegraphics[width=15cm]{img/dl.png}
|
\includegraphics[width=15cm]{img/dl.png}
|
||||||
\par\end{center}
|
\par\end{center}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,235 @@
|
|||||||
|
# Exported from Pamhyr2
|
||||||
|
0 1 0 37 0.000000 p1013
|
||||||
|
0.0000 0.0000 14.0000
|
||||||
|
0.0000 0.0134 12.9933
|
||||||
|
0.0000 0.9213 12.5393
|
||||||
|
0.0000 1.8292 12.0854
|
||||||
|
0.0000 2.7370 11.6315
|
||||||
|
0.0000 3.6449 11.1775
|
||||||
|
0.0000 4.5528 10.7236
|
||||||
|
0.0000 5.4607 10.2697
|
||||||
|
0.0000 6.3685 9.8157
|
||||||
|
0.0000 7.2764 9.3618
|
||||||
|
0.0000 8.1843 8.9079
|
||||||
|
0.0000 9.0921 8.4539
|
||||||
|
0.0000 10.0000 8.0000 FD
|
||||||
|
0.0000 10.8333 8.0000
|
||||||
|
0.0000 11.6667 8.0000
|
||||||
|
0.0000 12.5000 8.0000
|
||||||
|
0.0000 13.3333 8.0000
|
||||||
|
0.0000 14.1667 8.0000
|
||||||
|
0.0000 15.0000 8.0000
|
||||||
|
0.0000 15.8333 8.0000
|
||||||
|
0.0000 16.6667 8.0000
|
||||||
|
0.0000 17.5000 8.0000
|
||||||
|
0.0000 18.3333 8.0000
|
||||||
|
0.0000 19.1667 8.0000
|
||||||
|
0.0000 20.0000 8.0000 FG
|
||||||
|
0.0000 20.9079 8.4539
|
||||||
|
0.0000 21.8157 8.9079
|
||||||
|
0.0000 22.7236 9.3618
|
||||||
|
0.0000 23.6315 9.8157
|
||||||
|
0.0000 24.5393 10.2697
|
||||||
|
0.0000 25.4472 10.7236
|
||||||
|
0.0000 26.3551 11.1775
|
||||||
|
0.0000 27.2630 11.6315
|
||||||
|
0.0000 28.1708 12.0854
|
||||||
|
0.0000 29.0787 12.5393
|
||||||
|
0.0000 29.9866 12.9933
|
||||||
|
0.0000 30.0000 14.0000
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
1 2 0 37 350.000000 p1025
|
||||||
|
350.0000 0.0000 13.6500
|
||||||
|
350.0000 0.0134 12.6433
|
||||||
|
350.0000 0.9213 12.1893
|
||||||
|
350.0000 1.8292 11.7354
|
||||||
|
350.0000 2.7370 11.2815
|
||||||
|
350.0000 3.6449 10.8275
|
||||||
|
350.0000 4.5528 10.3736
|
||||||
|
350.0000 5.4607 9.9197
|
||||||
|
350.0000 6.3685 9.4657
|
||||||
|
350.0000 7.2764 9.0118
|
||||||
|
350.0000 8.1843 8.5579
|
||||||
|
350.0000 9.0921 8.1039
|
||||||
|
350.0000 10.0000 7.6500 FD
|
||||||
|
350.0000 10.8333 7.6500
|
||||||
|
350.0000 11.6667 7.6500
|
||||||
|
350.0000 12.5000 7.6500
|
||||||
|
350.0000 13.3333 7.6500
|
||||||
|
350.0000 14.1667 7.6500
|
||||||
|
350.0000 15.0000 7.6500
|
||||||
|
350.0000 15.8333 7.6500
|
||||||
|
350.0000 16.6667 7.6500
|
||||||
|
350.0000 17.5000 7.6500
|
||||||
|
350.0000 18.3333 7.6500
|
||||||
|
350.0000 19.1667 7.6500
|
||||||
|
350.0000 20.0000 7.6500 FG
|
||||||
|
350.0000 20.9079 8.1039
|
||||||
|
350.0000 21.8157 8.5579
|
||||||
|
350.0000 22.7236 9.0118
|
||||||
|
350.0000 23.6315 9.4657
|
||||||
|
350.0000 24.5393 9.9197
|
||||||
|
350.0000 25.4472 10.3736
|
||||||
|
350.0000 26.3551 10.8275
|
||||||
|
350.0000 27.2630 11.2815
|
||||||
|
350.0000 28.1708 11.7354
|
||||||
|
350.0000 29.0787 12.1893
|
||||||
|
350.0000 29.9866 12.6433
|
||||||
|
350.0000 30.0000 13.6500
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
2 3 0 37 370.000000 p1026
|
||||||
|
370.0000 0.0000 13.6300
|
||||||
|
370.0000 0.0134 12.6233
|
||||||
|
370.0000 0.9213 12.1693
|
||||||
|
370.0000 1.8292 11.7154
|
||||||
|
370.0000 2.7370 11.2615
|
||||||
|
370.0000 3.6449 10.8075
|
||||||
|
370.0000 4.5528 10.3536
|
||||||
|
370.0000 5.4607 9.8997
|
||||||
|
370.0000 6.3685 9.4457
|
||||||
|
370.0000 7.2764 8.9918
|
||||||
|
370.0000 8.1843 8.5379
|
||||||
|
370.0000 9.0921 8.0839
|
||||||
|
370.0000 10.0000 7.6300 FD
|
||||||
|
370.0000 11.2500 7.6300
|
||||||
|
370.0000 12.5000 7.6300
|
||||||
|
370.0000 13.7500 7.6300
|
||||||
|
370.0000 15.0000 7.6300
|
||||||
|
370.0000 16.2500 7.6300
|
||||||
|
370.0000 17.5000 7.6300
|
||||||
|
370.0000 18.7500 7.6300
|
||||||
|
370.0000 20.0000 7.6300
|
||||||
|
370.0000 21.2500 7.6300
|
||||||
|
370.0000 22.5000 7.6300
|
||||||
|
370.0000 23.7500 7.6300
|
||||||
|
370.0000 25.0000 7.6300 FG
|
||||||
|
370.0000 25.9079 8.0839
|
||||||
|
370.0000 26.8157 8.5379
|
||||||
|
370.0000 27.7236 8.9918
|
||||||
|
370.0000 28.6315 9.4457
|
||||||
|
370.0000 29.5393 9.8997
|
||||||
|
370.0000 30.4472 10.3536
|
||||||
|
370.0000 31.3551 10.8075
|
||||||
|
370.0000 32.2630 11.2615
|
||||||
|
370.0000 33.1708 11.7154
|
||||||
|
370.0000 34.0787 12.1693
|
||||||
|
370.0000 34.9866 12.6233
|
||||||
|
370.0000 35.0000 13.6300
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
3 4 0 37 630.000000 p1035
|
||||||
|
630.0000 0.0000 13.3700
|
||||||
|
630.0000 0.0134 12.3633
|
||||||
|
630.0000 0.9213 11.9093
|
||||||
|
630.0000 1.8292 11.4554
|
||||||
|
630.0000 2.7370 11.0015
|
||||||
|
630.0000 3.6449 10.5475
|
||||||
|
630.0000 4.5528 10.0936
|
||||||
|
630.0000 5.4607 9.6397
|
||||||
|
630.0000 6.3685 9.1857
|
||||||
|
630.0000 7.2764 8.7318
|
||||||
|
630.0000 8.1843 8.2779
|
||||||
|
630.0000 9.0921 7.8239
|
||||||
|
630.0000 10.0000 7.3700 FD
|
||||||
|
630.0000 11.2500 7.3700
|
||||||
|
630.0000 12.5000 7.3700
|
||||||
|
630.0000 13.7500 7.3700
|
||||||
|
630.0000 15.0000 7.3700
|
||||||
|
630.0000 16.2500 7.3700
|
||||||
|
630.0000 17.5000 7.3700
|
||||||
|
630.0000 18.7500 7.3700
|
||||||
|
630.0000 20.0000 7.3700
|
||||||
|
630.0000 21.2500 7.3700
|
||||||
|
630.0000 22.5000 7.3700
|
||||||
|
630.0000 23.7500 7.3700
|
||||||
|
630.0000 25.0000 7.3700 FG
|
||||||
|
630.0000 25.9079 7.8239
|
||||||
|
630.0000 26.8157 8.2779
|
||||||
|
630.0000 27.7236 8.7318
|
||||||
|
630.0000 28.6315 9.1857
|
||||||
|
630.0000 29.5393 9.6397
|
||||||
|
630.0000 30.4472 10.0936
|
||||||
|
630.0000 31.3551 10.5475
|
||||||
|
630.0000 32.2630 11.0015
|
||||||
|
630.0000 33.1708 11.4554
|
||||||
|
630.0000 34.0787 11.9093
|
||||||
|
630.0000 34.9866 12.3633
|
||||||
|
630.0000 35.0000 13.3700
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
4 5 0 37 650.000000 p1036
|
||||||
|
650.0000 0.0000 13.3500
|
||||||
|
650.0000 0.0134 12.3433
|
||||||
|
650.0000 0.9213 11.8893
|
||||||
|
650.0000 1.8292 11.4354
|
||||||
|
650.0000 2.7370 10.9815
|
||||||
|
650.0000 3.6449 10.5275
|
||||||
|
650.0000 4.5528 10.0736
|
||||||
|
650.0000 5.4607 9.6197
|
||||||
|
650.0000 6.3685 9.1657
|
||||||
|
650.0000 7.2764 8.7118
|
||||||
|
650.0000 8.1843 8.2579
|
||||||
|
650.0000 9.0921 7.8039
|
||||||
|
650.0000 10.0000 7.3500 FD
|
||||||
|
650.0000 10.8333 7.3500
|
||||||
|
650.0000 11.6667 7.3500
|
||||||
|
650.0000 12.5000 7.3500
|
||||||
|
650.0000 13.3333 7.3500
|
||||||
|
650.0000 14.1667 7.3500
|
||||||
|
650.0000 15.0000 7.3500
|
||||||
|
650.0000 15.8333 7.3500
|
||||||
|
650.0000 16.6667 7.3500
|
||||||
|
650.0000 17.5000 7.3500
|
||||||
|
650.0000 18.3333 7.3500
|
||||||
|
650.0000 19.1667 7.3500
|
||||||
|
650.0000 20.0000 7.3500 FG
|
||||||
|
650.0000 20.9079 7.8039
|
||||||
|
650.0000 21.8157 8.2579
|
||||||
|
650.0000 22.7236 8.7118
|
||||||
|
650.0000 23.6315 9.1657
|
||||||
|
650.0000 24.5393 9.6197
|
||||||
|
650.0000 25.4472 10.0736
|
||||||
|
650.0000 26.3551 10.5275
|
||||||
|
650.0000 27.2630 10.9815
|
||||||
|
650.0000 28.1708 11.4354
|
||||||
|
650.0000 29.0787 11.8893
|
||||||
|
650.0000 29.9866 12.3433
|
||||||
|
650.0000 30.0000 13.3500
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
5 6 0 37 1000.000000 p1048
|
||||||
|
1000.0000 0.0000 13.0000
|
||||||
|
1000.0000 0.0134 11.9933
|
||||||
|
1000.0000 0.9213 11.5393
|
||||||
|
1000.0000 1.8292 11.0854
|
||||||
|
1000.0000 2.7370 10.6315
|
||||||
|
1000.0000 3.6449 10.1775
|
||||||
|
1000.0000 4.5528 9.7236
|
||||||
|
1000.0000 5.4607 9.2697
|
||||||
|
1000.0000 6.3685 8.8157
|
||||||
|
1000.0000 7.2764 8.3618
|
||||||
|
1000.0000 8.1843 7.9079
|
||||||
|
1000.0000 9.0921 7.4539
|
||||||
|
1000.0000 10.0000 7.0000 FD
|
||||||
|
1000.0000 10.8333 7.0000
|
||||||
|
1000.0000 11.6667 7.0000
|
||||||
|
1000.0000 12.5000 7.0000
|
||||||
|
1000.0000 13.3333 7.0000
|
||||||
|
1000.0000 14.1667 7.0000
|
||||||
|
1000.0000 15.0000 7.0000
|
||||||
|
1000.0000 15.8333 7.0000
|
||||||
|
1000.0000 16.6667 7.0000
|
||||||
|
1000.0000 17.5000 7.0000
|
||||||
|
1000.0000 18.3333 7.0000
|
||||||
|
1000.0000 19.1667 7.0000
|
||||||
|
1000.0000 20.0000 7.0000 FG
|
||||||
|
1000.0000 20.9079 7.4539
|
||||||
|
1000.0000 21.8157 7.9079
|
||||||
|
1000.0000 22.7236 8.3618
|
||||||
|
1000.0000 23.6315 8.8157
|
||||||
|
1000.0000 24.5393 9.2697
|
||||||
|
1000.0000 25.4472 9.7236
|
||||||
|
1000.0000 26.3551 10.1775
|
||||||
|
1000.0000 27.2630 10.6315
|
||||||
|
1000.0000 28.1708 11.0854
|
||||||
|
1000.0000 29.0787 11.5393
|
||||||
|
1000.0000 29.9866 11.9933
|
||||||
|
1000.0000 30.0000 13.0000
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
# Exported from Pamhyr2
|
||||||
|
0 1 0 37 0.000000 p1210
|
||||||
|
0.0000 0.0000 14.0000
|
||||||
|
0.0000 0.0134 12.9933
|
||||||
|
0.0000 0.9213 12.5393
|
||||||
|
0.0000 1.8292 12.0854
|
||||||
|
0.0000 2.7370 11.6315
|
||||||
|
0.0000 3.6449 11.1775
|
||||||
|
0.0000 4.5528 10.7236
|
||||||
|
0.0000 5.4607 10.2697
|
||||||
|
0.0000 6.3685 9.8157
|
||||||
|
0.0000 7.2764 9.3618
|
||||||
|
0.0000 8.1843 8.9079
|
||||||
|
0.0000 9.0921 8.4539
|
||||||
|
0.0000 10.0000 8.0000 FD
|
||||||
|
0.0000 10.8333 8.0000
|
||||||
|
0.0000 11.6667 8.0000
|
||||||
|
0.0000 12.5000 8.0000
|
||||||
|
0.0000 13.3333 8.0000
|
||||||
|
0.0000 14.1667 8.0000
|
||||||
|
0.0000 15.0000 8.0000
|
||||||
|
0.0000 15.8333 8.0000
|
||||||
|
0.0000 16.6667 8.0000
|
||||||
|
0.0000 17.5000 8.0000
|
||||||
|
0.0000 18.3333 8.0000
|
||||||
|
0.0000 19.1667 8.0000
|
||||||
|
0.0000 20.0000 8.0000 FG
|
||||||
|
0.0000 20.9079 8.4539
|
||||||
|
0.0000 21.8157 8.9079
|
||||||
|
0.0000 22.7236 9.3618
|
||||||
|
0.0000 23.6315 9.8157
|
||||||
|
0.0000 24.5393 10.2697
|
||||||
|
0.0000 25.4472 10.7236
|
||||||
|
0.0000 26.3551 11.1775
|
||||||
|
0.0000 27.2630 11.6315
|
||||||
|
0.0000 28.1708 12.0854
|
||||||
|
0.0000 29.0787 12.5393
|
||||||
|
0.0000 29.9866 12.9933
|
||||||
|
0.0000 30.0000 14.0000
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
1 2 0 37 300.000000 p1225
|
||||||
|
300.0000 0.0000 13.7000
|
||||||
|
300.0000 0.0134 12.6933
|
||||||
|
300.0000 0.9213 12.2393
|
||||||
|
300.0000 1.8292 11.7854
|
||||||
|
300.0000 2.7370 11.3315
|
||||||
|
300.0000 3.6449 10.8775
|
||||||
|
300.0000 4.5528 10.4236
|
||||||
|
300.0000 5.4607 9.9697
|
||||||
|
300.0000 6.3685 9.5157
|
||||||
|
300.0000 7.2764 9.0618
|
||||||
|
300.0000 8.1843 8.6079
|
||||||
|
300.0000 9.0921 8.1539
|
||||||
|
300.0000 10.0000 7.7000 FD
|
||||||
|
300.0000 10.8333 7.7000
|
||||||
|
300.0000 11.6667 7.7000
|
||||||
|
300.0000 12.5000 7.7000
|
||||||
|
300.0000 13.3333 7.7000
|
||||||
|
300.0000 14.1667 7.7000
|
||||||
|
300.0000 15.0000 7.7000
|
||||||
|
300.0000 15.8333 7.7000
|
||||||
|
300.0000 16.6667 7.7000
|
||||||
|
300.0000 17.5000 7.7000
|
||||||
|
300.0000 18.3333 7.7000
|
||||||
|
300.0000 19.1667 7.7000
|
||||||
|
300.0000 20.0000 7.7000 FG
|
||||||
|
300.0000 20.9079 8.1539
|
||||||
|
300.0000 21.8157 8.6079
|
||||||
|
300.0000 22.7236 9.0618
|
||||||
|
300.0000 23.6315 9.5157
|
||||||
|
300.0000 24.5393 9.9697
|
||||||
|
300.0000 25.4472 10.4236
|
||||||
|
300.0000 26.3551 10.8775
|
||||||
|
300.0000 27.2630 11.3315
|
||||||
|
300.0000 28.1708 11.7854
|
||||||
|
300.0000 29.0787 12.2393
|
||||||
|
300.0000 29.9866 12.6933
|
||||||
|
300.0000 30.0000 13.7000
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
2 3 0 37 310.000000 p1226
|
||||||
|
310.0000 0.0000 13.1900
|
||||||
|
310.0000 0.0134 12.1833
|
||||||
|
310.0000 0.9213 11.7293
|
||||||
|
310.0000 1.8292 11.2754
|
||||||
|
310.0000 2.7370 10.8215
|
||||||
|
310.0000 3.6449 10.3675
|
||||||
|
310.0000 4.5528 9.9136
|
||||||
|
310.0000 5.4607 9.4597
|
||||||
|
310.0000 6.3685 9.0057
|
||||||
|
310.0000 7.2764 8.5518
|
||||||
|
310.0000 8.1843 8.0979
|
||||||
|
310.0000 9.0921 7.6439
|
||||||
|
310.0000 10.0000 7.1900 FD
|
||||||
|
310.0000 10.8333 7.1900
|
||||||
|
310.0000 11.6667 7.1900
|
||||||
|
310.0000 12.5000 7.1900
|
||||||
|
310.0000 13.3333 7.1900
|
||||||
|
310.0000 14.1667 7.1900
|
||||||
|
310.0000 15.0000 7.1900
|
||||||
|
310.0000 15.8333 7.1900
|
||||||
|
310.0000 16.6667 7.1900
|
||||||
|
310.0000 17.5000 7.1900
|
||||||
|
310.0000 18.3333 7.1900
|
||||||
|
310.0000 19.1667 7.1900
|
||||||
|
310.0000 20.0000 7.1900 FG
|
||||||
|
310.0000 20.9079 7.6439
|
||||||
|
310.0000 21.8157 8.0979
|
||||||
|
310.0000 22.7236 8.5518
|
||||||
|
310.0000 23.6315 9.0057
|
||||||
|
310.0000 24.5393 9.4597
|
||||||
|
310.0000 25.4472 9.9136
|
||||||
|
310.0000 26.3551 10.3675
|
||||||
|
310.0000 27.2630 10.8215
|
||||||
|
310.0000 28.1708 11.2754
|
||||||
|
310.0000 29.0787 11.7293
|
||||||
|
310.0000 29.9866 12.1833
|
||||||
|
310.0000 30.0000 13.1900
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
3 4 0 37 390.000000 p1230
|
||||||
|
390.0000 0.0000 13.1900
|
||||||
|
390.0000 0.0134 12.1833
|
||||||
|
390.0000 0.9213 11.7293
|
||||||
|
390.0000 1.8292 11.2754
|
||||||
|
390.0000 2.7370 10.8215
|
||||||
|
390.0000 3.6449 10.3675
|
||||||
|
390.0000 4.5528 9.9136
|
||||||
|
390.0000 5.4607 9.4597
|
||||||
|
390.0000 6.3685 9.0057
|
||||||
|
390.0000 7.2764 8.5518
|
||||||
|
390.0000 8.1843 8.0979
|
||||||
|
390.0000 9.0921 7.6439
|
||||||
|
390.0000 10.0000 7.1900 FD
|
||||||
|
390.0000 10.8333 7.1900
|
||||||
|
390.0000 11.6667 7.1900
|
||||||
|
390.0000 12.5000 7.1900
|
||||||
|
390.0000 13.3333 7.1900
|
||||||
|
390.0000 14.1667 7.1900
|
||||||
|
390.0000 15.0000 7.1900
|
||||||
|
390.0000 15.8333 7.1900
|
||||||
|
390.0000 16.6667 7.1900
|
||||||
|
390.0000 17.5000 7.1900
|
||||||
|
390.0000 18.3333 7.1900
|
||||||
|
390.0000 19.1667 7.1900
|
||||||
|
390.0000 20.0000 7.1900 FG
|
||||||
|
390.0000 20.9079 7.6439
|
||||||
|
390.0000 21.8157 8.0979
|
||||||
|
390.0000 22.7236 8.5518
|
||||||
|
390.0000 23.6315 9.0057
|
||||||
|
390.0000 24.5393 9.4597
|
||||||
|
390.0000 25.4472 9.9136
|
||||||
|
390.0000 26.3551 10.3675
|
||||||
|
390.0000 27.2630 10.8215
|
||||||
|
390.0000 28.1708 11.2754
|
||||||
|
390.0000 29.0787 11.7293
|
||||||
|
390.0000 29.9866 12.1833
|
||||||
|
390.0000 30.0000 13.1900
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
4 5 0 37 400.000000 p1231
|
||||||
|
400.0000 0.0000 13.6000
|
||||||
|
400.0000 0.0134 12.5933
|
||||||
|
400.0000 0.9213 12.1393
|
||||||
|
400.0000 1.8292 11.6854
|
||||||
|
400.0000 2.7370 11.2315
|
||||||
|
400.0000 3.6449 10.7775
|
||||||
|
400.0000 4.5528 10.3236
|
||||||
|
400.0000 5.4607 9.8697
|
||||||
|
400.0000 6.3685 9.4157
|
||||||
|
400.0000 7.2764 8.9618
|
||||||
|
400.0000 8.1843 8.5079
|
||||||
|
400.0000 9.0921 8.0539
|
||||||
|
400.0000 10.0000 7.6000 FD
|
||||||
|
400.0000 10.8333 7.6000
|
||||||
|
400.0000 11.6667 7.6000
|
||||||
|
400.0000 12.5000 7.6000
|
||||||
|
400.0000 13.3333 7.6000
|
||||||
|
400.0000 14.1667 7.6000
|
||||||
|
400.0000 15.0000 7.6000
|
||||||
|
400.0000 15.8333 7.6000
|
||||||
|
400.0000 16.6667 7.6000
|
||||||
|
400.0000 17.5000 7.6000
|
||||||
|
400.0000 18.3333 7.6000
|
||||||
|
400.0000 19.1667 7.6000
|
||||||
|
400.0000 20.0000 7.6000 FG
|
||||||
|
400.0000 20.9079 8.0539
|
||||||
|
400.0000 21.8157 8.5079
|
||||||
|
400.0000 22.7236 8.9618
|
||||||
|
400.0000 23.6315 9.4157
|
||||||
|
400.0000 24.5393 9.8697
|
||||||
|
400.0000 25.4472 10.3236
|
||||||
|
400.0000 26.3551 10.7775
|
||||||
|
400.0000 27.2630 11.2315
|
||||||
|
400.0000 28.1708 11.6854
|
||||||
|
400.0000 29.0787 12.1393
|
||||||
|
400.0000 29.9866 12.5933
|
||||||
|
400.0000 30.0000 13.6000
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
|
5 6 0 37 1000.000000 p1261
|
||||||
|
1000.0000 0.0000 13.0000
|
||||||
|
1000.0000 0.0134 11.9933
|
||||||
|
1000.0000 0.9213 11.5393
|
||||||
|
1000.0000 1.8292 11.0854
|
||||||
|
1000.0000 2.7370 10.6315
|
||||||
|
1000.0000 3.6449 10.1775
|
||||||
|
1000.0000 4.5528 9.7236
|
||||||
|
1000.0000 5.4607 9.2697
|
||||||
|
1000.0000 6.3685 8.8157
|
||||||
|
1000.0000 7.2764 8.3618
|
||||||
|
1000.0000 8.1843 7.9079
|
||||||
|
1000.0000 9.0921 7.4539
|
||||||
|
1000.0000 10.0000 7.0000 FD
|
||||||
|
1000.0000 10.8333 7.0000
|
||||||
|
1000.0000 11.6667 7.0000
|
||||||
|
1000.0000 12.5000 7.0000
|
||||||
|
1000.0000 13.3333 7.0000
|
||||||
|
1000.0000 14.1667 7.0000
|
||||||
|
1000.0000 15.0000 7.0000
|
||||||
|
1000.0000 15.8333 7.0000
|
||||||
|
1000.0000 16.6667 7.0000
|
||||||
|
1000.0000 17.5000 7.0000
|
||||||
|
1000.0000 18.3333 7.0000
|
||||||
|
1000.0000 19.1667 7.0000
|
||||||
|
1000.0000 20.0000 7.0000 FG
|
||||||
|
1000.0000 20.9079 7.4539
|
||||||
|
1000.0000 21.8157 7.9079
|
||||||
|
1000.0000 22.7236 8.3618
|
||||||
|
1000.0000 23.6315 8.8157
|
||||||
|
1000.0000 24.5393 9.2697
|
||||||
|
1000.0000 25.4472 9.7236
|
||||||
|
1000.0000 26.3551 10.1775
|
||||||
|
1000.0000 27.2630 10.6315
|
||||||
|
1000.0000 28.1708 11.0854
|
||||||
|
1000.0000 29.0787 11.5393
|
||||||
|
1000.0000 29.9866 11.9933
|
||||||
|
1000.0000 30.0000 13.0000
|
||||||
|
999.9990 999.9990 999.9990
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -12,3 +12,5 @@ shapely>=2.0.1
|
|||||||
lxml>=4.9.3
|
lxml>=4.9.3
|
||||||
platformdirs>=4.2.0
|
platformdirs>=4.2.0
|
||||||
pyshp>=2.3.1
|
pyshp>=2.3.1
|
||||||
|
rasterio==1.3.11
|
||||||
|
#fortranformat==2.0.3
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
guix shell --manifest=manifest.scm -- python3 ./src/pamhyr.py $@
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
;; manifest.scm -- Pamhyr2 Guix manifest
|
||||||
|
;; Copyright (C) 2025 INRAE
|
||||||
|
;;
|
||||||
|
;; This program is free software: you can redistribute it and/or modify
|
||||||
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
;; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
;; (at your option) any later version.
|
||||||
|
;;
|
||||||
|
;; This program is distributed in the hope that it will be useful,
|
||||||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;; GNU General Public License for more details.
|
||||||
|
;;
|
||||||
|
;; You should have received a copy of the GNU General Public License
|
||||||
|
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
(specifications->manifest
|
||||||
|
(list "python" "python-platformdirs" "python-lxml"
|
||||||
|
"python-pyqt@5" "python-pyqt5-sip"
|
||||||
|
"python-pyqtgraph" "python-qscintilla"
|
||||||
|
"python-numpy@1" "python-shapely" "python-pyshp"
|
||||||
|
"python-matplotlib" "python-colorama"
|
||||||
|
"python-rasterio"))
|
||||||
@@ -46,6 +46,10 @@ copy /y ..\mage8-windows\mage_extraire.exe pamhyr\mage8\
|
|||||||
copy /y ..\mage8-windows\mailleurTT.exe pamhyr\mage8\
|
copy /y ..\mage8-windows\mailleurTT.exe pamhyr\mage8\
|
||||||
copy /y ..\mage8-windows\libbief.dll pamhyr\mage8\
|
copy /y ..\mage8-windows\libbief.dll pamhyr\mage8\
|
||||||
|
|
||||||
|
rem rubar
|
||||||
|
mkdir pamhyr\rubar
|
||||||
|
copy /y ..\adists-windows\rubarbe.exe pamhyr\rubar\
|
||||||
|
|
||||||
rem adists
|
rem adists
|
||||||
mkdir pamhyr\adists
|
mkdir pamhyr\adists
|
||||||
copy /y ..\adists-windows\adists.exe pamhyr\adists\
|
copy /y ..\adists-windows\adists.exe pamhyr\adists\
|
||||||
@@ -68,14 +72,24 @@ copy /y ..\doc\dev\images\* pamhyr\doc\images
|
|||||||
copy /y ..\doc\images\* pamhyr\doc\images
|
copy /y ..\doc\images\* pamhyr\doc\images
|
||||||
|
|
||||||
rem Tuto
|
rem Tuto
|
||||||
mkdir pamhyr\doc\Tuto1\
|
mkdir pamhyr\doc\TP_Hydraulique_Hogneau\
|
||||||
mkdir pamhyr\doc\Tuto1\data
|
mkdir pamhyr\doc\TP_Hydraulique_Hogneau\data
|
||||||
copy /y ..\doc\users\Tuto1\Hogneau_Engees2022.pdf pamhyr\doc\Tuto1\Hogneau_Engees2022.pdf
|
copy /y ..\doc\users\TP_Hydraulique_Hogneau\Hogneau_Engees2022.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Hogneau_Engees2022.pdf
|
||||||
copy /y ..\doc\users\Tuto1\step-by-step.pdf pamhyr\doc\Tuto1\Tuto1-en.pdf
|
copy /y ..\doc\users\TP_Hydraulique_Hogneau\step-by-step.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Tuto1-en.pdf
|
||||||
copy /y ..\doc\users\Tuto1\pas-a-pas.pdf pamhyr\doc\Tuto1\Tuto1-fr.pdf
|
copy /y ..\doc\users\TP_Hydraulique_Hogneau\pas-a-pas.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Tuto1-fr.pdf
|
||||||
copy /y ..\doc\users\Tuto1\*.pamhyr pamhyr\doc\Tuto1\
|
copy /y ..\doc\users\TP_Hydraulique_Hogneau\Tuto-2-fr.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Tuto2-fr.pdf
|
||||||
copy /y ..\doc\users\Tuto1\data\* pamhyr\doc\Tuto1\data\
|
copy /y ..\doc\users\TP_Hydraulique_Hogneau\*.pamhyr pamhyr\doc\TP_Hydraulique_Hogneau\
|
||||||
|
copy /y ..\doc\users\TP_Hydraulique_Hogneau\data\* pamhyr\doc\TP_Hydraulique_Hogneau\data\
|
||||||
|
|
||||||
rem TP charriage
|
rem TP charriage
|
||||||
mkdir pamhyr\doc\TP_charriage
|
mkdir pamhyr\doc\TP_charriage
|
||||||
copy /y ..\doc\users\TP_charriage\ pamhyr\doc\TP_charriage
|
mkdir pamhyr\doc\TP_charriage\Donnees_TP_Pamhyr2_charriage
|
||||||
|
copy /y ..\doc\users\TP_charriage\TP_Pamhyr2_charriage.pdf pamhyr\doc\TP_charriage\
|
||||||
|
copy /y ..\doc\users\TP_charriage\Donnees_TP_Pamhyr2_charriage\* pamhyr\doc\TP_charriage\Donnees_TP_Pamhyr2_charriage\
|
||||||
|
|
||||||
|
rem TP AdisTS
|
||||||
|
mkdir pamhyr\doc\TP_AdisTS_Vieux_Rhone\
|
||||||
|
mkdir pamhyr\doc\TP_AdisTS_Vieux_Rhone\data
|
||||||
|
copy /y ..\doc\users\TP_AdisTS_Vieux_Rhone\*.pdf pamhyr\doc\TP_AdisTS_Vieux_Rhone\
|
||||||
|
copy /y ..\doc\users\TP_AdisTS_Vieux_Rhone\*.pamhyr pamhyr\doc\TP_AdisTS_Vieux_Rhone\
|
||||||
|
copy /y ..\doc\users\TP_AdisTS_Vieux_Rhone\data\* pamhyr\doc\TP_AdisTS_Vieux_Rhone\data\
|
||||||
@@ -12,3 +12,5 @@ shapely>=2.0.1
|
|||||||
lxml>=4.9.3
|
lxml>=4.9.3
|
||||||
platformdirs>=4.2.0
|
platformdirs>=4.2.0
|
||||||
pyshp>=2.3.1
|
pyshp>=2.3.1
|
||||||
|
rasterio==1.3.11
|
||||||
|
#fortranformat==2.0.3
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Adists.py -- Pamhyr study checkers
|
# Adists.py -- Pamhyr study checkers
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Checker.py -- Pamhyr abstract checker class
|
# Checker.py -- Pamhyr abstract checker class
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# Mage.py -- Pamhyr MAGE checkers
|
# Mage.py -- Pamhyr MAGE checkers
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Study.py -- Pamhyr study checkers
|
# Study.py -- Pamhyr study checkers
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# AMeshingTool.py -- Pamhyr
|
# AMeshingTool.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -0,0 +1,361 @@
|
|||||||
|
# Internal.py -- Pamhyr
|
||||||
|
# Copyright (C) 2023-2025 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from numpy import sign, interp
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from tools import logger_color_red, logger_color_reset, logger_exception
|
||||||
|
from Meshing.AMeshingTool import AMeshingTool
|
||||||
|
|
||||||
|
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class InternalMeshing(AMeshingTool):
|
||||||
|
def __init__(self):
|
||||||
|
super(InternalMeshing, self).__init__()
|
||||||
|
|
||||||
|
###########
|
||||||
|
# Meshing #
|
||||||
|
###########
|
||||||
|
|
||||||
|
def meshing(self, reach,
|
||||||
|
step: float = 50,
|
||||||
|
limites=[-1, -1],
|
||||||
|
linear: bool = True):
|
||||||
|
|
||||||
|
# pre process
|
||||||
|
|
||||||
|
profiles = self.get_profiles(reach, limites)
|
||||||
|
if profiles is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
for p in profiles:
|
||||||
|
if len(p) < 1:
|
||||||
|
return []
|
||||||
|
|
||||||
|
guide_list = self.get_guide_list(reach, profiles)
|
||||||
|
if guide_list is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# we never modify original profiles, we work on the copies
|
||||||
|
m_profiles = self.st_to_m(profiles, guide_list)
|
||||||
|
new_profiles = self.interpolate_transversal_step(m_profiles, step)
|
||||||
|
|
||||||
|
for new_profiles2 in new_profiles:
|
||||||
|
for p in new_profiles2:
|
||||||
|
p.hard_purge_aligned_points()
|
||||||
|
|
||||||
|
return new_profiles
|
||||||
|
|
||||||
|
def st_to_m(self, profiles, guide_list):
|
||||||
|
|
||||||
|
guide_list = ["un"] + guide_list + ["np"]
|
||||||
|
max_values = [0] * (len(guide_list) - 1)
|
||||||
|
max_values_index = [0] * (len(guide_list) - 1)
|
||||||
|
# we work between each couple of guidelines
|
||||||
|
for j, p in enumerate(profiles):
|
||||||
|
for i in range(len(guide_list) - 1):
|
||||||
|
index1 = p.named_point_index(guide_list[i])
|
||||||
|
index2 = p.named_point_index(guide_list[i+1])
|
||||||
|
if index2 - index1 > max_values[i]:
|
||||||
|
max_values[i] = index2 - index1
|
||||||
|
max_values_index[i] = j
|
||||||
|
|
||||||
|
for i in range(len(max_values)):
|
||||||
|
for isect in range(max_values_index[i], len(profiles)-1):
|
||||||
|
self.compl_sect(profiles[isect],
|
||||||
|
profiles[isect+1],
|
||||||
|
guide_list[i],
|
||||||
|
guide_list[i+1])
|
||||||
|
for isect in reversed(range(0, max_values_index[i])):
|
||||||
|
self.compl_sect(profiles[isect+1],
|
||||||
|
profiles[isect],
|
||||||
|
guide_list[i],
|
||||||
|
guide_list[i+1])
|
||||||
|
return profiles
|
||||||
|
|
||||||
|
def interpolate_transversal_step(self,
|
||||||
|
profiles,
|
||||||
|
step):
|
||||||
|
# calcul number of intermediate profiles
|
||||||
|
np = []
|
||||||
|
for i in range(len(profiles)-1):
|
||||||
|
np.append(int((profiles[i+1].rk -
|
||||||
|
profiles[i].rk) / step) - 1)
|
||||||
|
if np[-1] < 0:
|
||||||
|
np[-1] = 0
|
||||||
|
|
||||||
|
new_profiles = []
|
||||||
|
for i in range(len(profiles)-1):
|
||||||
|
new_profiles2 = []
|
||||||
|
d = 1.0/float(np[i]+1)
|
||||||
|
for j in range(np[i]):
|
||||||
|
p = profiles[i].copy()
|
||||||
|
# RATIO entre les deux sections initiales
|
||||||
|
dj = float(j+1)*d
|
||||||
|
pt1 = profiles[i].points
|
||||||
|
pt2 = profiles[i+1].points
|
||||||
|
for k in range(len(pt1)):
|
||||||
|
p.points[k].x = pt1[k].x + \
|
||||||
|
dj*(pt2[k].x -
|
||||||
|
pt1[k].x)
|
||||||
|
p.points[k].y = pt1[k].y + \
|
||||||
|
dj*(pt2[k].y -
|
||||||
|
pt1[k].y)
|
||||||
|
p.points[k].z = pt1[k].z + \
|
||||||
|
dj*(pt2[k].z -
|
||||||
|
pt1[k].z)
|
||||||
|
p.rk = profiles[i].rk + \
|
||||||
|
dj*(profiles[i+1].rk -
|
||||||
|
profiles[i].rk)
|
||||||
|
p.name = f'interpol{p.rk}'
|
||||||
|
new_profiles2.append(p)
|
||||||
|
new_profiles.append(new_profiles2)
|
||||||
|
return new_profiles
|
||||||
|
|
||||||
|
def compl_sect(self, sect1, sect2, tag1, tag2):
|
||||||
|
# sect1: reference section
|
||||||
|
# sect2: section to complete
|
||||||
|
# start1 and 2: indices of the first point of the bed to complete
|
||||||
|
# end = start + len
|
||||||
|
# len1 and 2: number of intervals
|
||||||
|
# len1: target len
|
||||||
|
|
||||||
|
start1 = sect1.named_point_index(tag1)
|
||||||
|
start2 = sect2.named_point_index(tag1)
|
||||||
|
|
||||||
|
end1 = sect1.named_point_index(tag2)
|
||||||
|
end2 = sect2.named_point_index(tag2)
|
||||||
|
|
||||||
|
len1 = end1 - start1
|
||||||
|
len2 = end2 - start2
|
||||||
|
|
||||||
|
if len1 < len2:
|
||||||
|
self.compl_sect(sect2, sect1, tag1, tag2)
|
||||||
|
return
|
||||||
|
elif len1 == len2:
|
||||||
|
return
|
||||||
|
|
||||||
|
ltot1 = 0.0
|
||||||
|
ltot2 = 0.0
|
||||||
|
alpha = []
|
||||||
|
beta = []
|
||||||
|
# remove names
|
||||||
|
sect2.points[start2].name = ''
|
||||||
|
sect2.points[end2].name = ''
|
||||||
|
for i in range(len1):
|
||||||
|
ltot1 += sect1.point(start1+i).dist(sect1.point(start1+i+1))
|
||||||
|
alpha.append(ltot1)
|
||||||
|
alpha = list(map(lambda x: x/ltot1, alpha)) # target ratios
|
||||||
|
for i in range(len2):
|
||||||
|
ltot2 += sect2.point(start2+i).dist(sect2.point(start2+i+1))
|
||||||
|
beta.append(ltot2)
|
||||||
|
if len2 < 1 or ltot2 < 0.0001:
|
||||||
|
# unique point (copy len1 times)
|
||||||
|
# we are at an edge of the profile
|
||||||
|
for i in range(len1-len2):
|
||||||
|
p = sect2.point(start2).copy()
|
||||||
|
sect2.insert_point(start2, p)
|
||||||
|
len2 += 1
|
||||||
|
elif ltot1 < 0.0001:
|
||||||
|
sect2.add_npoints(len1-len2)
|
||||||
|
len2 = len1
|
||||||
|
else: # regular case
|
||||||
|
beta = list(map(lambda x: x/ltot2, beta)) # current ratios
|
||||||
|
for i in range(len1 - len2):
|
||||||
|
beta.append(1.0)
|
||||||
|
beta.append(0.0) # beta[-1]
|
||||||
|
# loop on the points to insert
|
||||||
|
for k in range(len1-len2):
|
||||||
|
trouve = False
|
||||||
|
for j0 in range(len2):
|
||||||
|
if trouve:
|
||||||
|
break
|
||||||
|
undeplus = True
|
||||||
|
for j1 in range(j0, len2):
|
||||||
|
if undeplus:
|
||||||
|
if beta[j1] <= alpha[j1]:
|
||||||
|
undeplus = False
|
||||||
|
break
|
||||||
|
if undeplus:
|
||||||
|
if j0 == len2:
|
||||||
|
trouve = True
|
||||||
|
else:
|
||||||
|
j1 = j0+1
|
||||||
|
if beta[j0]-alpha[j0] > alpha[j1]-beta[j0]:
|
||||||
|
trouve = True
|
||||||
|
|
||||||
|
if trouve:
|
||||||
|
len2 += 1
|
||||||
|
for i in reversed(range(j0, len2)):
|
||||||
|
beta[i+1] = beta[i]
|
||||||
|
if (beta[j0] == beta[j0-1]):
|
||||||
|
# rien
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
ratio = (alpha[j0] - beta[j0-1]) \
|
||||||
|
/ (beta[j0] - beta[j0-1])
|
||||||
|
if ratio < 0.0:
|
||||||
|
print(f"ratio négatif {ratio}")
|
||||||
|
# on double le point a gauche
|
||||||
|
p = sect2.point(start2+j0-1).copy()
|
||||||
|
sect2.insert_point(start2+j0-1, p)
|
||||||
|
sect2.point(start2+j0-1).name = ''
|
||||||
|
beta[j0] = beta[j0-1]
|
||||||
|
else:
|
||||||
|
p = sect2.point(start2+j0).copy()
|
||||||
|
sect2.insert_point(start2+j0, p)
|
||||||
|
sect2.point(start2+j0+1).name = ''
|
||||||
|
sect2.point(start2+j0+1).x = \
|
||||||
|
(1.0-ratio) * sect2.point(start2+j0).x + \
|
||||||
|
ratio * sect2.point(start2+j0+2).x
|
||||||
|
sect2.point(start2+j0+1).y = \
|
||||||
|
(1.0-ratio) * sect2.point(start2+j0).y + \
|
||||||
|
ratio * sect2.point(start2+j0+2).y
|
||||||
|
sect2.point(start2+j0+1).z = \
|
||||||
|
(1.0-ratio) * sect2.point(start2+j0).z + \
|
||||||
|
ratio * sect2.point(start2+j0+2).z
|
||||||
|
beta[j0] = (1.-ratio)*beta[j0-1] \
|
||||||
|
+ ratio*beta[j0+1]
|
||||||
|
|
||||||
|
if len1 > len2:
|
||||||
|
for i in range(len1 - len2):
|
||||||
|
p = sect2.point(start2+len2).copy()
|
||||||
|
sect2.insert_point(start2+len2, p)
|
||||||
|
sect2.point(start2+len2).name = ''
|
||||||
|
if tag1 != "un":
|
||||||
|
sect2.point(start2).name = tag1
|
||||||
|
if tag1 != "np":
|
||||||
|
sect2.point(start2+len2).name = tag2
|
||||||
|
sect2.modified()
|
||||||
|
|
||||||
|
def update_rk(self, reach, begin_rk, end_rk,
|
||||||
|
step: float = 50,
|
||||||
|
limites=[-1, -1],
|
||||||
|
origin=0,
|
||||||
|
directrices=['un', 'np'],
|
||||||
|
lplan: bool = False,
|
||||||
|
lm: int = 3,
|
||||||
|
linear: bool = False,
|
||||||
|
origin_value=0.0,
|
||||||
|
orientation=0):
|
||||||
|
if reach is None or len(reach.profiles) == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
nprof = reach.number_profiles
|
||||||
|
if origin >= nprof or origin < 0:
|
||||||
|
logger.warning(
|
||||||
|
f"Origin outside reach"
|
||||||
|
)
|
||||||
|
return reach.get_rk()
|
||||||
|
|
||||||
|
# orientation is the orintation of the bief:
|
||||||
|
# 1: up -> downstream
|
||||||
|
# 2: down -> upstream
|
||||||
|
# else: keep current orientation
|
||||||
|
old_orientation = sign(reach.profiles[-1].rk - reach.profiles[0].rk)
|
||||||
|
if orientation == 1:
|
||||||
|
sgn = 1.0
|
||||||
|
elif orientation == 2:
|
||||||
|
sgn = -1.0
|
||||||
|
else:
|
||||||
|
sgn = old_orientation
|
||||||
|
if abs(sgn) < 0.5:
|
||||||
|
sgn = 1.0
|
||||||
|
|
||||||
|
new_rk = [0.0]*nprof
|
||||||
|
new_rk[origin] = origin_value
|
||||||
|
|
||||||
|
frictions = reach._parent.frictions
|
||||||
|
|
||||||
|
old_begin_rk = list(map(lambda x: x * old_orientation,
|
||||||
|
begin_rk))
|
||||||
|
old_end_rk = list(map(lambda x: x * old_orientation,
|
||||||
|
end_rk))
|
||||||
|
old_rk = list(map(lambda x: x * old_orientation,
|
||||||
|
reach.get_rk()))
|
||||||
|
|
||||||
|
if origin < nprof - 1:
|
||||||
|
for i in range(origin+1, nprof):
|
||||||
|
# 2D
|
||||||
|
d1 = reach.profiles[i-1].named_point(
|
||||||
|
directrices[0]
|
||||||
|
).dist_2d(reach.profiles[i].named_point(directrices[0]))
|
||||||
|
d2 = reach.profiles[i-1].named_point(
|
||||||
|
directrices[1]
|
||||||
|
).dist_2d(reach.profiles[i].named_point(directrices[1]))
|
||||||
|
new_rk[i] = new_rk[i-1] + (sgn * (d1 + d2) / 2)
|
||||||
|
if origin > 0:
|
||||||
|
for i in reversed(range(0, origin)):
|
||||||
|
# 2D
|
||||||
|
d1 = reach.profiles[i+1].named_point(
|
||||||
|
directrices[0]
|
||||||
|
).dist_2d(reach.profiles[i].named_point(directrices[0]))
|
||||||
|
d2 = reach.profiles[i+1].named_point(
|
||||||
|
directrices[1]
|
||||||
|
).dist_2d(reach.profiles[i].named_point(directrices[1]))
|
||||||
|
new_rk[i] = new_rk[i+1] - (sgn * (d1 + d2) / 2)
|
||||||
|
|
||||||
|
new_begin_rk = interp(old_begin_rk, old_rk, new_rk)
|
||||||
|
new_end_rk = interp(old_end_rk, old_rk, new_rk)
|
||||||
|
if abs(sgn - old_orientation) > 0.1: # orientation changed
|
||||||
|
return new_rk, new_end_rk, new_begin_rk
|
||||||
|
else:
|
||||||
|
return new_rk, new_begin_rk, new_end_rk
|
||||||
|
|
||||||
|
def get_guide_list(self, reach, profiles):
|
||||||
|
|
||||||
|
gl = reach.compute_guidelines()
|
||||||
|
|
||||||
|
# we make sure that the lines are in the left-to-right order
|
||||||
|
guide_list = [
|
||||||
|
[
|
||||||
|
x.name
|
||||||
|
for x in p.named_points()
|
||||||
|
if x.name in gl[0]
|
||||||
|
]
|
||||||
|
for p in profiles]
|
||||||
|
|
||||||
|
# we make sure the lines never cross
|
||||||
|
for gl in guide_list:
|
||||||
|
for i in range(len(guide_list[0])):
|
||||||
|
if gl[i] != guide_list[0][i]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return guide_list[0]
|
||||||
|
|
||||||
|
def get_profiles(self, reach, limites):
|
||||||
|
|
||||||
|
if reach is None or len(reach.profiles) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if limites[0] > limites[1]:
|
||||||
|
lim = limites[1]
|
||||||
|
limites[1] = limites[0]
|
||||||
|
limites[0] = lim
|
||||||
|
elif limites[0] == limites[1]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
profiles = [reach.profile(i).copy()
|
||||||
|
for i in range(limites[0], limites[1]+1)
|
||||||
|
]
|
||||||
|
|
||||||
|
return profiles
|
||||||
+8
-3
@@ -1,5 +1,5 @@
|
|||||||
# Mage.py -- Pamhyr
|
# Mage.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import tempfile
|
import tempfile
|
||||||
|
from numpy import sign
|
||||||
|
|
||||||
from ctypes import (
|
from ctypes import (
|
||||||
cdll,
|
cdll,
|
||||||
@@ -343,7 +344,9 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
logger.info("Waiting ...")
|
||||||
proc.waitForFinished()
|
proc.waitForFinished()
|
||||||
|
logger.info(f"Waiting ... Done (status : {proc.exitCode()})")
|
||||||
|
|
||||||
if proc.exitCode() != 0:
|
if proc.exitCode() != 0:
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -352,7 +355,7 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
|||||||
f"{logger_color_reset()}"
|
f"{logger_color_reset()}"
|
||||||
)
|
)
|
||||||
outputs = proc.readAllStandardOutput()
|
outputs = proc.readAllStandardOutput()
|
||||||
logger.debug(outputs)
|
logger.warning(outputs)
|
||||||
|
|
||||||
errors = proc.readAllStandardError()
|
errors = proc.readAllStandardError()
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -418,7 +421,9 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
logger.debug("Waiting ...")
|
||||||
proc.waitForFinished()
|
proc.waitForFinished()
|
||||||
|
logger.debug(f"Waiting ... Done (status : {proc.exitCode()})")
|
||||||
|
|
||||||
if proc.exitCode() != 0:
|
if proc.exitCode() != 0:
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -427,7 +432,7 @@ class MeshingWithMageMailleurTT(AMeshingTool):
|
|||||||
f"{logger_color_reset()}"
|
f"{logger_color_reset()}"
|
||||||
)
|
)
|
||||||
outputs = proc.readAllStandardOutput()
|
outputs = proc.readAllStandardOutput()
|
||||||
logger.debug(outputs)
|
logger.warning(outputs)
|
||||||
|
|
||||||
errors = proc.readAllStandardError()
|
errors = proc.readAllStandardError()
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# __init__.py -- Pamhyr
|
# __init__.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# test_Model.py -- Pamhyr
|
# test_Model.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,7 +21,6 @@ import unittest
|
|||||||
import warnings
|
import warnings
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from Model.Saved import SavedStatus
|
|
||||||
from Model.Study import Study
|
from Model.Study import Study
|
||||||
from Model.River import River
|
from Model.River import River
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# AddFile.py -- Pamhyr
|
# AddFile.py -- Pamhyr
|
||||||
# Copyright (C) 2024 INRAE
|
# Copyright (C) 2024-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,31 +22,25 @@ from tools import trace, timer
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
|
|
||||||
class AddFile(SQLSubModel):
|
class AddFile(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, enabled=True,
|
def __init__(self, id: int = -1, enabled=True,
|
||||||
name="", path="", text="",
|
name="", path="", text="",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(AddFile, self).__init__()
|
super(AddFile, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
if id == -1:
|
owner_scenario=owner_scenario
|
||||||
self.id = AddFile._id_cnt
|
)
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._name = f"File {self.id}" if name == "" else name
|
self._name = f"File #{self._pamhyr_id}" if name == "" else name
|
||||||
self._path = path
|
self._path = path
|
||||||
self._text = text
|
self._text = text
|
||||||
|
|
||||||
AddFile._id_cnt = max(id, AddFile._id_cnt+1)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
value = None
|
value = None
|
||||||
|
|
||||||
@@ -71,7 +65,7 @@ class AddFile(SQLSubModel):
|
|||||||
elif key == "text":
|
elif key == "text":
|
||||||
self._text = value
|
self._text = value
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
@@ -80,7 +74,7 @@ class AddFile(SQLSubModel):
|
|||||||
@enabled.setter
|
@enabled.setter
|
||||||
def enabled(self, enabled):
|
def enabled(self, enabled):
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def is_enabled(self):
|
def is_enabled(self):
|
||||||
return self._enabled
|
return self._enabled
|
||||||
@@ -92,7 +86,7 @@ class AddFile(SQLSubModel):
|
|||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self):
|
def path(self):
|
||||||
@@ -101,7 +95,7 @@ class AddFile(SQLSubModel):
|
|||||||
@path.setter
|
@path.setter
|
||||||
def path(self, path):
|
def path(self, path):
|
||||||
self._path = path
|
self._path = path
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text(self):
|
def text(self):
|
||||||
@@ -110,38 +104,80 @@ class AddFile(SQLSubModel):
|
|||||||
@text.setter
|
@text.setter
|
||||||
def text(self, text):
|
def text(self, text):
|
||||||
self._text = text
|
self._text = text
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE additional_files(
|
CREATE TABLE additional_files{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
enabled BOOLEAN NOT NULL,
|
enabled BOOLEAN NOT NULL,
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
path TEXT NOT NULL,
|
path TEXT NOT NULL,
|
||||||
text TEXT NOT NULL
|
text TEXT NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
|
release = int(release)
|
||||||
|
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 8:
|
if release < 8:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
return True
|
||||||
|
|
||||||
|
if 8 < release < 13:
|
||||||
|
cls._db_update_to_0_0_13(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if release < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE additional_files " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_0_13(cls, execute, data):
|
||||||
|
table = "additional_files"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
execute(
|
||||||
|
"INSERT INTO additional_files_tmp " +
|
||||||
|
"(pamhyr_id, enabled, name, path, text, scenario) " +
|
||||||
|
"SELECT pamhyr_id, enabled, name, path, text, scenario " +
|
||||||
|
"FROM additional_files"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, enabled, name, path, text " +
|
"SELECT pamhyr_id, enabled, deleted, name, path, text, scenario " +
|
||||||
"FROM additional_files"
|
"FROM additional_files " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
@@ -149,30 +185,45 @@ class AddFile(SQLSubModel):
|
|||||||
|
|
||||||
id = next(it)
|
id = next(it)
|
||||||
enabled = (next(it) == 1)
|
enabled = (next(it) == 1)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
name = next(it)
|
name = next(it)
|
||||||
path = next(it)
|
path = next(it)
|
||||||
text = next(it)
|
text = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
f = cls(
|
f = cls(
|
||||||
id=id, enabled=enabled, name=name, path=path, text=text,
|
id=id, enabled=enabled, name=name, path=path, text=text,
|
||||||
status=data['status']
|
status=data['status'], owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
f.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(id)
|
||||||
new.append(f)
|
new.append(f)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
sql = (
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"additional_files(id, enabled, name, path, text) " +
|
"additional_files(pamhyr_id, enabled, deleted, " +
|
||||||
|
"name, path, text, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {self._enabled}, " +
|
f"{self._pamhyr_id}, " +
|
||||||
|
f"{self._db_format(self._enabled)}, " +
|
||||||
|
f"{self._db_format(self.is_deleted())}, " +
|
||||||
f"'{self._db_format(self._name)}', " +
|
f"'{self._db_format(self._name)}', " +
|
||||||
f"'{self._db_format(self._path)}', " +
|
f"'{self._db_format(self._path)}', " +
|
||||||
f"'{self._db_format(self._text)}'" +
|
f"'{self._db_format(self._text)}', " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# AddFileList.py -- Pamhyr
|
# AddFileList.py -- Pamhyr
|
||||||
# Copyright (C) 2024 INRAE
|
# Copyright (C) 2024-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.AdditionalFile.AddFile import AddFile
|
from Model.AdditionalFile.AddFile import AddFile
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,10 @@ class AddFileList(PamhyrModelList):
|
|||||||
ok = True
|
ok = True
|
||||||
|
|
||||||
# Delete previous data
|
# Delete previous data
|
||||||
execute("DELETE FROM additional_files")
|
execute(
|
||||||
|
"DELETE FROM additional_files " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
for af in self._lst:
|
for af in self._lst:
|
||||||
ok &= af._db_save(execute, data)
|
ok &= af._db_save(execute, data)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# BoundaryCondition.py -- Pamhyr
|
# BoundaryCondition.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,24 +27,193 @@ from tools import (
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class BoundaryCondition(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, data0, data1,
|
||||||
status=None):
|
id: int = -1,
|
||||||
super(BoundaryCondition, self).__init__()
|
types=[float, float],
|
||||||
|
status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
|
super(Data, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._types = types
|
||||||
|
self._data = [data0, data1]
|
||||||
|
|
||||||
if id == -1:
|
@classmethod
|
||||||
self.id = BoundaryCondition._id_cnt
|
def _db_create(cls, execute, ext=""):
|
||||||
else:
|
execute(f"""
|
||||||
self.id = id
|
CREATE TABLE boundary_condition_data{ext}(
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
ind INTEGER NOT NULL,
|
||||||
|
data0 TEXT NOT NULL,
|
||||||
|
data1 TEXT NOT NULL,
|
||||||
|
bc INTEGER,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(bc) REFERENCES boundary_condition(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 1:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE boundary_condition_data " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "boundary_condition_data"
|
||||||
|
bcs = data['id2pid']['boundary_condition']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(
|
||||||
|
execute, table,
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, ind, data0, data1, bc, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ind, data0, data1, bc, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_bc_pid(execute, table, bcs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_bc_pid(cls, execute, table, bcs):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, bc FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
bc_id = next(it)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET bc = {bcs[bc_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
bc = data["bc"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
values = execute(
|
||||||
|
"SELECT pamhyr_id, deleted, ind, " +
|
||||||
|
"data0, data1, scenario " +
|
||||||
|
"FROM boundary_condition_data " +
|
||||||
|
f"WHERE bc = {bc._pamhyr_id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
|
||||||
|
"ORDER BY ind ASC"
|
||||||
|
)
|
||||||
|
|
||||||
|
for v in values:
|
||||||
|
it = iter(v)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
ind = next(it)
|
||||||
|
data0 = bc._types[0](next(it))
|
||||||
|
data1 = bc._types[1](next(it))
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
nd = cls(
|
||||||
|
data0, data1,
|
||||||
|
id=pid,
|
||||||
|
types=bc._types,
|
||||||
|
status=data['status'],
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
nd.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(nd)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
pid = self._pamhyr_id
|
||||||
|
ind = data["ind"]
|
||||||
|
data0 = self._db_format(str(self[0]))
|
||||||
|
data1 = self._db_format(str(self[1]))
|
||||||
|
bc = data["bc"]
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"boundary_condition_data(pamhyr_id, deleted, ind, " +
|
||||||
|
"data0, data1, bc, scenario) " +
|
||||||
|
f"VALUES (" +
|
||||||
|
f"{pid}, {self._db_format(self.is_deleted())}, " +
|
||||||
|
f"{ind}, '{self._db_format(data0)}', {self._db_format(data1)}, " +
|
||||||
|
f"{bc._pamhyr_id}, {self._status.scenario_id}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._types[key](self._data[key])
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self._data[key] = self._types[key](value)
|
||||||
|
|
||||||
|
|
||||||
|
class BoundaryCondition(SQLSubModel):
|
||||||
|
_sub_classes = [Data]
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1,
|
||||||
|
name: str = "",
|
||||||
|
status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
|
super(BoundaryCondition, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._type = ""
|
self._type = ""
|
||||||
@@ -53,37 +222,66 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
self._header = []
|
self._header = []
|
||||||
self._types = [float, float]
|
self._types = [float, float]
|
||||||
|
|
||||||
BoundaryCondition._id_cnt = max(BoundaryCondition._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE boundary_condition(
|
CREATE TABLE boundary_condition{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type TEXT NOT NULL,
|
type TEXT NOT NULL,
|
||||||
tab TEXT NOT NULL,
|
tab TEXT NOT NULL,
|
||||||
node INTEGER,
|
node INTEGER,
|
||||||
FOREIGN KEY(node) REFERENCES river_node(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(node) REFERENCES river_node(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
execute("""
|
if ext == "_tmp":
|
||||||
CREATE TABLE boundary_condition_data(
|
return True
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
ind INTEGER NOT NULL,
|
|
||||||
data0 TEXT NOT NULL,
|
|
||||||
data1 TEXT NOT NULL,
|
|
||||||
bc INTEGER,
|
|
||||||
FOREIGN KEY(bc) REFERENCES boundary_condition(id)
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
return True
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == minor == "0":
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE friction " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "boundary_condition"
|
||||||
|
nodes = data['id2pid']['river_node']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
# Copy table
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
f"(pamhyr_id, name, type, tab, node, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, type, tab, node, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_node_pid(execute, table, nodes)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_ctor_from_type(cls, t):
|
def _get_ctor_from_type(cls, t):
|
||||||
@@ -110,83 +308,117 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
nodes = data["nodes"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name, type, node " +
|
"SELECT pamhyr_id, deleted, name, type, node, scenario " +
|
||||||
"FROM boundary_condition " +
|
"FROM boundary_condition " +
|
||||||
f"WHERE tab = '{tab}'"
|
f"WHERE tab = '{tab}' " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
t = row[2]
|
it = iter(row)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
t = next(it)
|
||||||
|
node = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
ctor = cls._get_ctor_from_type(t)
|
ctor = cls._get_ctor_from_type(t)
|
||||||
|
|
||||||
bc = ctor(
|
bc = ctor(
|
||||||
id=row[0],
|
id=pid, name=name,
|
||||||
name=row[1],
|
status=data['status'],
|
||||||
status=data['status']
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
bc.set_as_deleted()
|
||||||
|
|
||||||
bc.node = None
|
bc.node = None
|
||||||
if row[3] != -1:
|
if node != -1:
|
||||||
bc.node = next(filter(lambda n: n.id == row[3], data["nodes"]),
|
bc.node = next(filter(lambda n: n.id == node, nodes), None)
|
||||||
None)
|
|
||||||
|
|
||||||
values = execute(
|
data["bc"] = bc
|
||||||
"SELECT ind, data0, data1 FROM boundary_condition_data " +
|
bc._data = Data._db_load(execute, data=data)
|
||||||
f"WHERE bc = '{bc.id}'"
|
|
||||||
)
|
|
||||||
# Create dummy data list
|
|
||||||
for _ in values:
|
|
||||||
bc.add(0)
|
|
||||||
# Write data
|
|
||||||
for v in values:
|
|
||||||
ind = v[0]
|
|
||||||
data0 = bc._types[0](v[1])
|
|
||||||
data1 = bc._types[1](v[2])
|
|
||||||
# Replace data at pos ind
|
|
||||||
bc._data[ind] = (data0, data1)
|
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
new.append(bc)
|
new.append(bc)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
|
||||||
execute(f"DELETE FROM boundary_condition WHERE id = {self.id}")
|
execute(
|
||||||
execute(f"DELETE FROM boundary_condition_data WHERE bc = {self.id}")
|
"DELETE FROM boundary_condition_data " +
|
||||||
|
f"WHERE bc = {self._pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
node = -1
|
node = -1
|
||||||
if self._node is not None:
|
if self._node is not None:
|
||||||
node = self._node.id
|
node = self._node.id
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"boundary_condition(id, name, type, tab, node) " +
|
"boundary_condition(" +
|
||||||
|
"pamhyr_id, deleted, name, type, tab, node, scenario" +
|
||||||
|
") " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._db_format(self._name)}', " +
|
f"{self._pamhyr_id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"'{self._db_format(self._type)}', '{tab}', {node}" +
|
f"'{self._db_format(self._name)}', " +
|
||||||
|
f"'{self._db_format(self._type)}', '{tab}', {node}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
data["bc"] = self
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for d in self._data:
|
for d in self._data:
|
||||||
data0 = self._db_format(str(d[0]))
|
data["ind"] = ind
|
||||||
data1 = self._db_format(str(d[1]))
|
|
||||||
|
d._db_save(execute, data)
|
||||||
|
|
||||||
sql = (
|
|
||||||
"INSERT INTO " +
|
|
||||||
"boundary_condition_data(ind, data0, data1, bc) " +
|
|
||||||
f"VALUES ({ind}, '{data0}', {data1}, {self.id})"
|
|
||||||
)
|
|
||||||
execute(sql)
|
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for el in self._data:
|
||||||
|
el._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(
|
||||||
|
list(
|
||||||
|
filter(
|
||||||
|
lambda el: not el.is_deleted(),
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def compatibility(cls):
|
def compatibility(cls):
|
||||||
@@ -211,14 +443,14 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._name == "":
|
if self._name == "":
|
||||||
return f"B{self.id + 1}"
|
return f"B #{self.pamhyr_id}"
|
||||||
|
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bctype(self):
|
def bctype(self):
|
||||||
@@ -231,7 +463,7 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
@node.setter
|
@node.setter
|
||||||
def node(self, node):
|
def node(self, node):
|
||||||
self._node = node
|
self._node = node
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def has_node(self):
|
def has_node(self):
|
||||||
return self._node is not None
|
return self._node is not None
|
||||||
@@ -242,7 +474,12 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def data(self):
|
def data(self):
|
||||||
return self._data.copy()
|
return list(
|
||||||
|
filter(
|
||||||
|
lambda el: not el.is_deleted(),
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def get_type_column(self, column):
|
def get_type_column(self, column):
|
||||||
if 0 <= column < 2:
|
if 0 <= column < 2:
|
||||||
@@ -276,51 +513,79 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
new_0 = self._types[0](data[0].replace(",", "."))
|
new_0 = self._types[0](data[0].replace(",", "."))
|
||||||
new_1 = self._types[1](data[1].replace(",", "."))
|
new_1 = self._types[1](data[1].replace(",", "."))
|
||||||
|
|
||||||
return (new_0, new_1)
|
return Data(
|
||||||
|
new_0, new_1,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
|
|
||||||
def add(self, index: int):
|
def add(self, index: int):
|
||||||
value = (self._default_0, self._default_1)
|
value = Data(
|
||||||
|
self._default_0, self._default_1,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def insert(self, index: int, value):
|
def insert(self, index: int, value):
|
||||||
self._data.insert(index, value)
|
if value in self._data:
|
||||||
self._status.modified()
|
value.set_as_not_deleted()
|
||||||
|
else:
|
||||||
|
self._data.insert(index, value)
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
self.modified()
|
||||||
|
|
||||||
|
def hard_delete_i(self, indexes):
|
||||||
self._data = list(
|
self._data = list(
|
||||||
map(
|
map(
|
||||||
lambda e: e[1],
|
lambda e: e[1],
|
||||||
filter(
|
filter(
|
||||||
lambda e: e[0] not in indexes,
|
lambda e: e[0] not in indexes,
|
||||||
|
enumerate(self._data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda e: e[1].set_as_deleted(),
|
||||||
|
filter(
|
||||||
|
lambda e: e[0] in indexes,
|
||||||
enumerate(self.data)
|
enumerate(self.data)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete(self, els):
|
def delete(self, els):
|
||||||
self._data = list(
|
for el in els:
|
||||||
filter(
|
el.set_as_deleted()
|
||||||
lambda e: e not in els,
|
|
||||||
self.data
|
self.modified()
|
||||||
)
|
|
||||||
)
|
def undelete(self, els):
|
||||||
self._status.modified()
|
for el in els:
|
||||||
|
el.set_as_not_deleted()
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def sort(self, _reverse=False, key=None):
|
def sort(self, _reverse=False, key=None):
|
||||||
if key is None:
|
if key is None:
|
||||||
self._data.sort(reverse=_reverse)
|
self._data.sort(reverse=_reverse)
|
||||||
else:
|
else:
|
||||||
self._data.sort(reverse=_reverse, key=key)
|
self._data.sort(reverse=_reverse, key=key)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def index(self, bc):
|
def index(self, bc):
|
||||||
self._data.index(bc)
|
self._data.index(bc)
|
||||||
|
|
||||||
def get_i(self, index):
|
def get_i(self, index):
|
||||||
return self.data[index]
|
if len(self._data) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self._data[index]
|
||||||
|
|
||||||
def get_range(self, _range):
|
def get_range(self, _range):
|
||||||
lst = []
|
lst = []
|
||||||
@@ -329,10 +594,10 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
return lst
|
return lst
|
||||||
|
|
||||||
def _set_i_c_v(self, index, column, value):
|
def _set_i_c_v(self, index, column, value):
|
||||||
v = list(self._data[index])
|
v = self._data[index]
|
||||||
v[column] = self._types[column](value)
|
v[column] = self._types[column](value)
|
||||||
self._data[index] = tuple(v)
|
self._data[index] = v
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def set_i_0(self, index: int, value):
|
def set_i_0(self, index: int, value):
|
||||||
self._set_i_c_v(index, 0, value)
|
self._set_i_c_v(index, 0, value)
|
||||||
@@ -364,14 +629,14 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
next = index - 1
|
next = index - 1
|
||||||
d = self._data
|
d = self._data
|
||||||
d[index], d[next] = d[next], d[index]
|
d[index], d[next] = d[next], d[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def move_down(self, index):
|
def move_down(self, index):
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
d = self._data
|
d = self._data
|
||||||
d[index], d[prev] = d[prev], d[index]
|
d[index], d[prev] = d[prev], d[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def reach(self, river):
|
def reach(self, river):
|
||||||
r = []
|
r = []
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# BoundaryConditionList.py -- Pamhyr
|
# BoundaryConditionList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelListWithTab
|
from Model.Tools.PamhyrListExt import PamhyrModelListWithTab
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
||||||
@@ -41,9 +41,6 @@ class BoundaryConditionList(PamhyrModelListWithTab):
|
|||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = cls(status=data['status'])
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
if data is None:
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
for tab in new._tabs:
|
for tab in new._tabs:
|
||||||
data["tab"] = tab
|
data["tab"] = tab
|
||||||
new._tabs[tab] = BoundaryCondition._db_load(
|
new._tabs[tab] = BoundaryCondition._db_load(
|
||||||
@@ -53,10 +50,10 @@ class BoundaryConditionList(PamhyrModelListWithTab):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM boundary_condition")
|
execute(
|
||||||
|
"DELETE FROM boundary_condition " +
|
||||||
if data is None:
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
data = {}
|
)
|
||||||
|
|
||||||
for tab in self._tabs:
|
for tab in self._tabs:
|
||||||
data["tab"] = tab
|
data["tab"] = tab
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# BoundaryConditionTypes.py -- Pamhyr
|
# BoundaryConditionTypes.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,8 +22,12 @@ from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
|||||||
|
|
||||||
|
|
||||||
class NotDefined(BoundaryCondition):
|
class NotDefined(BoundaryCondition):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(NotDefined, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(NotDefined, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "ND"
|
self._type = "ND"
|
||||||
self._header = ["x", "y"]
|
self._header = ["x", "y"]
|
||||||
@@ -34,9 +38,12 @@ class NotDefined(BoundaryCondition):
|
|||||||
|
|
||||||
|
|
||||||
class PonctualContribution(BoundaryCondition):
|
class PonctualContribution(BoundaryCondition):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
super(PonctualContribution, self).__init__(
|
super(PonctualContribution, self).__init__(
|
||||||
id=id, name=name, status=status)
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "PC"
|
self._type = "PC"
|
||||||
self._header = ["time", "discharge"]
|
self._header = ["time", "discharge"]
|
||||||
@@ -48,8 +55,12 @@ class PonctualContribution(BoundaryCondition):
|
|||||||
|
|
||||||
|
|
||||||
class TimeOverZ(BoundaryCondition):
|
class TimeOverZ(BoundaryCondition):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(TimeOverZ, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(TimeOverZ, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "TZ"
|
self._type = "TZ"
|
||||||
self._header = ["time", "z"]
|
self._header = ["time", "z"]
|
||||||
@@ -61,9 +72,12 @@ class TimeOverZ(BoundaryCondition):
|
|||||||
|
|
||||||
|
|
||||||
class TimeOverDischarge(BoundaryCondition):
|
class TimeOverDischarge(BoundaryCondition):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
super(TimeOverDischarge, self).__init__(
|
super(TimeOverDischarge, self).__init__(
|
||||||
id=id, name=name, status=status)
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "TD"
|
self._type = "TD"
|
||||||
self._header = ["time", "discharge"]
|
self._header = ["time", "discharge"]
|
||||||
@@ -75,8 +89,12 @@ class TimeOverDischarge(BoundaryCondition):
|
|||||||
|
|
||||||
|
|
||||||
class ZOverDischarge(BoundaryCondition):
|
class ZOverDischarge(BoundaryCondition):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(ZOverDischarge, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(ZOverDischarge, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "ZD"
|
self._type = "ZD"
|
||||||
self._header = ["z", "discharge"]
|
self._header = ["z", "discharge"]
|
||||||
@@ -92,8 +110,12 @@ class ZOverDischarge(BoundaryCondition):
|
|||||||
|
|
||||||
|
|
||||||
class Solid(BoundaryCondition):
|
class Solid(BoundaryCondition):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(Solid, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(Solid, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self.d50 = 0.002
|
self.d50 = 0.002
|
||||||
self.sigma = 1
|
self.sigma = 1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# BoundaryConditionsAdisTS.py -- Pamhyr
|
# BoundaryConditionsAdisTS.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,25 +27,193 @@ from tools import (
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class BoundaryConditionAdisTS(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
def __init__(self,
|
||||||
|
data0, data1,
|
||||||
|
id: int = -1,
|
||||||
|
types=[float, float],
|
||||||
|
status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
|
super(Data, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
self._types = types
|
||||||
|
self._data = [data0, data1]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE boundary_condition_data_adists{ext}(
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
data0 TEXT NOT NULL,
|
||||||
|
data1 TEXT NOT NULL,
|
||||||
|
bca INTEGER,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(bca) REFERENCES boundary_condition_adists(pamhyr_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 7:
|
||||||
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "boundary_condition_data_adists"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, data0, data1, bca, scenario) " +
|
||||||
|
"SELECT pamhyr_id, data0, data1, bc, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_bca_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_bca_pid(cls, execute, data):
|
||||||
|
pid_bca = data["id2pid"]["boundary_condition_adists"]
|
||||||
|
els = execute(
|
||||||
|
"SELECT pamhyr_id, bca " +
|
||||||
|
"FROM boundary_condition_data_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
bca_id = next(it)
|
||||||
|
|
||||||
|
if bca_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE boundary_condition_data_adists " +
|
||||||
|
f"SET bca = {pid_bca[bca_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
bca = data["bca"]
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, deleted, data0, data1, scenario FROM " +
|
||||||
|
"boundary_condition_data_adists " +
|
||||||
|
f"WHERE bca = {bca.id} " +
|
||||||
|
f"AND scenario = {scenario.id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
it = iter(row)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
data0 = next(it)
|
||||||
|
data1 = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
bc = cls(
|
||||||
|
data0, data1,
|
||||||
|
id=pid,
|
||||||
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
bc.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(bc)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
bca = data["bca"]
|
||||||
|
|
||||||
|
data0 = self._db_format(self._data[0])
|
||||||
|
data1 = self._db_format(self._data[1])
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"boundary_condition_data_adists(" +
|
||||||
|
"pamhyr_id, data0, data1, bca, scenario) " +
|
||||||
|
f"VALUES ({self.id}, '{data0}', {data1}, {bca.id}, " +
|
||||||
|
f"{self._status.scenario_id})"
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._types[key](self._data[key])
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self._data[key] = self._types[key](value)
|
||||||
|
|
||||||
|
|
||||||
|
class BoundaryConditionAdisTS(SQLSubModel):
|
||||||
|
_sub_classes = [Data]
|
||||||
|
|
||||||
def __init__(self, id: int = -1,
|
def __init__(self, id: int = -1,
|
||||||
pollutant: int = -1, status=None):
|
pollutant: int = -1, status=None,
|
||||||
super(BoundaryConditionAdisTS, self).__init__()
|
owner_scenario=-1):
|
||||||
|
super(BoundaryConditionAdisTS, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
self.id = BoundaryConditionAdisTS._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._type = ""
|
self._type = ""
|
||||||
self._node = None
|
self._node = None
|
||||||
self._pollutant = pollutant
|
self._pollutant = pollutant
|
||||||
@@ -53,117 +221,210 @@ class BoundaryConditionAdisTS(SQLSubModel):
|
|||||||
self._header = []
|
self._header = []
|
||||||
self._types = [self.time_convert, float]
|
self._types = [self.time_convert, float]
|
||||||
|
|
||||||
BoundaryConditionAdisTS._id_cnt = max(
|
|
||||||
BoundaryConditionAdisTS._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE boundary_condition_adists(
|
CREATE TABLE boundary_condition_adists{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
pollutant INTEGER NOT NULL,
|
pollutant INTEGER NOT NULL,
|
||||||
type TEXT NOT NULL,
|
type TEXT NOT NULL,
|
||||||
node INTEGER,
|
node INTEGER,
|
||||||
FOREIGN KEY(pollutant) REFERENCES Pollutants(id),
|
{Scenario.create_db_add_scenario()},
|
||||||
FOREIGN KEY(node) REFERENCES river_node(id)
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES Pollutants(pamhyr_id),
|
||||||
|
FOREIGN KEY(node) REFERENCES river_node(pamhyr_id)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
execute("""
|
if ext != "":
|
||||||
CREATE TABLE boundary_condition_data_adists(
|
return True
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
data0 TEXT NOT NULL,
|
|
||||||
data1 TEXT NOT NULL,
|
|
||||||
bc INTEGER,
|
|
||||||
FOREIGN KEY(bc) REFERENCES boundary_condition_adists(id)
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 7:
|
||||||
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "boundary_condition_adists"
|
||||||
|
nodes = data['id2pid']['river_node']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, pollutant, type, node, scenario) " +
|
||||||
|
"SELECT pamhyr_id, pollutant, type, node, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_node_pid(execute, table, nodes)
|
||||||
|
cls._db_update_to_0_2_0_set_pollutants_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_pollutants_pid(cls, execute, data):
|
||||||
|
pid_pol = data["id2pid"]["Pollutants"]
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, pollutant " +
|
||||||
|
"FROM boundary_condition_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
pol_id = next(it)
|
||||||
|
|
||||||
|
if pol_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE boundary_condition_adists " +
|
||||||
|
f"SET pollutant = {pid_pol[pol_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
nodes = data['nodes']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, pollutant, type, node " +
|
"SELECT pamhyr_id, deleted, pollutant, type, node, scenario " +
|
||||||
"FROM boundary_condition_adists"
|
"FROM boundary_condition_adists " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
bc = cls(
|
it = iter(row)
|
||||||
id=row[0],
|
|
||||||
pollutant=row[1],
|
|
||||||
status=data['status']
|
|
||||||
)
|
|
||||||
|
|
||||||
bc.type = row[2]
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
pollutant = next(it)
|
||||||
|
bc_type = next(it)
|
||||||
|
node = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
bc = cls(
|
||||||
|
id=pid,
|
||||||
|
pollutant=pollutant,
|
||||||
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
bc.set_as_deleted()
|
||||||
|
|
||||||
|
bc.type = bc_type
|
||||||
|
|
||||||
bc.node = None
|
bc.node = None
|
||||||
if row[3] != -1:
|
if row[3] != -1:
|
||||||
tmp = next(filter(
|
tmp = next(
|
||||||
lambda n: n.id == row[3], data["nodes"]),
|
filter(
|
||||||
None)
|
lambda n: n.id == node, nodes
|
||||||
|
),
|
||||||
|
None
|
||||||
|
)
|
||||||
if tmp is not None:
|
if tmp is not None:
|
||||||
bc.node = tmp.id
|
bc.node = tmp.id
|
||||||
else:
|
else:
|
||||||
bc.node = -1
|
bc.node = -1
|
||||||
|
|
||||||
values = execute(
|
data["bca"] = bc
|
||||||
"SELECT data0, data1 FROM " +
|
bc._data = Data._db_load(execute, data=data)
|
||||||
"boundary_condition_data_adists " +
|
|
||||||
f"WHERE bc = '{bc.id}'"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Write data
|
|
||||||
for v in values:
|
|
||||||
data0 = bc._types[0](v[0])
|
|
||||||
data1 = bc._types[1](v[1])
|
|
||||||
# Replace data at pos ind
|
|
||||||
bc._data.append((data0, data1))
|
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
new.append(bc)
|
new.append(bc)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
execute(f"DELETE FROM boundary_condition_adists WHERE id = {self.id}")
|
execute(
|
||||||
execute(f"DELETE FROM boundary_condition_data_adists" +
|
"DELETE FROM boundary_condition_adists " +
|
||||||
f" WHERE bc = {self.id}")
|
f"WHERE pamhyr_id = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id} "
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM boundary_condition_data_adists " +
|
||||||
|
f"WHERE bca = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id} "
|
||||||
|
)
|
||||||
|
|
||||||
node = -1
|
node = -1
|
||||||
if self._node is not None:
|
if self._node is not None:
|
||||||
node = self._node
|
node = self._node
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"boundary_condition_adists(id, pollutant, type, node) " +
|
"boundary_condition_adists(" +
|
||||||
|
"pamhyr_id, deleted, pollutant, type, " +
|
||||||
|
"node, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {self._pollutant}, " +
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"'{self._db_format(self._type)}', {node}" +
|
f"{self._pollutant}, " +
|
||||||
|
f"'{self._db_format(self._type)}', {node}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
|
data["bca"] = self
|
||||||
|
|
||||||
|
ind = 0
|
||||||
for d in self._data:
|
for d in self._data:
|
||||||
data0 = self._db_format(str(d[0]))
|
data["ind"] = ind
|
||||||
data1 = self._db_format(str(d[1]))
|
|
||||||
|
|
||||||
sql = (
|
d._db_save(execute, data)
|
||||||
"INSERT INTO " +
|
|
||||||
"boundary_condition_data_adists(data0, data1, bc) " +
|
ind += 1
|
||||||
f"VALUES ('{data0}', {data1}, {self.id})"
|
|
||||||
)
|
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self._data)
|
||||||
|
|
||||||
@@ -222,3 +483,82 @@ class BoundaryConditionAdisTS(SQLSubModel):
|
|||||||
@property
|
@property
|
||||||
def data(self):
|
def data(self):
|
||||||
return self._data.copy()
|
return self._data.copy()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _default_0(self):
|
||||||
|
return self._types[0](0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _default_1(self):
|
||||||
|
return self._types[1](0.0)
|
||||||
|
|
||||||
|
def new_from_data(self, header, data):
|
||||||
|
new_0 = self._default_0
|
||||||
|
new_1 = self._default_1
|
||||||
|
|
||||||
|
if len(header) != 0:
|
||||||
|
for i in [0, 1]:
|
||||||
|
for j in range(len(header)):
|
||||||
|
if self._header[i] == header[j]:
|
||||||
|
if i == 0:
|
||||||
|
new_0 = self._types[i](data[j].replace(",", "."))
|
||||||
|
else:
|
||||||
|
new_1 = self._types[i](data[j].replace(",", "."))
|
||||||
|
else:
|
||||||
|
new_0 = self._types[0](data[0].replace(",", "."))
|
||||||
|
new_1 = self._types[1](data[1].replace(",", "."))
|
||||||
|
|
||||||
|
return (new_0, new_1)
|
||||||
|
|
||||||
|
def add(self, index: int):
|
||||||
|
value = (self._default_0, self._default_1)
|
||||||
|
self._data.insert(index, value)
|
||||||
|
self._status.modified()
|
||||||
|
return value
|
||||||
|
|
||||||
|
def insert(self, index: int, value):
|
||||||
|
self._data.insert(index, value)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
self._data = list(
|
||||||
|
map(
|
||||||
|
lambda e: e[1],
|
||||||
|
filter(
|
||||||
|
lambda e: e[0] not in indexes,
|
||||||
|
enumerate(self.data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def sort(self, _reverse=False, key=None):
|
||||||
|
if key is None:
|
||||||
|
self._data.sort(reverse=_reverse)
|
||||||
|
else:
|
||||||
|
self._data.sort(reverse=_reverse, key=key)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def index(self, bc):
|
||||||
|
self._data.index(bc)
|
||||||
|
|
||||||
|
def get_i(self, index):
|
||||||
|
return self.data[index]
|
||||||
|
|
||||||
|
def get_range(self, _range):
|
||||||
|
lst = []
|
||||||
|
for r in _range:
|
||||||
|
lst.append(r)
|
||||||
|
return lst
|
||||||
|
|
||||||
|
def _set_i_c_v(self, index, column, value):
|
||||||
|
v = list(self._data[index])
|
||||||
|
v[column] = self._types[column](value)
|
||||||
|
self._data[index] = tuple(v)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def set_i_0(self, index: int, value):
|
||||||
|
self._set_i_c_v(index, 0, value)
|
||||||
|
|
||||||
|
def set_i_1(self, index: int, value):
|
||||||
|
self._set_i_c_v(index, 1, value)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# BoundaryConditionsAdisTSList.py -- Pamhyr
|
# BoundaryConditionsAdisTSList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS \
|
from Model.BoundaryConditionsAdisTS.BoundaryConditionAdisTS \
|
||||||
@@ -45,14 +45,20 @@ class BoundaryConditionsAdisTSList(PamhyrModelList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM boundary_condition_adists")
|
execute(
|
||||||
execute("DELETE FROM boundary_condition_data_adists")
|
"DELETE FROM boundary_condition_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM boundary_condition_data_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
for bc in self._lst:
|
for bca in self._lst:
|
||||||
bc._db_save(execute, data=data)
|
bca._db_save(execute, data=data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# D90AdisTS.py -- Pamhyr
|
# D90AdisTS.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,6 +23,7 @@ from tools import trace, timer, old_pamhyr_date_to_timestamp
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
from Model.D90AdisTS.D90AdisTSSpec import D90AdisTSSpec
|
from Model.D90AdisTS.D90AdisTSSpec import D90AdisTSSpec
|
||||||
|
|
||||||
@@ -33,107 +34,162 @@ class D90AdisTS(SQLSubModel):
|
|||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
D90AdisTSSpec,
|
D90AdisTSSpec,
|
||||||
]
|
]
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "default",
|
def __init__(self, id: int = -1, name: str = "default",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(D90AdisTS, self).__init__()
|
super(D90AdisTS, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
self.id = D90AdisTS._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._d90 = None
|
self._d90 = None
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
D90AdisTS._id_cnt = max(
|
|
||||||
D90AdisTS._id_cnt + 1,
|
|
||||||
self.id
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE d90_adists(
|
CREATE TABLE d90_adists{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
name TEXT NOT NULL,
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
d90 REAL NOT NULL,
|
name TEXT NOT NULL,
|
||||||
enabled BOOLEAN NOT NULL
|
d90 REAL NOT NULL,
|
||||||
)
|
enabled BOOLEAN NOT NULL,
|
||||||
""")
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()}
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
if ext != "":
|
||||||
|
return True
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == 0 and minor < 1:
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "d90_adists"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, name, d90, enabled, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, d90, enabled, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name, d90, enabled " +
|
"SELECT pamhyr_id, deleted, name, d90, enabled, scenario " +
|
||||||
"FROM d90_adists"
|
"FROM d90_adists " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
d90_id = row[0]
|
it = iter(row)
|
||||||
name = row[1]
|
|
||||||
d90 = row[2]
|
|
||||||
enabled = (row[3] == 1)
|
|
||||||
|
|
||||||
D90 = cls(
|
pid = next(it)
|
||||||
id=d90_id,
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
value_d90 = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
d90 = cls(
|
||||||
|
id=pid,
|
||||||
name=name,
|
name=name,
|
||||||
status=data['status']
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
d90.set_as_deleted()
|
||||||
|
|
||||||
D90.d90 = d90
|
d90.d90 = value_d90
|
||||||
D90.enabled = enabled
|
d90.enabled = enabled
|
||||||
|
|
||||||
data['d90_default_id'] = d90_id
|
data['d90_default_id'] = pid
|
||||||
D90._data = D90AdisTSSpec._db_load(execute, data)
|
d90._data = D90AdisTSSpec._db_load(execute, data)
|
||||||
|
|
||||||
new.append(D90)
|
loaded.add(pid)
|
||||||
|
new.append(d90)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute(f"DELETE FROM d90_adists WHERE id = {self.id}")
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"DELETE FROM d90_adists " +
|
||||||
|
f"WHERE pamhyr_id = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id} "
|
||||||
|
)
|
||||||
|
|
||||||
d90 = -1.
|
d90 = -1.
|
||||||
if self.d90 is not None:
|
if self.d90 is not None:
|
||||||
d90 = self.d90
|
d90 = self.d90
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"d90_adists(" +
|
"d90_adists(" +
|
||||||
"id, name, d90, enabled" +
|
"pamhyr_id, deleted, " +
|
||||||
|
"name, d90, enabled, scenario" +
|
||||||
") " +
|
") " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._db_format(self._name)}', " +
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"{d90}, {self._enabled}" +
|
f"'{self._db_format(self._name)}', " +
|
||||||
|
f"{d90}, {self._enabled}, {self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
|
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
data['d90_default_id'] = self.id
|
data['d90_default_id'] = self.id
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM d90_spec " +
|
"DELETE FROM d90_adists_spec " +
|
||||||
f"WHERE d90_default = {self.id}"
|
f"WHERE d90_default = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id} "
|
||||||
)
|
)
|
||||||
|
|
||||||
for d90_spec in self._data:
|
for d90_spec in self._data:
|
||||||
@@ -141,6 +197,16 @@ class D90AdisTS(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self._data)
|
||||||
|
|
||||||
@@ -151,7 +217,7 @@ class D90AdisTS(SQLSubModel):
|
|||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def d90(self):
|
def d90(self):
|
||||||
@@ -160,7 +226,7 @@ class D90AdisTS(SQLSubModel):
|
|||||||
@d90.setter
|
@d90.setter
|
||||||
def d90(self, d90):
|
def d90(self, d90):
|
||||||
self._d90 = d90
|
self._d90 = d90
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
@@ -169,28 +235,45 @@ class D90AdisTS(SQLSubModel):
|
|||||||
@enabled.setter
|
@enabled.setter
|
||||||
def enabled(self, enabled):
|
def enabled(self, enabled):
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = D90AdisTSSpec(status=self._status)
|
n = D90AdisTSSpec(status=self._status)
|
||||||
self._data.insert(index, n)
|
self._data.insert(index, n)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def delete(self, data):
|
def delete(self, data):
|
||||||
self._data = list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda x: x not in data,
|
lambda x: x.set_as_deleted(),
|
||||||
self._data
|
data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
def delete_i(self, indexes):
|
||||||
for ind in indexes:
|
list(
|
||||||
del self._data[ind]
|
map(
|
||||||
self._status.modified()
|
lambda e: e[1].set_as_deleted(),
|
||||||
|
filter(
|
||||||
|
lambda e: e[0] in indexes,
|
||||||
|
enumerate(self._data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def insert(self, index, data):
|
def insert(self, index, data):
|
||||||
self._data.insert(index, data)
|
if data in self._data:
|
||||||
self._status.modified()
|
self.undelete([data])
|
||||||
|
else:
|
||||||
|
self._data.insert(index, data)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
def undelete(self, lst):
|
||||||
|
for x in lst:
|
||||||
|
x.set_as_not_deleted()
|
||||||
|
|
||||||
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# D90AdisTSList.py -- Pamhyr
|
# D90AdisTSList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.D90AdisTS.D90AdisTS import D90AdisTS
|
from Model.D90AdisTS.D90AdisTS import D90AdisTS
|
||||||
|
|
||||||
|
|
||||||
@@ -42,7 +42,10 @@ class D90AdisTSList(PamhyrModelList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM d90_adists")
|
execute(
|
||||||
|
"DELETE FROM d90_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# D90AdisTSSpec.py -- Pamhyr
|
# D90AdisTSSpec.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,25 +22,21 @@ from tools import trace, timer
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class D90AdisTSSpec(SQLSubModel):
|
class D90AdisTSSpec(SQLSubModel):
|
||||||
_sub_classes = [
|
_sub_classes = []
|
||||||
]
|
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(D90AdisTSSpec, self).__init__()
|
super(D90AdisTSSpec, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
self._status = status
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
if id == -1:
|
|
||||||
self.id = D90AdisTSSpec._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name_section = name
|
self._name_section = name
|
||||||
self._reach = None
|
self._reach = None
|
||||||
@@ -49,62 +45,129 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
self._d90 = None
|
self._d90 = None
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
|
|
||||||
D90AdisTSSpec._id_cnt = max(D90AdisTSSpec._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE d90_spec(
|
CREATE TABLE d90_adists_spec{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
d90_default INTEGER NOT NULL,
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
d90_default INTEGER NOT NULL,
|
||||||
reach INTEGER NOT NULL,
|
name TEXT NOT NULL,
|
||||||
start_rk REAL NOT NULL,
|
reach INTEGER NOT NULL,
|
||||||
end_rk REAL NOT NULL,
|
start_rk REAL NOT NULL,
|
||||||
d90 REAL NOT NULL,
|
end_rk REAL NOT NULL,
|
||||||
enabled BOOLEAN NOT NULL,
|
d90 REAL NOT NULL,
|
||||||
FOREIGN KEY(d90_default) REFERENCES d90_adists(id),
|
enabled BOOLEAN NOT NULL,
|
||||||
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
)
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
""")
|
FOREIGN KEY(d90_default) REFERENCES d90_adists(pamhyr_id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
if major == 0 and minor < 1:
|
if major == 0 and minor < 1:
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "d90_spec"
|
||||||
|
table_new = "d90_adists_spec"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table_new}_tmp " +
|
||||||
|
"(pamhyr_id, name, d90, enabled, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, d90, enabled, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table_new}_tmp RENAME TO {table_new}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_d90_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_d90_pid(cls, execute, data):
|
||||||
|
pid_d90 = data["id2pid"]["d90_adists"]
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, d90 FROM d90_adists_spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
d90_id = next(it)
|
||||||
|
|
||||||
|
if d90_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE d90_adists_spec" +
|
||||||
|
f"SET d90 = {pid_d90[d90_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, d90_default, name, reach, start_rk, end_rk, " +
|
"SELECT pamhyr_id, deleted, " +
|
||||||
"d90, enabled " +
|
f"name, reach, start_rk, end_rk, " +
|
||||||
"FROM d90_spec " +
|
"d90, enabled, scenario " +
|
||||||
f"WHERE d90_default = {data['d90_default_id']} "
|
"FROM d90_adists_spec " +
|
||||||
|
f"WHERE d90_default = {data['d90_default_id']} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
name = row[2]
|
|
||||||
reach = row[3]
|
pid = next(it)
|
||||||
start_rk = row[4]
|
deleted = (next(it) == 1)
|
||||||
end_rk = row[5]
|
name = next(it)
|
||||||
d90 = row[6]
|
reach = next(it)
|
||||||
enabled = (row[7] == 1)
|
start_rk = next(it)
|
||||||
|
end_rk = next(it)
|
||||||
|
d90 = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
new_spec = cls(
|
new_spec = cls(
|
||||||
id=id,
|
id=pid,
|
||||||
name=name,
|
name=name,
|
||||||
status=data['status']
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
new_spec.is_deleted()
|
||||||
|
|
||||||
new_spec.reach = reach
|
new_spec.reach = reach
|
||||||
new_spec.start_rk = start_rk
|
new_spec.start_rk = start_rk
|
||||||
@@ -112,29 +175,36 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
new_spec.d90 = d90
|
new_spec.d90 = d90
|
||||||
new_spec.enabled = enabled
|
new_spec.enabled = enabled
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
new.append(new_spec)
|
new.append(new_spec)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
d90_default = data['d90_default_id']
|
d90_default = data['d90_default_id']
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"d90_spec(id, d90_default, name, reach, " +
|
"d90_adists_spec(pamhyr_id, deleted, " +
|
||||||
"start_rk, end_rk, d90, enabled) " +
|
"d90_default, name, reach, " +
|
||||||
|
"start_rk, end_rk, d90, enabled, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, " +
|
f"{self.id}, {self._db_format(self.is_deleted())}" +
|
||||||
f"{d90_default}, " +
|
f"{d90_default}, " +
|
||||||
f"'{self._db_format(self._name_section)}', " +
|
f"'{self._db_format(self._name_section)}', " +
|
||||||
f"{self._reach}, " +
|
f"{self._reach}, " +
|
||||||
f"{self._start_rk}, " +
|
f"{self._start_rk}, {self._end_rk}, " +
|
||||||
f"{self._end_rk}, " +
|
f"{self._d90}, {self._enabled}" +
|
||||||
f"{self._d90}, " +
|
f"{self._status.scenario_id}" +
|
||||||
f"{self._enabled}" +
|
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -145,7 +215,7 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name_section = name
|
self._name_section = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
@@ -154,7 +224,7 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
@reach.setter
|
@reach.setter
|
||||||
def reach(self, reach):
|
def reach(self, reach):
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def start_rk(self):
|
def start_rk(self):
|
||||||
@@ -163,7 +233,7 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
@start_rk.setter
|
@start_rk.setter
|
||||||
def start_rk(self, start_rk):
|
def start_rk(self, start_rk):
|
||||||
self._start_rk = start_rk
|
self._start_rk = start_rk
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def end_rk(self):
|
def end_rk(self):
|
||||||
@@ -172,7 +242,7 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
@end_rk.setter
|
@end_rk.setter
|
||||||
def end_rk(self, end_rk):
|
def end_rk(self, end_rk):
|
||||||
self._end_rk = end_rk
|
self._end_rk = end_rk
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def d90(self):
|
def d90(self):
|
||||||
@@ -181,7 +251,7 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
@d90.setter
|
@d90.setter
|
||||||
def d90(self, d90):
|
def d90(self, d90):
|
||||||
self._d90 = d90
|
self._d90 = d90
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
@@ -190,4 +260,4 @@ class D90AdisTSSpec(SQLSubModel):
|
|||||||
@enabled.setter
|
@enabled.setter
|
||||||
def enabled(self, enabled):
|
def enabled(self, enabled):
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._status.modified()
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# DIFAdisTS.py -- Pamhyr
|
# DIFAdisTS.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,6 +23,7 @@ from tools import trace, timer, old_pamhyr_date_to_timestamp
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
from Model.DIFAdisTS.DIFAdisTSSpec import DIFAdisTSSpec
|
from Model.DIFAdisTS.DIFAdisTSSpec import DIFAdisTSSpec
|
||||||
|
|
||||||
@@ -33,19 +34,16 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
DIFAdisTSSpec,
|
DIFAdisTSSpec,
|
||||||
]
|
]
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "default",
|
def __init__(self, id: int = -1, name: str = "default",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(DIFAdisTS, self).__init__()
|
super(DIFAdisTS, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
self.id = DIFAdisTS._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._method = None
|
self._method = None
|
||||||
self._dif = None
|
self._dif = None
|
||||||
@@ -55,76 +53,129 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
self._types = ["iwasa", "fisher", "elder", "constante", "generique"]
|
self._types = ["iwasa", "fisher", "elder", "constante", "generique"]
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
DIFAdisTS._id_cnt = max(
|
|
||||||
DIFAdisTS._id_cnt + 1,
|
|
||||||
self.id
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE dif_adists(
|
CREATE TABLE dif_adists{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
method TEXT NOT NULL,
|
method TEXT NOT NULL,
|
||||||
dif REAL NOT NULL,
|
dif REAL NOT NULL,
|
||||||
b REAL,
|
b REAL,
|
||||||
c REAL,
|
c REAL,
|
||||||
enabled BOOLEAN NOT NULL
|
enabled BOOLEAN NOT NULL,
|
||||||
)
|
{Scenario.create_db_add_scenario()},
|
||||||
""")
|
{Scenario.create_db_add_scenario_fk()}
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
if ext != "":
|
||||||
|
return True
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == 0 and minor < 1:
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "dif_adists"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, name, method, dif, b, c, enabled, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, method, dif, b, c, enabled, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name, method, dif, b, c, enabled " +
|
"SELECT pamhyr_id, name, method, dif, b, c, enabled, scenario " +
|
||||||
"FROM dif_adists"
|
"FROM dif_adists " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
dif_id = row[0]
|
it = iter(row)
|
||||||
name = row[1]
|
|
||||||
method = row[2]
|
|
||||||
dif = row[3]
|
|
||||||
b = row[4]
|
|
||||||
c = row[5]
|
|
||||||
enabled = (row[6] == 1)
|
|
||||||
|
|
||||||
DIF = cls(
|
pid = next(it)
|
||||||
id=dif_id,
|
name = next(it)
|
||||||
|
method = next(it)
|
||||||
|
dif = next(it)
|
||||||
|
b = next(it)
|
||||||
|
c = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
dif = cls(
|
||||||
|
id=pid,
|
||||||
name=name,
|
name=name,
|
||||||
status=data['status']
|
status=status,
|
||||||
|
owner_scenario=owner_scenario,
|
||||||
)
|
)
|
||||||
|
|
||||||
DIF.method = method
|
dif.method = method
|
||||||
DIF.dif = dif
|
dif.dif = dif
|
||||||
DIF.b = b
|
dif.b = b
|
||||||
DIF.c = c
|
dif.c = c
|
||||||
DIF.enabled = enabled
|
dif.enabled = enabled
|
||||||
|
|
||||||
data['dif_default_id'] = dif_id
|
data['dif_default_id'] = pid
|
||||||
DIF._data = DIFAdisTSSpec._db_load(execute, data)
|
dif._data = DIFAdisTSSpec._db_load(execute, data)
|
||||||
|
|
||||||
new.append(DIF)
|
loaded.add(pid)
|
||||||
|
new.append(dif)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute(f"DELETE FROM dif_adists WHERE id = {self.id}")
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"DELETE FROM dif_adists " +
|
||||||
|
f"WHERE pamhyr_id = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id} "
|
||||||
|
)
|
||||||
|
|
||||||
method = ""
|
method = ""
|
||||||
if self.method is not None:
|
if self.method is not None:
|
||||||
@@ -145,12 +196,13 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"dif_adists(" +
|
"dif_adists(" +
|
||||||
"id, name, method, dif, b, c, enabled" +
|
"pamhyr_id, name, method, dif, b, c, enabled, scenario" +
|
||||||
") " +
|
") " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._db_format(self._name)}', " +
|
f"{self.id}, '{self._db_format(self._name)}', " +
|
||||||
f"'{self._db_format(self._method)}', " +
|
f"'{self._db_format(self._method)}', " +
|
||||||
f"{dif}, {b}, {c}, {self._enabled}" +
|
f"{dif.id}, {b}, {c}, {self._enabled}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -158,8 +210,9 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
|
|
||||||
data['dif_default_id'] = self.id
|
data['dif_default_id'] = self.id
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM dif_spec " +
|
"DELETE FROM dif_adists_spec " +
|
||||||
f"WHERE dif_default = {self.id}"
|
f"WHERE dif_default = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id} "
|
||||||
)
|
)
|
||||||
|
|
||||||
for dif_spec in self._data:
|
for dif_spec in self._data:
|
||||||
@@ -167,6 +220,16 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self._data)
|
||||||
|
|
||||||
@@ -177,7 +240,7 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def method(self):
|
def method(self):
|
||||||
@@ -186,7 +249,7 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
@method.setter
|
@method.setter
|
||||||
def method(self, method):
|
def method(self, method):
|
||||||
self._method = method
|
self._method = method
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def types(self):
|
def types(self):
|
||||||
@@ -199,7 +262,7 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
@dif.setter
|
@dif.setter
|
||||||
def dif(self, dif):
|
def dif(self, dif):
|
||||||
self._dif = dif
|
self._dif = dif
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def b(self):
|
def b(self):
|
||||||
@@ -208,7 +271,7 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
@b.setter
|
@b.setter
|
||||||
def b(self, b):
|
def b(self, b):
|
||||||
self._b = b
|
self._b = b
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def c(self):
|
def c(self):
|
||||||
@@ -217,7 +280,7 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
@c.setter
|
@c.setter
|
||||||
def c(self, c):
|
def c(self, c):
|
||||||
self._c = c
|
self._c = c
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
@@ -226,28 +289,45 @@ class DIFAdisTS(SQLSubModel):
|
|||||||
@enabled.setter
|
@enabled.setter
|
||||||
def enabled(self, enabled):
|
def enabled(self, enabled):
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = DIFAdisTSSpec(status=self._status)
|
n = DIFAdisTSSpec(status=self._status)
|
||||||
self._data.insert(index, n)
|
self._data.insert(index, n)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def delete(self, data):
|
def delete(self, data):
|
||||||
self._data = list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda x: x not in data,
|
lambda x: x.set_as_deleted(),
|
||||||
self._data
|
data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
def delete_i(self, indexes):
|
||||||
for ind in indexes:
|
list(
|
||||||
del self._data[ind]
|
map(
|
||||||
self._status.modified()
|
lambda e: e[1].set_as_deleted(),
|
||||||
|
filter(
|
||||||
|
lambda e: e[0] in indexes,
|
||||||
|
enumerate(self._data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def insert(self, index, data):
|
def insert(self, index, data):
|
||||||
self._data.insert(index, data)
|
if data in self._data:
|
||||||
self._status.modified()
|
self.undelete([data])
|
||||||
|
else:
|
||||||
|
self._data.insert(index, data)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
def undelete(self, lst):
|
||||||
|
for x in lst:
|
||||||
|
x.set_as_not_deleted()
|
||||||
|
|
||||||
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# DIFAdisTSList.py -- Pamhyr
|
# DIFAdisTSList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.DIFAdisTS.DIFAdisTS import DIFAdisTS
|
from Model.DIFAdisTS.DIFAdisTS import DIFAdisTS
|
||||||
|
|
||||||
|
|
||||||
@@ -42,7 +42,10 @@ class DIFAdisTSList(PamhyrModelList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM dif_adists")
|
execute(
|
||||||
|
"DELETE FROM dif_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# DIFAdisTSSpec.py -- Pamhyr
|
# DIFAdisTSSpec.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,6 +22,7 @@ from tools import trace, timer
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@@ -54,63 +55,137 @@ class DIFAdisTSSpec(SQLSubModel):
|
|||||||
DIFAdisTSSpec._id_cnt = max(DIFAdisTSSpec._id_cnt + 1, self.id)
|
DIFAdisTSSpec._id_cnt = max(DIFAdisTSSpec._id_cnt + 1, self.id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE dif_spec(
|
CREATE TABLE dif_adists_spec{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
dif_default INTEGER NOT NULL,
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
method TEXT NOT NULL,
|
dif_default INTEGER NOT NULL,
|
||||||
reach INTEGER NOT NULL,
|
method TEXT NOT NULL,
|
||||||
start_rk REAL NOT NULL,
|
reach INTEGER NOT NULL,
|
||||||
end_rk REAL NOT NULL,
|
start_rk REAL NOT NULL,
|
||||||
dif REAL NOT NULL,
|
end_rk REAL NOT NULL,
|
||||||
b REAL,
|
dif REAL NOT NULL,
|
||||||
c REAL,
|
b REAL,
|
||||||
enabled BOOLEAN NOT NULL,
|
c REAL,
|
||||||
FOREIGN KEY(dif_default) REFERENCES dif_adists(id),
|
enabled BOOLEAN NOT NULL,
|
||||||
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
)
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
""")
|
FOREIGN KEY(dif_default) REFERENCES dif_adists(id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
if major == 0 and minor < 1:
|
if major == 0 and minor < 1:
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "dif_spec"
|
||||||
|
table_new = "dif_adists_spec"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table_new}_tmp " +
|
||||||
|
"(pamhyr_id, dif_default, " +
|
||||||
|
"method, reach, start_rk, end_rk, " +
|
||||||
|
"dif, b, c, scenario) " +
|
||||||
|
"SELECT pamhyr_id, dif_default, " +
|
||||||
|
"method, reach, start_rk, end_rk, " +
|
||||||
|
"dif, b, c, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table_new}_tmp RENAME TO {table_new}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table_new, reachs)
|
||||||
|
cls._db_update_to_0_2_0_set_dif_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_dif_pid(cls, execute, data):
|
||||||
|
pid_dif = data["id2pid"]["dif_adists"]
|
||||||
|
els = execute(
|
||||||
|
"SELECT pamhyr_id, dif_default FROM dif_adists_spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
dif_id = next(it)
|
||||||
|
|
||||||
|
if dif_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE dif_adists_spec" +
|
||||||
|
f"SET dif_default = {pid_dif[dif_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, dif_default, method, reach, start_rk, end_rk, " +
|
"SELECT pamhyr_id, deleted, method, reach, start_rk, end_rk, " +
|
||||||
"dif, b, c, enabled " +
|
"dif, b, c, enabled, scenario " +
|
||||||
"FROM dif_spec " +
|
"FROM dif_adists_spec " +
|
||||||
f"WHERE dif_default = {data['dif_default_id']} "
|
f"WHERE dif_default = {data['dif_default_id']} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
method = row[2]
|
|
||||||
reach = row[3]
|
id = next(it)
|
||||||
start_rk = row[4]
|
deleted = (next(it) == 1)
|
||||||
end_rk = row[5]
|
method = next(it)
|
||||||
dif = row[6]
|
reach = next(it)
|
||||||
b = row[7]
|
start_rk = next(it)
|
||||||
c = row[8]
|
end_rk = next(it)
|
||||||
enabled = (row[9] == 1)
|
dif = next(it)
|
||||||
|
b = next(it)
|
||||||
|
c = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
new_spec = cls(
|
new_spec = cls(
|
||||||
id=id,
|
id=id,
|
||||||
method=method,
|
method=method,
|
||||||
status=data['status']
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
new_spec.set_as_deleted()
|
||||||
|
|
||||||
new_spec.reach = reach
|
new_spec.reach = reach
|
||||||
new_spec.start_rk = start_rk
|
new_spec.start_rk = start_rk
|
||||||
@@ -120,31 +195,37 @@ class DIFAdisTSSpec(SQLSubModel):
|
|||||||
new_spec.c = c
|
new_spec.c = c
|
||||||
new_spec.enabled = enabled
|
new_spec.enabled = enabled
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
new.append(new_spec)
|
new.append(new_spec)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
dif_default = data['dif_default_id']
|
dif_default = data['dif_default_id']
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"dif_spec(id, dif_default, method, reach, " +
|
"dif_adists_spec(pamhyr_id, deleted, " +
|
||||||
"start_rk, end_rk, dif, b, c, enabled) " +
|
"dif_default, method, reach, " +
|
||||||
|
"start_rk, end_rk, dif, b, c, enabled, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, " +
|
f"{self.id}, {self._db_format(self.is_deleted())}" +
|
||||||
f"{dif_default}, " +
|
f"{dif_default}, " +
|
||||||
f"'{self._db_format(self._method)}', " +
|
f"'{self._db_format(self._method)}', " +
|
||||||
f"{self._reach}, " +
|
f"{self._reach}, " +
|
||||||
f"{self._start_rk}, " +
|
f"{self._start_rk}, {self._end_rk}, " +
|
||||||
f"{self._end_rk}, " +
|
f"{self._dif}, {self._b}, {self._c}, " +
|
||||||
f"{self._dif}, " +
|
|
||||||
f"{self._b}, " +
|
|
||||||
f"{self._c}, " +
|
|
||||||
f"{self._enabled}" +
|
f"{self._enabled}" +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# Except.py -- Pamhyr model exceptions
|
# Except.py -- Pamhyr model exceptions
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+187
-84
@@ -1,5 +1,5 @@
|
|||||||
# Friction.py -- Pamhyr
|
# Friction.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,6 +21,7 @@ import logging
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
from numpy import interp
|
from numpy import interp
|
||||||
|
|
||||||
@@ -28,49 +29,49 @@ logger = logging.getLogger()
|
|||||||
|
|
||||||
|
|
||||||
class Friction(SQLSubModel):
|
class Friction(SQLSubModel):
|
||||||
_id_cnt = 0
|
def __init__(self, id: int = -1,
|
||||||
|
reach=None,
|
||||||
|
status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
|
super(Friction, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
self._reach = reach
|
||||||
status=None):
|
|
||||||
super(Friction, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
self.id = Friction._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
Friction._id_cnt = max(self.id, Friction._id_cnt+1)
|
|
||||||
|
|
||||||
self._name = name
|
|
||||||
self._edge = None
|
|
||||||
self._begin_rk = 0.0
|
self._begin_rk = 0.0
|
||||||
self._end_rk = 0.0
|
self._end_rk = 0.0
|
||||||
self._begin_strickler = None
|
self._begin_strickler = None
|
||||||
self._end_strickler = None
|
self._end_strickler = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE friction(
|
CREATE TABLE friction{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
ind INTEGER NOT NULL,
|
ind INTEGER NOT NULL,
|
||||||
begin_rk REAL NOT NULL,
|
begin_rk REAL NOT NULL,
|
||||||
end_rk REAL NOT NULL,
|
end_rk REAL NOT NULL,
|
||||||
reach INTEGER NOT NULL,
|
reach INTEGER NOT NULL,
|
||||||
begin_strickler INTEGER NOT NULL,
|
begin_strickler INTEGER NOT NULL,
|
||||||
end_strickler INTEGER NOT NULL,
|
end_strickler INTEGER NOT NULL,
|
||||||
FOREIGN KEY(reach) REFERENCES river_reach(id),
|
{Scenario.create_db_add_scenario()},
|
||||||
FOREIGN KEY(begin_strickler) REFERENCES stricklers(id),
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
FOREIGN KEY(end_strickler) REFERENCES stricklers(id)
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
|
||||||
|
FOREIGN KEY(begin_strickler) REFERENCES stricklers(pamhyr_id),
|
||||||
|
FOREIGN KEY(end_strickler) REFERENCES stricklers(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return True
|
if ext != "":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 11:
|
if int(release) < 11:
|
||||||
@@ -78,49 +79,164 @@ class Friction(SQLSubModel):
|
|||||||
"RENAME COLUMN begin_kp TO begin_rk")
|
"RENAME COLUMN begin_kp TO begin_rk")
|
||||||
execute("ALTER TABLE friction RENAME COLUMN end_kp TO end_rk")
|
execute("ALTER TABLE friction RENAME COLUMN end_kp TO end_rk")
|
||||||
|
|
||||||
return True
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE friction " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "friction"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
stricklers = data['id2pid']['stricklers']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, ind, begin_rk, end_rk, reach, " +
|
||||||
|
"begin_strickler, end_strickler, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ind, begin_rk, end_rk, reach, " +
|
||||||
|
"begin_strickler, end_strickler, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table, reachs)
|
||||||
|
cls._db_update_to_0_2_0_set_stricklers_pid(execute, table, stricklers)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_stricklers_pid(cls, execute, table,
|
||||||
|
stricklers):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, begin_strickler, end_strickler FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
b_s_id = next(it)
|
||||||
|
e_s_id = next(it)
|
||||||
|
|
||||||
|
b_s = stricklers[b_s_id] if b_s_id != -1 else -1
|
||||||
|
e_s = stricklers[e_s_id] if e_s_id != -1 else -1
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET begin_strickler = {b_s}, " +
|
||||||
|
f"end_strickler = {e_s} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
reach = data["reach"]
|
reach = data["reach"]
|
||||||
status = data["status"]
|
|
||||||
stricklers = data["stricklers"].stricklers
|
stricklers = data["stricklers"].stricklers
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, ind, begin_rk, end_rk, " +
|
"SELECT pamhyr_id, deleted, begin_rk, end_rk, " +
|
||||||
"begin_strickler, end_strickler " +
|
"begin_strickler, end_strickler, scenario " +
|
||||||
f"FROM friction WHERE reach = {reach.id}"
|
"FROM friction " +
|
||||||
|
f"WHERE reach = {reach.pamhyr_id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
|
||||||
|
"ORDER BY ind ASC"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
ind = row[1]
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
begin_rk = next(it)
|
||||||
|
end_rk = next(it)
|
||||||
|
begin_strickler_pid = int(next(it))
|
||||||
|
end_strickler_pid = int(next(it))
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
# Get stricklers
|
# Get stricklers
|
||||||
if int(row[4]) == -1:
|
begin_strickler = None
|
||||||
bs = None
|
if begin_strickler_pid != -1:
|
||||||
else:
|
begin_strickler = next(
|
||||||
bs = next(filter(lambda s: s.id == row[4], stricklers))
|
filter(
|
||||||
|
lambda s: s.id == begin_strickler_pid,
|
||||||
|
stricklers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if int(row[5]) == -1:
|
end_strickler = None
|
||||||
es = None
|
if end_strickler_pid != -1:
|
||||||
else:
|
end_strickler = next(
|
||||||
es = next(filter(lambda s: s.id == row[5], stricklers))
|
filter(
|
||||||
|
lambda s: s.id == begin_strickler_pid,
|
||||||
|
stricklers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Create friction
|
new_friction = cls(
|
||||||
sec = cls(status=status)
|
id=pid, status=data['status'],
|
||||||
sec.edge = reach
|
owner_scenario=owner_scenario
|
||||||
sec.begin_rk = row[2]
|
)
|
||||||
sec.end_rk = row[3]
|
if deleted:
|
||||||
sec.begin_strickler = bs
|
f.set_as_deleted()
|
||||||
sec.end_strickler = es
|
|
||||||
|
|
||||||
new.append((ind, sec))
|
new_friction.reach = reach
|
||||||
|
new_friction.begin_rk = begin_rk
|
||||||
|
new_friction.end_rk = end_rk
|
||||||
|
new_friction.begin_strickler = begin_strickler
|
||||||
|
new_friction.end_strickler = begin_strickler
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(new_friction)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
def cloned_for(self, reach):
|
||||||
|
new = Friction(reach=reach, status=self._status)
|
||||||
|
|
||||||
|
new.reach = reach
|
||||||
|
new.begin_rk = self._begin_rk
|
||||||
|
new.end_rk = self._end_rk
|
||||||
|
new.begin_strickler = self._begin_strickler
|
||||||
|
new.end_strickler = self._begin_strickler
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def must_be_saved(self):
|
||||||
|
ssi = self._status.scenario_id
|
||||||
|
|
||||||
|
return (
|
||||||
|
self._begin_strickler._owner_scenario == ssi
|
||||||
|
# or self._end_strickler._owner_scenario == ssi
|
||||||
|
or super(Friction, self).must_be_saved()
|
||||||
|
)
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
b_s_id = -1
|
b_s_id = -1
|
||||||
@@ -133,47 +249,34 @@ class Friction(SQLSubModel):
|
|||||||
|
|
||||||
execute(
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"friction(id, ind, begin_rk, end_rk, " +
|
"friction(pamhyr_id, deleted, ind, begin_rk, end_rk, " +
|
||||||
"reach, begin_strickler, end_strickler) " +
|
"reach, begin_strickler, end_strickler, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {ind}, " +
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"{self._begin_rk}, {self._end_rk}, " +
|
f"{ind}, {self._begin_rk}, {self._end_rk}, " +
|
||||||
f"{self._edge.id}, " +
|
f"{self._reach.id}, {b_s_id}, {e_s_id}, " +
|
||||||
f"{b_s_id}, {e_s_id}" +
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, name):
|
|
||||||
self._name = name
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def edge(self):
|
|
||||||
return self._edge
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
return self._edge
|
return self._reach
|
||||||
|
|
||||||
@edge.setter
|
@reach.setter
|
||||||
def edge(self, edge):
|
def reach(self, reach):
|
||||||
self._edge = edge
|
self._reach = reach
|
||||||
if (edge is not None and
|
if (reach is not None and
|
||||||
self._begin_rk == 0.0 and
|
self._begin_rk == 0.0 and
|
||||||
self._end_rk == 0.0):
|
self._end_rk == 0.0):
|
||||||
self._begin_rk = self._edge.reach.get_rk_min()
|
self._begin_rk = self._reach.reach.get_rk_min()
|
||||||
self._end_rk = self._edge.reach.get_rk_max()
|
self._end_rk = self._reach.reach.get_rk_max()
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def has_edge(self):
|
def has_reach(self):
|
||||||
return self._edge is not None
|
return self._reach is not None
|
||||||
|
|
||||||
def has_coefficient(self):
|
def has_coefficient(self):
|
||||||
return (
|
return (
|
||||||
@@ -181,7 +284,7 @@ class Friction(SQLSubModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def is_full_defined(self):
|
def is_full_defined(self):
|
||||||
return self.has_edge() and self.has_coefficient()
|
return self.has_reach() and self.has_coefficient()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def begin_rk(self):
|
def begin_rk(self):
|
||||||
@@ -189,11 +292,11 @@ class Friction(SQLSubModel):
|
|||||||
|
|
||||||
@begin_rk.setter
|
@begin_rk.setter
|
||||||
def begin_rk(self, begin_rk):
|
def begin_rk(self, begin_rk):
|
||||||
if self._edge is None:
|
if self._reach is None:
|
||||||
self._begin_rk = begin_rk
|
self._begin_rk = begin_rk
|
||||||
else:
|
else:
|
||||||
_min = self._edge.reach.get_rk_min()
|
_min = self._reach.reach.get_rk_min()
|
||||||
_max = self._edge.reach.get_rk_max()
|
_max = self._reach.reach.get_rk_max()
|
||||||
|
|
||||||
if _min <= begin_rk <= _max:
|
if _min <= begin_rk <= _max:
|
||||||
self._begin_rk = begin_rk
|
self._begin_rk = begin_rk
|
||||||
@@ -206,11 +309,11 @@ class Friction(SQLSubModel):
|
|||||||
|
|
||||||
@end_rk.setter
|
@end_rk.setter
|
||||||
def end_rk(self, end_rk):
|
def end_rk(self, end_rk):
|
||||||
if self._edge is None:
|
if self._reach is None:
|
||||||
self._end_rk = end_rk
|
self._end_rk = end_rk
|
||||||
else:
|
else:
|
||||||
_min = self._edge.reach.get_rk_min()
|
_min = self._reach.reach.get_rk_min()
|
||||||
_max = self._edge.reach.get_rk_max()
|
_max = self._reach.reach.get_rk_max()
|
||||||
|
|
||||||
if _min <= end_rk <= _max:
|
if _min <= end_rk <= _max:
|
||||||
self._end_rk = end_rk
|
self._end_rk = end_rk
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# FrictionList.py -- Pamhyr
|
# FrictionList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,9 +20,10 @@ import logging
|
|||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
|
|
||||||
from Model.Friction.Friction import Friction
|
from Model.Friction.Friction import Friction
|
||||||
|
|
||||||
@@ -39,30 +40,30 @@ class FrictionList(PamhyrModelList):
|
|||||||
execute("ALTER TABLE `section` RENAME TO `friction`")
|
execute("ALTER TABLE `section` RENAME TO `friction`")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
if version == "0.0.0":
|
if version == "0.0.0":
|
||||||
logger.info(f"Update friction TABLE from {version}")
|
|
||||||
cls._db_update_0_0_1(execute, version)
|
cls._db_update_0_0_1(execute, version)
|
||||||
|
|
||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = cls(status=data['status'])
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
ilst = Friction._db_load(
|
new._lst = Friction._db_load(
|
||||||
execute, data
|
execute, data
|
||||||
)
|
)
|
||||||
|
|
||||||
new._lst = list(map(lambda x: x[1], sorted(ilst)))
|
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
frictions = self.lst
|
frictions = self.lst
|
||||||
|
|
||||||
reach = data["reach"]
|
reach = data["reach"]
|
||||||
execute(f"DELETE FROM friction WHERE reach = {reach.id}")
|
execute(
|
||||||
|
f"DELETE FROM friction WHERE reach = {reach.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
ok = True
|
ok = True
|
||||||
ind = 0
|
ind = 0
|
||||||
@@ -86,19 +87,38 @@ class FrictionList(PamhyrModelList):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def lst(self):
|
|
||||||
if not isinstance(self._lst, list):
|
|
||||||
self._lst = self._get_frictions_list()
|
|
||||||
|
|
||||||
return self._lst
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def frictions(self):
|
def frictions(self):
|
||||||
return self.lst
|
return self.lst
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, reach, index):
|
||||||
n = Friction(status=self._status)
|
n = Friction(reach=reach, status=self._status)
|
||||||
self._lst.insert(index, n)
|
self._lst.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
def _splited_for(self, reach):
|
||||||
|
new = FrictionList(status=self._status)
|
||||||
|
|
||||||
|
rk_min, rk_max = reduce(
|
||||||
|
lambda mm, p: (
|
||||||
|
min(mm[0], p.rk),
|
||||||
|
max(mm[1], p.rk)
|
||||||
|
),
|
||||||
|
reach.reach.profiles,
|
||||||
|
((999 ** 100), -(999 ** 100))
|
||||||
|
)
|
||||||
|
|
||||||
|
frictions = list(
|
||||||
|
filter(
|
||||||
|
lambda f: ((rk_min <= f.begin_rk <= rk_max) or
|
||||||
|
(rk_min <= f.end_rk <= rk_max)),
|
||||||
|
self._lst))
|
||||||
|
|
||||||
|
for ind, friction in enumerate(frictions):
|
||||||
|
n = friction.cloned_for(reach)
|
||||||
|
|
||||||
|
new._lst.insert(ind, n)
|
||||||
|
new._status.modified()
|
||||||
|
|
||||||
|
return new
|
||||||
@@ -0,0 +1,368 @@
|
|||||||
|
# GeoTIFF.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
|
try:
|
||||||
|
import rasterio
|
||||||
|
import rasterio.control
|
||||||
|
import rasterio.crs
|
||||||
|
import rasterio.sample
|
||||||
|
import rasterio.vrt
|
||||||
|
import rasterio._features
|
||||||
|
|
||||||
|
from rasterio.io import MemoryFile
|
||||||
|
_rasterio_loaded = True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Module 'rasterio' is not available: {e}")
|
||||||
|
_rasterio_loaded = False
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class GeoTIFF(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, enabled=True,
|
||||||
|
name="", description="",
|
||||||
|
path="", coordinates=None,
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
|
super(GeoTIFF, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
self._enabled = enabled
|
||||||
|
self._name = f"GeoTIFF #{self._pamhyr_id}" if name == "" else name
|
||||||
|
self._description = description
|
||||||
|
|
||||||
|
self._file_bytes = b''
|
||||||
|
if coordinates is None:
|
||||||
|
self._coordinates = {
|
||||||
|
"bottom": 0.0,
|
||||||
|
"top": 0.0,
|
||||||
|
"left": 0.0,
|
||||||
|
"right": 0.0,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
self._coordinates = coordinates
|
||||||
|
self._file_name = ""
|
||||||
|
|
||||||
|
if path != "":
|
||||||
|
self.read_file(path)
|
||||||
|
|
||||||
|
self._memfile = None
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
value = None
|
||||||
|
|
||||||
|
if key == "enabled":
|
||||||
|
value = self._enabled
|
||||||
|
elif key == "name":
|
||||||
|
value = self.name
|
||||||
|
elif key == "description":
|
||||||
|
value = self.description
|
||||||
|
elif key == "file_name":
|
||||||
|
value = self.file_name
|
||||||
|
elif key == "coordinates":
|
||||||
|
value = self.coordinates
|
||||||
|
elif key == "coordinates_bottom":
|
||||||
|
value = self.coordinates["bottom"]
|
||||||
|
elif key == "coordinates_top":
|
||||||
|
value = self.coordinates["top"]
|
||||||
|
elif key == "coordinates_left":
|
||||||
|
value = self.coordinates["left"]
|
||||||
|
elif key == "coordinates_right":
|
||||||
|
value = self.coordinates["right"]
|
||||||
|
elif key == "memfile":
|
||||||
|
value = self.memfile
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
if key == "enabled":
|
||||||
|
self.enabled = value
|
||||||
|
elif key == "name":
|
||||||
|
self.name = value
|
||||||
|
elif key == "description":
|
||||||
|
self.description = value
|
||||||
|
elif key == "file_name":
|
||||||
|
if self._file_name != value:
|
||||||
|
self.read_file(value)
|
||||||
|
elif key == "coordinates":
|
||||||
|
self.coordinates = value
|
||||||
|
elif key == "coordinates_bottom" or key == "bottom":
|
||||||
|
self.coordinates["bottom"] = value
|
||||||
|
elif key == "coordinates_top" or key == "top":
|
||||||
|
self.coordinates["top"] = value
|
||||||
|
elif key == "coordinates_left" or key == "left":
|
||||||
|
self.coordinates["left"] = value
|
||||||
|
elif key == "coordinates_right" or key == "right":
|
||||||
|
self.coordinates["right"] = value
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
def is_enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
return self._description
|
||||||
|
|
||||||
|
@description.setter
|
||||||
|
def description(self, description):
|
||||||
|
self._description = description
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file_name(self):
|
||||||
|
return self._file_name
|
||||||
|
|
||||||
|
@file_name.setter
|
||||||
|
def file_name(self, file_name):
|
||||||
|
self._file_name = file_name
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coordinates(self):
|
||||||
|
return self._coordinates
|
||||||
|
|
||||||
|
@coordinates.setter
|
||||||
|
def coordinates(self, coordinates):
|
||||||
|
self._coordinates = coordinates
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_bottom(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["bottom"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_top(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["top"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_left(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["left"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coord_right(self):
|
||||||
|
if self._coordinates is None:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self._coordinates["right"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def memfile(self):
|
||||||
|
if not _rasterio_loaded:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self._file_bytes == b'':
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self._memfile is None:
|
||||||
|
self._memfile = MemoryFile()
|
||||||
|
self._memfile.write(self._file_bytes)
|
||||||
|
|
||||||
|
return self._memfile
|
||||||
|
|
||||||
|
def read_file(self, path):
|
||||||
|
logger.debug(f"Read GeoTIFF file at : '{path}'")
|
||||||
|
|
||||||
|
self._file_name = path
|
||||||
|
self._file_bytes = b''
|
||||||
|
self._memfile = None
|
||||||
|
|
||||||
|
nbytes = 0
|
||||||
|
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
while True:
|
||||||
|
data = f.read(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
|
||||||
|
nbytes += len(data)
|
||||||
|
self._file_bytes += data
|
||||||
|
|
||||||
|
logger.debug(f"Read GeoTIFF: {nbytes} bytes readed")
|
||||||
|
|
||||||
|
def write_file(self, path):
|
||||||
|
with open(path, "w+b") as f:
|
||||||
|
f.write(self._file_bytes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE geotiff{ext} (
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
enabled BOOLEAN NOT NULL,
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
file_name TEXT NOT NULL,
|
||||||
|
file_bytes BLOB NOT NULL,
|
||||||
|
coordinates_bottom REAL NOT NULL,
|
||||||
|
coordinates_top REAL NOT NULL,
|
||||||
|
coordinates_left REAL NOT NULL,
|
||||||
|
coordinates_right REAL NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
if major == "0" and int(minor) == 2:
|
||||||
|
if int(release) < 3:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, enabled, deleted, " +
|
||||||
|
"name, description, file_name, file_bytes, " +
|
||||||
|
"coordinates_bottom, coordinates_top, " +
|
||||||
|
"coordinates_left, coordinates_right, " +
|
||||||
|
"scenario " +
|
||||||
|
"FROM geotiff " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
it = iter(row)
|
||||||
|
|
||||||
|
id = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
description = next(it)
|
||||||
|
file_name = next(it)
|
||||||
|
file_bytes = next(it)
|
||||||
|
coordinates_bottom = next(it)
|
||||||
|
coordinates_top = next(it)
|
||||||
|
coordinates_left = next(it)
|
||||||
|
coordinates_right = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
f = cls(
|
||||||
|
id=id, enabled=enabled, name=name,
|
||||||
|
description=description, coordinates={
|
||||||
|
"bottom": coordinates_bottom,
|
||||||
|
"top": coordinates_top,
|
||||||
|
"left": coordinates_left,
|
||||||
|
"right": coordinates_right,
|
||||||
|
},
|
||||||
|
status=data['status'],
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
f.set_as_deleted()
|
||||||
|
|
||||||
|
f._file_bytes = file_bytes
|
||||||
|
|
||||||
|
loaded.add(id)
|
||||||
|
new.append(f)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO geotiff (" +
|
||||||
|
"pamhyr_id, enabled, deleted, " +
|
||||||
|
"name, description, file_name, file_bytes, " +
|
||||||
|
"coordinates_bottom, coordinates_top, " +
|
||||||
|
"coordinates_left, coordinates_right, " +
|
||||||
|
"scenario) " +
|
||||||
|
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||||
|
self._pamhyr_id,
|
||||||
|
self._enabled,
|
||||||
|
self.is_deleted(),
|
||||||
|
self.name,
|
||||||
|
self.description,
|
||||||
|
self.file_name,
|
||||||
|
self._file_bytes,
|
||||||
|
self.coordinates['bottom'],
|
||||||
|
self.coordinates['top'],
|
||||||
|
self.coordinates['left'],
|
||||||
|
self.coordinates['right'],
|
||||||
|
self._status.scenario_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# GeoTIFFList.py -- Pamhyr
|
||||||
|
# Copyright (C) 2024-2025 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
|
from Model.GeoTIFF.GeoTIFF import GeoTIFF
|
||||||
|
|
||||||
|
|
||||||
|
class GeoTIFFList(PamhyrModelList):
|
||||||
|
_sub_classes = [GeoTIFF]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = cls(status=data["status"])
|
||||||
|
|
||||||
|
new._lst = GeoTIFF._db_load(execute, data)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
ok = True
|
||||||
|
|
||||||
|
# Delete previous data
|
||||||
|
execute(
|
||||||
|
"DELETE FROM geotiff " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for gt in self._lst:
|
||||||
|
ok &= gt._db_save(execute, data)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
|
||||||
|
@property
|
||||||
|
def files(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = GeoTIFF(status=self._status)
|
||||||
|
self.insert(index, n)
|
||||||
|
self._status.modified()
|
||||||
|
return n
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Point.py -- Pamhyr
|
# Point.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,14 +16,18 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
|
||||||
class Point(object):
|
class Point(SQLSubModel):
|
||||||
def __init__(self, name: str = "", profile=None, status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(Point, self).__init__()
|
profile=None, status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
self._status = status
|
super(Point, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._profile = profile
|
self._profile = profile
|
||||||
@@ -43,6 +47,8 @@ class Point(object):
|
|||||||
else:
|
else:
|
||||||
self._sl = sl
|
self._sl = sl
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._name
|
return self._name
|
||||||
@@ -50,9 +56,9 @@ class Point(object):
|
|||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def point_is_named(self):
|
def is_named(self):
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
True if the point is named.
|
True if the point is named.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# PointXY.py -- Pamhyr
|
# PointXY.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
+218
-40
@@ -1,5 +1,5 @@
|
|||||||
# PointXYZ.py -- Pamhyr
|
# PointXYZ.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,30 +16,40 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from math import dist
|
from math import dist
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Scenario import Scenario
|
||||||
from Model.Geometry.Point import Point
|
from Model.Geometry.Point import Point
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class PointXYZ(Point, SQLSubModel):
|
|
||||||
|
class PointXYZ(Point):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
|
|
||||||
def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0,
|
def __init__(self, id: int = -1,
|
||||||
name: str = "", profile=None, status=None):
|
x: float = 0.0, y: float = 0.0, z: float = 0.0,
|
||||||
|
name: str = "", profile=None,
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
super(PointXYZ, self).__init__(
|
super(PointXYZ, self).__init__(
|
||||||
name=name, profile=profile, status=status)
|
id=id, name=name, profile=profile, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._x = float(x)
|
self._x = float(x)
|
||||||
self._y = float(y)
|
self._y = float(y)
|
||||||
self._z = float(z)
|
self._z = float(z)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE geometry_pointXYZ(
|
CREATE TABLE geometry_pointXYZ{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
ind INTEGER NOT NULL,
|
ind INTEGER NOT NULL,
|
||||||
name TEXT,
|
name TEXT,
|
||||||
x INTEGER NOT NULL,
|
x INTEGER NOT NULL,
|
||||||
@@ -47,17 +57,19 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
z INTEGER NOT NULL,
|
z INTEGER NOT NULL,
|
||||||
profile INTEGER NOT NULL,
|
profile INTEGER NOT NULL,
|
||||||
sl INTEGER,
|
sl INTEGER,
|
||||||
FOREIGN KEY(profile) REFERENCES geometry_profileXYZ(id),
|
{Scenario.create_db_add_scenario()},
|
||||||
FOREIGN KEY(sl) REFERENCES sedimentary_layer(id)
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(profile)
|
||||||
|
REFERENCES geometry_profileXYZ(pamhyr_id),
|
||||||
|
FOREIGN KEY(sl) REFERENCES sedimentary_layer(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
cls._update_submodel(execute, version)
|
|
||||||
|
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 2:
|
if int(release) < 2:
|
||||||
@@ -68,63 +80,174 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
REFERENCES sedimentary_layer(id)
|
REFERENCES sedimentary_layer(id)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
return True
|
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE geometry_pointXYZ " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "geometry_pointXYZ"
|
||||||
|
id2pid = data['id2pid']
|
||||||
|
profiles = id2pid['geometry_profileXYZ']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, ind, name, x, y, z, profile, sl, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ind, name, x, y, z, profile, sl, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_profile_pid(execute, table, profiles)
|
||||||
|
|
||||||
|
if 'sedimentary_layer' in id2pid:
|
||||||
|
sl = id2pid['sedimentary_layer']
|
||||||
|
cls._db_update_to_0_2_0_set_sl_pid(execute, table, sl)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_profile_pid(cls, execute, table, profiles):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, profile FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
profile_id = next(it)
|
||||||
|
|
||||||
|
if profile_id not in profiles:
|
||||||
|
logger.warning(
|
||||||
|
f"This point as no associated profile ({profile_id})"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET profile = {profiles[profile_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_sl_pid(cls, execute, table, sl):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, sl FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
sl_id = next(it)
|
||||||
|
|
||||||
|
if sl_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET sl = {sl[sl_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
profile = data["profile"]
|
profile = data["profile"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT ind, name, x, y, z, sl " +
|
"SELECT pamhyr_id, ind, deleted, " +
|
||||||
|
"name, x, y, z, sl, scenario " +
|
||||||
"FROM geometry_pointXYZ " +
|
"FROM geometry_pointXYZ " +
|
||||||
f"WHERE profile = {profile.id}"
|
f"WHERE profile = {profile.pamhyr_id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
|
||||||
|
"ORDER BY ind ASC"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fill points list with new point
|
|
||||||
for row in table:
|
for row in table:
|
||||||
ind = row[0]
|
it = iter(row)
|
||||||
name = row[1]
|
|
||||||
x = row[2]
|
|
||||||
y = row[3]
|
|
||||||
z = row[4]
|
|
||||||
sl = row[5]
|
|
||||||
|
|
||||||
new = cls(
|
pid = next(it)
|
||||||
|
ind = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
x = next(it)
|
||||||
|
y = next(it)
|
||||||
|
z = next(it)
|
||||||
|
sl = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
point = cls(
|
||||||
|
id=pid,
|
||||||
name=name,
|
name=name,
|
||||||
x=x, y=y, z=z,
|
x=x, y=y, z=z,
|
||||||
profile=profile,
|
profile=profile,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
point.set_as_deleted()
|
||||||
|
|
||||||
if sl == -1 or sl is None:
|
if sl == -1 or sl is None:
|
||||||
new._sl = None
|
point._sl = None
|
||||||
else:
|
else:
|
||||||
new._sl = next(
|
point._sl = next(
|
||||||
filter(
|
filter(
|
||||||
lambda s: s.id == sl,
|
lambda s: s.pamhyr_id == sl,
|
||||||
data["sediment_layers_list"].sediment_layers
|
data["sediment_layers_list"].sediment_layers
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
yield ind, new
|
loaded.add(pid)
|
||||||
|
new.append((ind, point))
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
profile = data["profile"]
|
profile = data["profile"]
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
sl = self._sl.id if self._sl is not None else -1
|
sl = self._sl.pamhyr_id if self._sl is not None else -1
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"geometry_pointXYZ(ind, name, x, y, z, profile, sl) " +
|
"geometry_pointXYZ(pamhyr_id, deleted, ind, name, " +
|
||||||
|
"x, y, z, profile, sl, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
|
f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"{ind}, '{self._db_format(self._name)}', " +
|
f"{ind}, '{self._db_format(self._name)}', " +
|
||||||
f"{self.x}, {self.y}, {self.z}, " +
|
f"{self.x}, {self.y}, {self.z}, " +
|
||||||
f"{profile.id}, {sl}" +
|
f"{profile.pamhyr_id}, {sl}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -150,9 +273,44 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
|
|
||||||
return point
|
return point
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
new_p = PointXYZ(
|
||||||
|
id=-1,
|
||||||
|
name=self.name,
|
||||||
|
x=self.x, y=self.y, z=self.z,
|
||||||
|
profile=self._profile,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
|
if self.is_deleted():
|
||||||
|
new_p.set_as_deleted()
|
||||||
|
|
||||||
|
new_p._sl = self.sl
|
||||||
|
|
||||||
|
new_p.modified()
|
||||||
|
return new_p
|
||||||
|
|
||||||
|
def cloned_for(self, new_profile):
|
||||||
|
new_p = PointXYZ(
|
||||||
|
id=-1,
|
||||||
|
name=self.name,
|
||||||
|
x=self.x, y=self.y, z=self.z,
|
||||||
|
profile=new_profile,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
|
if self.is_deleted():
|
||||||
|
new_p.set_as_deleted()
|
||||||
|
|
||||||
|
new_p._sl = self.sl
|
||||||
|
|
||||||
|
new_p.modified()
|
||||||
|
return new_p
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"({self._x}, {self._y}, {self._z}, {self._name})"
|
return f"({self._x}, {self._y}, {self._z}, {self._name})"
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self.y > other.y
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def x(self):
|
def x(self):
|
||||||
return self._x
|
return self._x
|
||||||
@@ -160,7 +318,7 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
@x.setter
|
@x.setter
|
||||||
def x(self, value):
|
def x(self, value):
|
||||||
self._x = float(value)
|
self._x = float(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def y(self):
|
def y(self):
|
||||||
@@ -169,7 +327,7 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
@y.setter
|
@y.setter
|
||||||
def y(self, value):
|
def y(self, value):
|
||||||
self._y = float(value)
|
self._y = float(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def z(self):
|
def z(self):
|
||||||
@@ -178,7 +336,10 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
@z.setter
|
@z.setter
|
||||||
def z(self, value):
|
def z(self, value):
|
||||||
self._z = float(value)
|
self._z = float(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
|
def get_coordinate(self):
|
||||||
|
return (self._x, self._y, self._z)
|
||||||
|
|
||||||
def is_nan(self):
|
def is_nan(self):
|
||||||
"""
|
"""
|
||||||
@@ -226,5 +387,22 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
a = PointXYZ.distance(p1, p2)
|
a = PointXYZ.distance(p1, p2)
|
||||||
b = PointXYZ.distance(p2, p3)
|
b = PointXYZ.distance(p2, p3)
|
||||||
c = PointXYZ.distance(p3, p1)
|
c = PointXYZ.distance(p3, p1)
|
||||||
s = (a + b + c) / 2
|
|
||||||
return (s*(s-a) * (s-b)*(s-c)) ** 0.5
|
s = float((a + b + c) / 2)
|
||||||
|
res = abs(
|
||||||
|
s * (s - a) * (s - b) * (s - c)
|
||||||
|
) ** 0.5
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def dist_from_seg(self, p1, p2):
|
||||||
|
a2 = pow(PointXYZ.distance(self, p1), 2)
|
||||||
|
b2 = pow(PointXYZ.distance(self, p2), 2)
|
||||||
|
c2 = pow(PointXYZ.distance(p1, p2), 2)
|
||||||
|
if c2 < 0.00000001:
|
||||||
|
# si les deux points sont confondus
|
||||||
|
d = 0.0
|
||||||
|
else:
|
||||||
|
d = np.sqrt(abs(a2 - pow((c2 - b2 + a2) / (2*np.sqrt(c2)), 2)))
|
||||||
|
|
||||||
|
return d
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Profile.py -- Pamhyr
|
# Profile.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,23 +28,15 @@ logger = logging.getLogger()
|
|||||||
|
|
||||||
|
|
||||||
class Profile(object):
|
class Profile(object):
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, num: int = 0,
|
def __init__(self, id: int = -1, num: int = 0,
|
||||||
rk: float = 0.0, name: str = "",
|
rk: float = 0.0, name: str = "",
|
||||||
code1: int = 0, code2: int = 0,
|
code1: int = 0, code2: int = 0,
|
||||||
_type: str = "", reach=None,
|
_type: str = "", reach=None,
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(Profile, self).__init__()
|
super(Profile, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
self._status = status
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
if id == -1:
|
|
||||||
self.id = Profile._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
Profile._id_cnt = max(self.id, Profile._id_cnt+1)
|
|
||||||
|
|
||||||
self._num = int(num)
|
self._num = int(num)
|
||||||
self._code1 = int(code1)
|
self._code1 = int(code1)
|
||||||
@@ -66,28 +58,42 @@ class Profile(object):
|
|||||||
return len(self.points)
|
return len(self.points)
|
||||||
|
|
||||||
def _get_points_list(self):
|
def _get_points_list(self):
|
||||||
# Points list generator is type (int, Point) with the first
|
return list(self._points)
|
||||||
# element the index of the Point in list
|
|
||||||
return list(
|
|
||||||
map(
|
|
||||||
lambda p: p[1],
|
|
||||||
sorted(
|
|
||||||
self._points,
|
|
||||||
key=lambda p: p[0]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def points(self):
|
def points(self):
|
||||||
if not isinstance(self._points, list):
|
if not isinstance(self._points, list):
|
||||||
self._points = self._get_points_list()
|
self._points = self._get_points_list()
|
||||||
|
|
||||||
return self._points
|
return list(
|
||||||
|
filter(
|
||||||
|
lambda p: not p.is_deleted(),
|
||||||
|
self._points
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def point(self, index):
|
def point(self, index):
|
||||||
return self.points[index]
|
return self.points[index]
|
||||||
|
|
||||||
|
def named_point(self, name):
|
||||||
|
if name == "un":
|
||||||
|
return self.points[0]
|
||||||
|
elif name == "np":
|
||||||
|
return self.points[-1]
|
||||||
|
else:
|
||||||
|
return next((p for p in self.points if p.name == name), None)
|
||||||
|
|
||||||
|
def named_point_index(self, name):
|
||||||
|
if name == "un":
|
||||||
|
return 0
|
||||||
|
elif name == "np":
|
||||||
|
return len(self.points) - 1
|
||||||
|
else:
|
||||||
|
return next(
|
||||||
|
(p for p in enumerate(self.points) if p[1].name == name),
|
||||||
|
None
|
||||||
|
)[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
return self._reach
|
return self._reach
|
||||||
@@ -103,7 +109,7 @@ class Profile(object):
|
|||||||
@num.setter
|
@num.setter
|
||||||
def num(self, value: int):
|
def num(self, value: int):
|
||||||
self._num = int(value)
|
self._num = int(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def code1(self):
|
def code1(self):
|
||||||
@@ -116,7 +122,7 @@ class Profile(object):
|
|||||||
@code1.setter
|
@code1.setter
|
||||||
def code1(self, value: int):
|
def code1(self, value: int):
|
||||||
self._code1 = int(value)
|
self._code1 = int(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def code2(self):
|
def code2(self):
|
||||||
@@ -129,7 +135,7 @@ class Profile(object):
|
|||||||
@code2.setter
|
@code2.setter
|
||||||
def code2(self, value: int):
|
def code2(self, value: int):
|
||||||
self._code2 = int(value)
|
self._code2 = int(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nb_points(self):
|
def nb_points(self):
|
||||||
@@ -146,7 +152,7 @@ class Profile(object):
|
|||||||
@rk.setter
|
@rk.setter
|
||||||
def rk(self, value: float):
|
def rk(self, value: float):
|
||||||
self._rk = float(value)
|
self._rk = float(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -159,7 +165,7 @@ class Profile(object):
|
|||||||
@name.setter
|
@name.setter
|
||||||
def name(self, value: str):
|
def name(self, value: str):
|
||||||
self._name = value.strip()
|
self._name = value.strip()
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sl(self):
|
def sl(self):
|
||||||
@@ -172,7 +178,7 @@ class Profile(object):
|
|||||||
@sl.setter
|
@sl.setter
|
||||||
def sl(self, value):
|
def sl(self, value):
|
||||||
self._sl = value
|
self._sl = value
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def profile_type(self):
|
def profile_type(self):
|
||||||
@@ -185,7 +191,7 @@ class Profile(object):
|
|||||||
@profile_type.setter
|
@profile_type.setter
|
||||||
def profile_type(self, value: str):
|
def profile_type(self, value: str):
|
||||||
self._profile_type = value
|
self._profile_type = value
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def point(self, i: int):
|
def point(self, i: int):
|
||||||
if i < len(self.points):
|
if i < len(self.points):
|
||||||
@@ -200,33 +206,37 @@ class Profile(object):
|
|||||||
The list of named point
|
The list of named point
|
||||||
"""
|
"""
|
||||||
return [point for point in self.points
|
return [point for point in self.points
|
||||||
if point.point_is_named()]
|
if point.is_named()]
|
||||||
|
|
||||||
def insert_point(self, index: int, point: Point):
|
def insert_point(self, index: int, point: Point):
|
||||||
"""Insert point at index.
|
"""Insert point at index.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
index: The index of new profile.
|
index: The index of new point.
|
||||||
point: The point.
|
point: The point.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self.points.insert(index, point)
|
if point in self._points:
|
||||||
self._status.modified()
|
point.set_as_not_deleted()
|
||||||
|
else:
|
||||||
|
self._points.insert(index, point)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def delete_i(self, indexes: list):
|
def delete_i(self, indexes: list):
|
||||||
self._points = list(
|
list(
|
||||||
map(
|
map(
|
||||||
lambda e: e[1],
|
lambda e: e[1].set_as_deleted(),
|
||||||
filter(
|
filter(
|
||||||
lambda e: e[0] not in indexes,
|
lambda e: e[0] in indexes,
|
||||||
enumerate(self.points)
|
enumerate(self.points)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete_points(self, points):
|
def delete_points(self, points):
|
||||||
"""Delete some elements in profile list
|
"""Delete some elements in profile list
|
||||||
@@ -237,31 +247,31 @@ class Profile(object):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self._points = list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda p: p not in points,
|
lambda p: p.set_as_deleted(),
|
||||||
self.points
|
points
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
# Move
|
# Move
|
||||||
|
|
||||||
def move_up_point(self, index: int):
|
def move_up_point(self, index: int):
|
||||||
if index < len(self.points):
|
if index < len(self._points):
|
||||||
next = index - 1
|
next = index - 1
|
||||||
|
|
||||||
p = self.points
|
p = self._points
|
||||||
p[index], p[next] = p[next], p[index]
|
p[index], p[next] = p[next], p[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def move_down_point(self, index: int):
|
def move_down_point(self, index: int):
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
|
|
||||||
p = self.points
|
p = self._points
|
||||||
p[index], p[prev] = p[prev], p[index]
|
p[index], p[prev] = p[prev], p[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
# Sort
|
# Sort
|
||||||
|
|
||||||
@@ -274,32 +284,32 @@ class Profile(object):
|
|||||||
def predicate(p): return p.z
|
def predicate(p): return p.z
|
||||||
|
|
||||||
self._points = sorted(
|
self._points = sorted(
|
||||||
self.points,
|
self._points,
|
||||||
key=predicate,
|
key=predicate,
|
||||||
reverse=is_reversed
|
reverse=is_reversed
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort_with_indexes(self, indexes: list):
|
def sort_with_indexes(self, indexes: list):
|
||||||
if len(self.points) != len(indexes):
|
if len(self._points) != len(indexes):
|
||||||
logger.critical("Indexes list do not correspond to point list")
|
logger.critical("Indexes list do not correspond to point list")
|
||||||
|
|
||||||
self._points = list(
|
self._points = list(
|
||||||
map(
|
map(
|
||||||
lambda x: x[1],
|
lambda x: x[1],
|
||||||
sorted(
|
sorted(
|
||||||
enumerate(self.points),
|
enumerate(self._points),
|
||||||
key=lambda x: indexes[x[0]]
|
key=lambda x: indexes[x[0]]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def reverse(self):
|
def reverse(self):
|
||||||
self._points.reverse()
|
self._points.reverse()
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
# Sediment Layers
|
# Sediment Layers
|
||||||
|
|
||||||
|
|||||||
+377
-123
@@ -1,5 +1,5 @@
|
|||||||
# ProfileXYZ.py -- Pamhyr
|
# ProfileXYZ.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,17 +16,20 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import queue
|
||||||
|
import random
|
||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import List
|
from typing import List
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from tools import timer
|
from tools import timer, flatten
|
||||||
from shapely import geometry
|
from shapely import geometry
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import ClipboardFormatError
|
from Model.Except import ClipboardFormatError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
from Model.Geometry.Profile import Profile
|
from Model.Geometry.Profile import Profile
|
||||||
from Model.Geometry.PointXYZ import PointXYZ
|
from Model.Geometry.PointXYZ import PointXYZ
|
||||||
from Model.Geometry.Vector_1d import Vector1d
|
from Model.Geometry.Vector_1d import Vector1d
|
||||||
@@ -48,13 +51,14 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
id: int = -1,
|
id: int = -1,
|
||||||
|
ind: int = -1,
|
||||||
name: str = "",
|
name: str = "",
|
||||||
rk: float = 0.,
|
rk: float = 0.,
|
||||||
reach=None,
|
reach=None,
|
||||||
num=0,
|
num=0,
|
||||||
nb_point: int = 0,
|
nb_point: int = 0,
|
||||||
code1: int = 0, code2: int = 0,
|
code1: int = 0, code2: int = 0,
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
"""ProfileXYZ constructor
|
"""ProfileXYZ constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -69,15 +73,16 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
super(ProfileXYZ, self).__init__(
|
super(ProfileXYZ, self).__init__(
|
||||||
id=id,
|
id=id,
|
||||||
num=num,
|
|
||||||
name=name,
|
name=name,
|
||||||
rk=rk,
|
num=num, rk=rk,
|
||||||
code1=code1, code2=code2,
|
code1=code1, code2=code2,
|
||||||
_type="XYZ",
|
_type="XYZ",
|
||||||
reach=reach,
|
reach=reach,
|
||||||
status=status,
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._db_ind = ind
|
||||||
self.tab = Tabulation([], [], [])
|
self.tab = Tabulation([], [], [])
|
||||||
self.tab_up_to_date = False
|
self.tab_up_to_date = False
|
||||||
self.time_z = 0.0
|
self.time_z = 0.0
|
||||||
@@ -87,10 +92,11 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
self.station_up_to_date = False
|
self.station_up_to_date = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE geometry_profileXYZ(
|
CREATE TABLE geometry_profileXYZ{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
ind INTEGER NOT NULL,
|
ind INTEGER NOT NULL,
|
||||||
name TEXT,
|
name TEXT,
|
||||||
reach INTEGER NOT NULL,
|
reach INTEGER NOT NULL,
|
||||||
@@ -99,15 +105,21 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
code1 INTEGER NOT NULL,
|
code1 INTEGER NOT NULL,
|
||||||
code2 INTEGER NOT NULL,
|
code2 INTEGER NOT NULL,
|
||||||
sl INTEGER,
|
sl INTEGER,
|
||||||
FOREIGN KEY(reach) REFERENCES river_reach(id),
|
{Scenario.create_db_add_scenario()},
|
||||||
FOREIGN KEY(sl) REFERENCES sedimentary_layer(id)
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
|
||||||
|
FOREIGN KEY(sl) REFERENCES sedimentary_layer(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
if ext == "_tmp":
|
||||||
|
return True
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
rl = int(release)
|
rl = int(release)
|
||||||
@@ -128,84 +140,215 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
return cls._update_submodel(execute, version)
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE geometry_profileXYZ " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "geometry_profileXYZ"
|
||||||
|
id2pid = data['id2pid']
|
||||||
|
reachs = id2pid['river_reach']
|
||||||
|
|
||||||
|
cls._db_update_cleanup_points(execute)
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, ind, name, reach, rk, " +
|
||||||
|
"num, code1, code2, sl, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ind, name, reach, rk, " +
|
||||||
|
"num, code1, code2, sl, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table, reachs)
|
||||||
|
|
||||||
|
if 'sedimentary_layer' in id2pid:
|
||||||
|
sl = id2pid['sedimentary_layer']
|
||||||
|
cls._db_update_to_0_2_0_set_sl_pid(execute, table, sl)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_cleanup_points(cls, execute):
|
||||||
|
profiles = set(
|
||||||
|
map(
|
||||||
|
str,
|
||||||
|
flatten(
|
||||||
|
execute(
|
||||||
|
"SELECT id FROM geometry_profileXYZ"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"DELETE FROM geometry_pointXYZ " +
|
||||||
|
f"WHERE profile NOT IN ({', '.join(profiles)})"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_sl_pid(cls, execute, table, sl):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, sl FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
sl_id = next(it)
|
||||||
|
|
||||||
|
if sl_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET sl = {sl[sl_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
profiles = []
|
new = []
|
||||||
|
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
reach = data["reach"]
|
reach = data["reach"]
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, ind, name, rk, num, code1, code2, sl " +
|
"SELECT pamhyr_id, ind, deleted, name, rk, num, " +
|
||||||
|
"code1, code2, sl, scenario " +
|
||||||
"FROM geometry_profileXYZ " +
|
"FROM geometry_profileXYZ " +
|
||||||
f"WHERE reach = {reach.id}"
|
f"WHERE reach = {reach.id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
|
||||||
|
"ORDER BY ind ASC"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
ind = row[1]
|
|
||||||
name = row[2]
|
|
||||||
rk = row[3]
|
|
||||||
num = row[5]
|
|
||||||
code1 = row[5]
|
|
||||||
code2 = row[6]
|
|
||||||
sl = row[7]
|
|
||||||
|
|
||||||
new = cls(
|
pid = next(it)
|
||||||
id=id, num=num,
|
ind = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
rk = next(it)
|
||||||
|
num = next(it)
|
||||||
|
code1 = next(it)
|
||||||
|
code2 = next(it)
|
||||||
|
sl = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
profile = cls(
|
||||||
|
id=pid, ind=ind, num=num,
|
||||||
name=name, rk=rk,
|
name=name, rk=rk,
|
||||||
code1=code1, code2=code2,
|
code1=code1, code2=code2,
|
||||||
reach=reach,
|
reach=reach,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
profile.set_as_deleted()
|
||||||
|
|
||||||
if sl == -1 or sl is None:
|
if sl == -1 or sl is None:
|
||||||
new._sl = None
|
profile._sl = None
|
||||||
else:
|
else:
|
||||||
new._sl = next(
|
profile._sl = next(
|
||||||
filter(
|
filter(
|
||||||
lambda s: s.id == sl,
|
lambda s: s.id == sl,
|
||||||
data["sediment_layers_list"].sediment_layers
|
data["sediment_layers_list"].sediment_layers
|
||||||
)
|
),
|
||||||
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
data["profile"] = new
|
loaded_save = data['loaded_pid']
|
||||||
new._points = PointXYZ._db_load(execute, data.copy())
|
data['loaded_pid'] = set()
|
||||||
|
data["profile"] = profile
|
||||||
|
|
||||||
yield ind, new
|
profile._points = list(
|
||||||
|
map(
|
||||||
|
lambda ip: ip[1],
|
||||||
|
sorted(
|
||||||
|
PointXYZ._db_load(execute, data.copy()),
|
||||||
|
key=lambda ip: ip[0]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
data['loaded_pid'] = loaded_save
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(profile)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
ok = True
|
ok = True
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
sl = self._sl.id if self._sl is not None else -1
|
sl = self._sl.pamhyr_id if self._sl is not None else -1
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT OR REPLACE INTO " +
|
"INSERT OR REPLACE INTO " +
|
||||||
"geometry_profileXYZ(id, ind, name, reach, " +
|
"geometry_profileXYZ(pamhyr_id, deleted, ind, name, reach, " +
|
||||||
"rk, num, code1, code2, sl) " +
|
"rk, num, code1, code2, sl, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {ind}, '{self._db_format(self._name)}', " +
|
f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"{self.reach.id}, {self.rk}, {self.num}, " +
|
f"{ind}, '{self._db_format(self._name)}', " +
|
||||||
f"{self.code1}, {self.code1}, {sl}" +
|
f"{self.reach.pamhyr_id}, {self.rk}, {self.num}, " +
|
||||||
|
f"{self.code1}, {self.code1}, {sl}, {self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
points = self.points
|
|
||||||
|
|
||||||
data["profile"] = self
|
data["profile"] = self
|
||||||
execute(f"DELETE FROM geometry_pointXYZ WHERE profile = {self.id}")
|
execute(
|
||||||
|
"DELETE FROM geometry_pointXYZ " +
|
||||||
|
f"WHERE profile = {self.pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for point in points:
|
for point in self._points:
|
||||||
data["ind"] = ind
|
data["ind"] = ind
|
||||||
ok &= point._db_save(execute, data)
|
ok &= point._db_save(execute, data)
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for p in self._points:
|
||||||
|
p._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data(cls, header, data):
|
def from_data(cls, header, data):
|
||||||
profile = None
|
profile = None
|
||||||
@@ -238,6 +381,47 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
return profile
|
return profile
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
new_p = ProfileXYZ(
|
||||||
|
id=-1,
|
||||||
|
name=self.name,
|
||||||
|
rk=self.rk,
|
||||||
|
reach=self.reach,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
|
if self.is_deleted():
|
||||||
|
new_p.set_as_deleted()
|
||||||
|
|
||||||
|
new_p._sl = self.sl
|
||||||
|
|
||||||
|
for point in self._points:
|
||||||
|
p = point.copy()
|
||||||
|
print(p)
|
||||||
|
new_p._points.append(p)
|
||||||
|
|
||||||
|
new_p.modified()
|
||||||
|
return new_p
|
||||||
|
|
||||||
|
def cloned_for(self, new_reach):
|
||||||
|
new_p = ProfileXYZ(
|
||||||
|
id=-1,
|
||||||
|
name=self.name,
|
||||||
|
rk=self.rk,
|
||||||
|
reach=new_reach,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
|
if self.is_deleted():
|
||||||
|
new_p.set_as_deleted()
|
||||||
|
|
||||||
|
new_p._sl = self.sl
|
||||||
|
|
||||||
|
for point in self._points:
|
||||||
|
p = point.cloned_for(new_p)
|
||||||
|
new_p._points.append(p)
|
||||||
|
|
||||||
|
new_p.modified()
|
||||||
|
return new_p
|
||||||
|
|
||||||
def point_from_data(self, header, data):
|
def point_from_data(self, header, data):
|
||||||
def float_format(s: str):
|
def float_format(s: str):
|
||||||
return float(
|
return float(
|
||||||
@@ -278,6 +462,12 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
def modified(self):
|
||||||
|
super(ProfileXYZ, self).modified()
|
||||||
|
|
||||||
|
self.tab_up_to_date = False
|
||||||
|
self.station_up_to_date = False
|
||||||
|
|
||||||
def x(self):
|
def x(self):
|
||||||
return [point.x for point in self.points]
|
return [point.x for point in self.points]
|
||||||
|
|
||||||
@@ -318,11 +508,20 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
for point in list_points:
|
for point in list_points:
|
||||||
pt = PointXYZ(*point, profile=self, status=self._status)
|
named_args = {
|
||||||
self.points.append(pt)
|
"x": point[0],
|
||||||
self._status.modified()
|
"y": point[1],
|
||||||
self.tab_up_to_date = False
|
"z": point[2],
|
||||||
self.station_up_to_date = False
|
"name": point[3],
|
||||||
|
}
|
||||||
|
|
||||||
|
pt = PointXYZ(
|
||||||
|
id=-1, **named_args, profile=self,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
|
self._points.append(pt)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def get_point_i(self, index: int) -> PointXYZ:
|
def get_point_i(self, index: int) -> PointXYZ:
|
||||||
"""Get point at index.
|
"""Get point at index.
|
||||||
@@ -381,11 +580,13 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
point_xyz = PointXYZ(
|
||||||
|
x=0., y=0., z=0., profile=self,
|
||||||
|
status=self._status
|
||||||
|
)
|
||||||
self.points.append(point_xyz)
|
self.points.append(point_xyz)
|
||||||
self._status.modified()
|
|
||||||
self.tab_up_to_date = False
|
self.modified()
|
||||||
self.station_up_to_date = False
|
|
||||||
|
|
||||||
def insert(self, index: int):
|
def insert(self, index: int):
|
||||||
"""Insert a new point at index.
|
"""Insert a new point at index.
|
||||||
@@ -396,11 +597,16 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
The new point.
|
The new point.
|
||||||
"""
|
"""
|
||||||
point = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
x, y, z = (0., 0., 0.)
|
||||||
self.points.insert(index, point)
|
|
||||||
self._status.modified()
|
if 0 < len(self._points) >= index:
|
||||||
self.tab_up_to_date = False
|
x, y, z = self._points[index - 1].get_coordinate()
|
||||||
self.station_up_to_date = False
|
|
||||||
|
point = PointXYZ(x=x, y=y, z=z, profile=self, status=self._status)
|
||||||
|
self._points.insert(index, point)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
return point
|
return point
|
||||||
|
|
||||||
def filter_isnan(self, lst):
|
def filter_isnan(self, lst):
|
||||||
@@ -543,8 +749,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
if zz[i] >= z and zz[i+1] < z:
|
if zz[i] >= z and zz[i+1] < z:
|
||||||
y = np.interp(
|
y = np.interp(
|
||||||
z,
|
z,
|
||||||
[zz[i], zz[i+1]],
|
[zz[i+1], zz[i]],
|
||||||
[station[i], station[i+1]]
|
[station[i+1], station[i]]
|
||||||
)
|
)
|
||||||
line.append([y, z])
|
line.append([y, z])
|
||||||
|
|
||||||
@@ -633,11 +839,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
for i in range(self.number_points-1):
|
for i in range(self.number_points-1):
|
||||||
if zz[i] > z and zz[i+1] <= z:
|
if zz[i] > z and zz[i+1] <= z:
|
||||||
y = np.interp(
|
fact = (z - zz[i]) / (zz[i+1] - zz[i])
|
||||||
z,
|
y = station[i] + fact * (station[i+1] - station[i])
|
||||||
[zz[i], zz[i+1]],
|
|
||||||
[station[i], station[i+1]]
|
|
||||||
)
|
|
||||||
start.append(y)
|
start.append(y)
|
||||||
|
|
||||||
end = []
|
end = []
|
||||||
@@ -646,11 +849,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
for i in reversed(range(self.number_points-1)):
|
for i in reversed(range(self.number_points-1)):
|
||||||
if zz[i] <= z and zz[i+1] > z:
|
if zz[i] <= z and zz[i+1] > z:
|
||||||
y = np.interp(
|
fact = (z - zz[i]) / (zz[i+1] - zz[i])
|
||||||
z,
|
y = station[i] + fact * (station[i+1] - station[i])
|
||||||
[zz[i], zz[i+1]],
|
|
||||||
[station[i], station[i+1]]
|
|
||||||
)
|
|
||||||
end.append(y)
|
end.append(y)
|
||||||
|
|
||||||
if len(start) != len(end):
|
if len(start) != len(end):
|
||||||
@@ -681,33 +881,31 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
# Interpolate points at river left side
|
# Interpolate points at river left side
|
||||||
if (i_left > 0):
|
if (i_left > 0):
|
||||||
x = np.interp(
|
if abs(self.point(i_left - 1).z - self.point(i_left).z) < 1e-20:
|
||||||
z,
|
pt_left = self.point(i_left)
|
||||||
[self.point(i_left).z, self.point(i_left - 1).z],
|
else:
|
||||||
[self.point(i_left).x, self.point(i_left - 1).x]
|
fact = (z - self.point(i_left).z) / \
|
||||||
)
|
(self.point(i_left - 1).z - self.point(i_left).z)
|
||||||
y = np.interp(
|
x = self.point(i_left).x + fact * \
|
||||||
z,
|
(self.point(i_left - 1).x - self.point(i_left).x)
|
||||||
[self.point(i_left).z, self.point(i_left - 1).z],
|
y = self.point(i_left).y + fact * \
|
||||||
[self.point(i_left).y, self.point(i_left - 1).y]
|
(self.point(i_left - 1).y - self.point(i_left).y)
|
||||||
)
|
pt_left = PointXYZ(x=x, y=y, z=z, name="wl_left")
|
||||||
pt_left = PointXYZ(x, y, z, name="wl_left")
|
|
||||||
else:
|
else:
|
||||||
pt_left = self.point(0)
|
pt_left = self.point(0)
|
||||||
|
|
||||||
# Interpolate points at river right side
|
# Interpolate points at river right side
|
||||||
if (i_right < self.number_points - 1):
|
if (i_right < self.number_points - 1):
|
||||||
x = np.interp(
|
if abs(self.point(i_right + 1).z - self.point(i_right).z) < 1e-20:
|
||||||
z,
|
pt_right = self.point(i_right)
|
||||||
[self.point(i_right).z, self.point(i_right + 1).z],
|
else:
|
||||||
[self.point(i_right).x, self.point(i_right + 1).x]
|
fact = (z - self.point(i_right).z) / \
|
||||||
)
|
(self.point(i_right + 1).z - self.point(i_right).z)
|
||||||
y = np.interp(
|
x = self.point(i_right).x + fact * \
|
||||||
z,
|
(self.point(i_right + 1).x - self.point(i_right).x)
|
||||||
[self.point(i_right).z, self.point(i_right + 1).z],
|
y = self.point(i_right).y + fact * \
|
||||||
[self.point(i_right).y, self.point(i_right + 1).y]
|
(self.point(i_right + 1).y - self.point(i_right).y)
|
||||||
)
|
pt_right = PointXYZ(x=x, y=y, z=z, name="wl_right")
|
||||||
pt_right = PointXYZ(x, y, z, name="wl_right")
|
|
||||||
else:
|
else:
|
||||||
pt_right = self.point(self.number_points - 1)
|
pt_right = self.point(self.number_points - 1)
|
||||||
|
|
||||||
@@ -755,13 +953,13 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
last_point_not_nan = self._last_point_not_nan(points)
|
last_point_not_nan = self._last_point_not_nan(points)
|
||||||
|
|
||||||
for index, point in enumerate(points):
|
for index, point in enumerate(points):
|
||||||
if point.point_is_named():
|
if point.is_named():
|
||||||
index_first_named_point = index
|
index_first_named_point = index
|
||||||
first_named_point = point
|
first_named_point = point
|
||||||
break
|
break
|
||||||
|
|
||||||
for point in reversed(points):
|
for point in reversed(points):
|
||||||
if point.point_is_named():
|
if point.is_named():
|
||||||
last_named_point = point
|
last_named_point = point
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -832,54 +1030,110 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
Remove points to keep at most np_purge points.
|
Remove points to keep at most np_purge points.
|
||||||
"""
|
"""
|
||||||
if (self.nb_points <= np_purge):
|
if self.nb_points <= np_purge:
|
||||||
return
|
return
|
||||||
|
|
||||||
nb_named = 2 # we consider the first and last point as named
|
nb_named = 0 # we consider the first and last point as named
|
||||||
area = [0.0]
|
area = []
|
||||||
|
|
||||||
for i in range(1, self.nb_points-1):
|
for i, p in enumerate(self.points):
|
||||||
if self.point(i).point_is_named():
|
if p.is_named() or i == 0 or i == self.nb_points - 1:
|
||||||
area.append(9999999.999)
|
area.append((9999999.999, p))
|
||||||
nb_named += 1
|
nb_named += 1
|
||||||
else:
|
else:
|
||||||
area.append(
|
area.append((
|
||||||
PointXYZ.areatriangle3d(
|
PointXYZ.areatriangle3d(
|
||||||
self.point(i-1),
|
self.point(i-1),
|
||||||
self.point(i),
|
p,
|
||||||
self.point(i+1))
|
self.point(i+1)
|
||||||
)
|
),
|
||||||
|
p
|
||||||
area.append(0.0)
|
))
|
||||||
|
|
||||||
while self.nb_points > max(np_purge, nb_named):
|
while self.nb_points > max(np_purge, nb_named):
|
||||||
to_rm = np.argmin(area[1:self.nb_points - 1]) + 1
|
ind, (min_area, p) = min(
|
||||||
|
enumerate(area),
|
||||||
|
key=lambda t: t[1][0]
|
||||||
|
)
|
||||||
|
|
||||||
self.delete_i([to_rm])
|
p.set_as_deleted()
|
||||||
area.pop(to_rm)
|
area.pop(ind)
|
||||||
|
|
||||||
for i in [to_rm-1, to_rm]:
|
for i in [ind-1, ind]:
|
||||||
if (i == 0):
|
p = self.point(i)
|
||||||
continue
|
|
||||||
|
|
||||||
if (i == self.nb_points - 1):
|
if p.is_named() or i == 0 or i == self.nb_points - 1:
|
||||||
continue
|
area[i] = (9999999.999, p)
|
||||||
|
|
||||||
if self.point(i).point_is_named():
|
|
||||||
area[i] = 9999999.999
|
|
||||||
else:
|
else:
|
||||||
area[i] = PointXYZ.areatriangle3d(
|
area[i] = (
|
||||||
self.point(i-1),
|
PointXYZ.areatriangle3d(
|
||||||
self.point(i),
|
self.point(i-1), p, self.point(i+1)
|
||||||
self.point(i+1)
|
),
|
||||||
|
p
|
||||||
)
|
)
|
||||||
|
|
||||||
def shift(self, x, y, z):
|
def shift(self, x, y, z):
|
||||||
for p in self.points:
|
for p in self._points:
|
||||||
p.x = p.x + x
|
p.x = p.x + x
|
||||||
p.y = p.y + y
|
p.y = p.y + y
|
||||||
p.z = p.z + z
|
p.z = p.z + z
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def modified(self):
|
def modified(self):
|
||||||
self.tab_up_to_date = False
|
self.tab_up_to_date = False
|
||||||
self.station_up_to_date = False
|
self.station_up_to_date = False
|
||||||
|
|
||||||
|
def add_npoints(self, npoints):
|
||||||
|
# add npoints in a profile
|
||||||
|
for k in range(npoints):
|
||||||
|
disti = 0.0
|
||||||
|
i = 1
|
||||||
|
for j in range(len(self.points)-1):
|
||||||
|
distj = self.point(j).dist(self.point(j+1))
|
||||||
|
if distj > disti:
|
||||||
|
disti = distj
|
||||||
|
i = j
|
||||||
|
self.insert_point(i, self.point(i).copy())
|
||||||
|
self.point(i+1).name = ''
|
||||||
|
self.point(i+1).x = 0.5 * self.point(i).x + 0.5 * self.point(i+2).x
|
||||||
|
self.point(i+1).y = 0.5 * self.point(i).y + 0.5 * self.point(i+2).y
|
||||||
|
self.point(i+1).z = 0.5 * self.point(i).z + 0.5 * self.point(i+2).z
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
p = ProfileXYZ(name=self.name,
|
||||||
|
rk=self.rk,
|
||||||
|
reach=self.reach,
|
||||||
|
status=self._status)
|
||||||
|
for i, k in enumerate(self.points):
|
||||||
|
p.insert_point(i, k.copy())
|
||||||
|
|
||||||
|
return p
|
||||||
|
|
||||||
|
def purge_aligned_points(self):
|
||||||
|
|
||||||
|
align = True
|
||||||
|
while (align):
|
||||||
|
align = False
|
||||||
|
for i in range(1, self.number_points - 1):
|
||||||
|
d = self.point(i).dist_from_seg(self.point(i-1),
|
||||||
|
self.point(i+1))
|
||||||
|
if d < 0.00001 and self.point(i).name == "":
|
||||||
|
align = True
|
||||||
|
self.delete_i([i])
|
||||||
|
break
|
||||||
|
|
||||||
|
def hard_purge_aligned_points(self):
|
||||||
|
align = True
|
||||||
|
points = self.points
|
||||||
|
while (align):
|
||||||
|
align = False
|
||||||
|
for i in range(1, len(points) - 1):
|
||||||
|
d = points[i].dist_from_seg(points[i-1],
|
||||||
|
points[i+1])
|
||||||
|
if d < 0.00001 and points[i].name == "":
|
||||||
|
align = True
|
||||||
|
points.pop(i)
|
||||||
|
break
|
||||||
|
self._points = points
|
||||||
|
self.modified()
|
||||||
+120
-83
@@ -1,5 +1,5 @@
|
|||||||
# Reach.py -- Pamhyr
|
# Reach.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -45,7 +45,6 @@ class Reach(SQLSubModel):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status=None, parent=None):
|
def __init__(self, status=None, parent=None):
|
||||||
self.id = parent.id if parent is not None else 0
|
|
||||||
self._status = status
|
self._status = status
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self._profiles: List[Profile] = []
|
self._profiles: List[Profile] = []
|
||||||
@@ -53,41 +52,59 @@ class Reach(SQLSubModel):
|
|||||||
self._guidelines_is_valid = False
|
self._guidelines_is_valid = False
|
||||||
self._guidelines = {}
|
self._guidelines = {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pamhyr_id(self):
|
||||||
|
return self._parent.pamhyr_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _pamhyr_id(self):
|
||||||
|
return self._parent.pamhyr_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute):
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = cls(status=data["status"], parent=data["reach"])
|
new = cls(status=data["status"], parent=data["reach"])
|
||||||
|
|
||||||
new._profiles = ProfileXYZ._db_load(
|
new._profiles = sorted(
|
||||||
execute,
|
ProfileXYZ._db_load(
|
||||||
data=data.copy()
|
execute,
|
||||||
|
data=data.copy()
|
||||||
|
),
|
||||||
|
key=lambda p: p._db_ind
|
||||||
)
|
)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
profiles = self.profiles
|
ok = True
|
||||||
|
|
||||||
# Delete old data
|
execute(
|
||||||
execute(f"DELETE FROM geometry_profileXYZ WHERE reach = {self.id}")
|
"DELETE FROM geometry_profileXYZ " +
|
||||||
|
f"WHERE reach = {self.pamhyr_id} " +
|
||||||
if data is None:
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
data = {}
|
)
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for profile in profiles:
|
for profile in self._profiles:
|
||||||
data["ind"] = ind
|
data["ind"] = ind
|
||||||
profile._db_save(execute, data)
|
ok &= profile._db_save(execute, data)
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return True
|
return ok
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
for p in self._profiles:
|
||||||
|
p._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def profile(self, i):
|
def profile(self, i):
|
||||||
"""Returns profile at index i
|
"""Returns profile at index i
|
||||||
@@ -111,31 +128,18 @@ class Reach(SQLSubModel):
|
|||||||
return self._parent.name
|
return self._parent.name
|
||||||
|
|
||||||
def _get_profiles_list(self):
|
def _get_profiles_list(self):
|
||||||
# Profiles list generator is type (int, Point) with the first
|
|
||||||
# element the index of the Point in list
|
|
||||||
logger.debug(f"Load profiles from reach {self.name}")
|
logger.debug(f"Load profiles from reach {self.name}")
|
||||||
return list(
|
return list(self._profiles)
|
||||||
map(
|
|
||||||
lambda p: p[1],
|
|
||||||
sorted(
|
|
||||||
self._profiles,
|
|
||||||
key=lambda p: p[0]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
if not isinstance(self._profiles, list):
|
return len(self.profiles)
|
||||||
self._profiles = self._get_profiles_list()
|
|
||||||
|
|
||||||
return len(self._profiles)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def profiles(self):
|
def profiles(self):
|
||||||
if not isinstance(self._profiles, list):
|
if not isinstance(self._profiles, list):
|
||||||
self._profiles = self._get_profiles_list()
|
self._profiles = self._get_profiles_list()
|
||||||
|
|
||||||
return self._profiles
|
return list(filter(lambda p: not p.is_deleted(), self._profiles))
|
||||||
|
|
||||||
@profiles.setter
|
@profiles.setter
|
||||||
def profiles(self, profiles):
|
def profiles(self, profiles):
|
||||||
@@ -163,15 +167,6 @@ class Reach(SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
return self.profiles
|
return self.profiles
|
||||||
|
|
||||||
def _update_profile_numbers(self):
|
|
||||||
"""Update profiles index
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Nothing.
|
|
||||||
"""
|
|
||||||
for ind, profile in enumerate(self.get_geometry()):
|
|
||||||
profile.num = ind + 1
|
|
||||||
|
|
||||||
def insert(self, index: int):
|
def insert(self, index: int):
|
||||||
"""Insert new profile in list
|
"""Insert new profile in list
|
||||||
|
|
||||||
@@ -183,10 +178,9 @@ class Reach(SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
profile = ProfileXYZ(reach=self, status=self._status)
|
profile = ProfileXYZ(reach=self, status=self._status)
|
||||||
|
|
||||||
self.profiles.insert(index, profile)
|
self._profiles.insert(index, profile)
|
||||||
self._update_profile_numbers()
|
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
return profile
|
return profile
|
||||||
|
|
||||||
@@ -199,9 +193,14 @@ class Reach(SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self.profiles.insert(index, profile)
|
if profile in self._profiles:
|
||||||
self._update_profile_numbers()
|
self.undelete([profile])
|
||||||
self._status.modified()
|
profile.num = index
|
||||||
|
else:
|
||||||
|
profile.num = index
|
||||||
|
self._profiles.insert(index, profile)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def delete(self, indexes):
|
def delete(self, indexes):
|
||||||
"""Delete some elements in profile list
|
"""Delete some elements in profile list
|
||||||
@@ -212,24 +211,36 @@ class Reach(SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
profiles = set(
|
list(
|
||||||
map(
|
map(
|
||||||
lambda e: e[1],
|
lambda p: p[1].set_as_deleted(),
|
||||||
filter(
|
filter(
|
||||||
lambda e: e[0] in indexes,
|
lambda e: e[0] in indexes,
|
||||||
enumerate(self.profiles)
|
enumerate(self._profiles)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
def hard_delete(self, indexes):
|
||||||
|
"""Delete some elements in profile list
|
||||||
|
|
||||||
|
Args:
|
||||||
|
indexes: The list of index to delete
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
"""
|
||||||
self._profiles = list(
|
self._profiles = list(
|
||||||
filter(
|
map(
|
||||||
lambda p: p not in profiles,
|
lambda p: p[1],
|
||||||
self.profiles
|
filter(
|
||||||
|
lambda e: e[0] not in indexes,
|
||||||
|
enumerate(self._profiles)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._update_profile_numbers()
|
self.modified()
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_profiles(self, profiles):
|
def delete_profiles(self, profiles):
|
||||||
"""Delete some elements in profile list
|
"""Delete some elements in profile list
|
||||||
@@ -240,35 +251,41 @@ class Reach(SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self._profiles = list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda p: p not in profiles,
|
lambda p: p.set_as_deleted(),
|
||||||
self.profiles
|
profiles
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._update_profile_numbers()
|
self.modified()
|
||||||
self._status.modified()
|
|
||||||
|
def undelete(self, lst):
|
||||||
|
for el in lst:
|
||||||
|
el.set_as_not_deleted()
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def purge(self):
|
def purge(self):
|
||||||
self._profiles = []
|
for el in self._profiles:
|
||||||
self._update_profile_numbers()
|
el.set_as_deleted()
|
||||||
self._status.modified()
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def move_up_profile(self, index: int):
|
def move_up_profile(self, index: int):
|
||||||
if index < len(self.profiles):
|
if index < len(self._profiles):
|
||||||
next = index - 1
|
next = index - 1
|
||||||
|
|
||||||
p = self.profiles
|
p = self._profiles
|
||||||
p[index], p[next] = p[next], p[index]
|
p[index], p[next] = p[next], p[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def move_down_profile(self, index: int):
|
def move_down_profile(self, index: int):
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
|
|
||||||
p = self.profiles
|
p = self._profiles
|
||||||
p[index], p[prev] = p[prev], p[index]
|
p[index], p[prev] = p[prev], p[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def get_x(self):
|
def get_x(self):
|
||||||
return list(
|
return list(
|
||||||
@@ -496,7 +513,7 @@ class Reach(SQLSubModel):
|
|||||||
self._compute_guidelines_cache(guide_set, named_points,
|
self._compute_guidelines_cache(guide_set, named_points,
|
||||||
complete, incomplete)
|
complete, incomplete)
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
return (complete, incomplete)
|
return (complete, incomplete)
|
||||||
|
|
||||||
def _map_guidelines_points(self, func, full=False):
|
def _map_guidelines_points(self, func, full=False):
|
||||||
@@ -537,28 +554,28 @@ class Reach(SQLSubModel):
|
|||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort(self, is_reversed: bool = False):
|
def sort(self, is_reversed: bool = False):
|
||||||
self.profiles = sorted(
|
self._profiles = sorted(
|
||||||
self.profiles,
|
self._profiles,
|
||||||
key=lambda profile: profile.rk,
|
key=lambda profile: profile.rk,
|
||||||
reverse=is_reversed
|
reverse=is_reversed
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort_with_indexes(self, indexes: list):
|
def sort_with_indexes(self, indexes: list):
|
||||||
if len(self.profiles) != len(indexes):
|
if len(self._profiles) != len(indexes):
|
||||||
logger.critical("Indexes list do not correspond to profile list")
|
logger.critical("Indexes list do not correspond to profile list")
|
||||||
|
|
||||||
self.profiles = list(
|
self._profiles = list(
|
||||||
map(
|
map(
|
||||||
lambda x: x[1],
|
lambda x: x[1],
|
||||||
sorted(
|
sorted(
|
||||||
enumerate(self.profiles),
|
enumerate(self._profiles),
|
||||||
key=lambda x: indexes[x[0]]
|
key=lambda x: indexes[x[0]]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
# Import/Export
|
# Import/Export
|
||||||
|
|
||||||
@@ -614,8 +631,7 @@ class Reach(SQLSubModel):
|
|||||||
|
|
||||||
profiles.append(prof)
|
profiles.append(prof)
|
||||||
|
|
||||||
self.profiles = profiles + self.profiles
|
self._profiles = profiles + self._profiles
|
||||||
self._update_profile_numbers()
|
|
||||||
self._recompute_rk()
|
self._recompute_rk()
|
||||||
|
|
||||||
return profiles
|
return profiles
|
||||||
@@ -633,6 +649,8 @@ class Reach(SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
imported_profiles = []
|
imported_profiles = []
|
||||||
|
|
||||||
|
logger.info(f"import reach from {file_path_name}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
list_profile, list_header = self.read_file_st(str(file_path_name))
|
list_profile, list_header = self.read_file_st(str(file_path_name))
|
||||||
profile_header = ["num", "code1", "code2",
|
profile_header = ["num", "code1", "code2",
|
||||||
@@ -645,12 +663,15 @@ class Reach(SQLSubModel):
|
|||||||
d[profile_header[i]] = data
|
d[profile_header[i]] = data
|
||||||
|
|
||||||
prof = ProfileXYZ(
|
prof = ProfileXYZ(
|
||||||
**d, reach=self, status=self._status
|
id=-1,
|
||||||
|
**d,
|
||||||
|
reach=self,
|
||||||
|
status=self._status
|
||||||
)
|
)
|
||||||
prof.import_points(profile)
|
prof.import_points(profile)
|
||||||
|
|
||||||
imported_profiles.append(prof)
|
imported_profiles.append(prof)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
exception_message_box(e)
|
exception_message_box(e)
|
||||||
@@ -658,9 +679,8 @@ class Reach(SQLSubModel):
|
|||||||
logger.error(e)
|
logger.error(e)
|
||||||
e.alert()
|
e.alert()
|
||||||
finally:
|
finally:
|
||||||
self.profiles = imported_profiles + self.profiles
|
self._profiles = self._profiles + imported_profiles
|
||||||
|
|
||||||
self._update_profile_numbers()
|
|
||||||
return imported_profiles
|
return imported_profiles
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
@@ -894,3 +914,20 @@ class Reach(SQLSubModel):
|
|||||||
|
|
||||||
profile.rk = previous.rk + dist
|
profile.rk = previous.rk + dist
|
||||||
previous = profile
|
previous = profile
|
||||||
|
|
||||||
|
def _split(self, profile, reach1, reach2):
|
||||||
|
if profile is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
nr1 = Reach(status=self._status, parent=reach1)
|
||||||
|
nr2 = Reach(status=self._status, parent=reach2)
|
||||||
|
|
||||||
|
ind = self.profiles.index(profile)
|
||||||
|
|
||||||
|
nr1_profiles = self.profiles[:ind+1]
|
||||||
|
nr2_profiles = self.profiles[ind:]
|
||||||
|
|
||||||
|
nr1._profiles = list(map(lambda p: p.cloned_for(nr1), nr1_profiles))
|
||||||
|
nr2._profiles = list(map(lambda p: p.cloned_for(nr2), nr2_profiles))
|
||||||
|
|
||||||
|
return nr1, nr2
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Vector_1d.py -- Pamhyr
|
# Vector_1d.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# HydraulicStructures.py -- Pamhyr
|
# HydraulicStructures.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,6 +21,7 @@ import logging
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Scenario import Scenario
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.HydraulicStructures.Basic.Value import (
|
from Model.HydraulicStructures.Basic.Value import (
|
||||||
@@ -34,49 +35,97 @@ class BasicHS(SQLSubModel):
|
|||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
BHSValue,
|
BHSValue,
|
||||||
]
|
]
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(BasicHS, self).__init__()
|
super(BasicHS, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
self._status = status
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
if id == -1:
|
|
||||||
self.id = BasicHS._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._type = ""
|
self._type = ""
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
BasicHS._id_cnt = max(BasicHS._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE hydraulic_structures_basic(
|
CREATE TABLE hydraulic_structures_basic{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type TEXT NOT NULL,
|
type TEXT NOT NULL,
|
||||||
enabled BOOLEAN NOT NULL,
|
enabled BOOLEAN NOT NULL,
|
||||||
hs INTEGER,
|
hs INTEGER,
|
||||||
FOREIGN KEY(hs) REFERENCES hydraulic_structures(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(hs) REFERENCES hydraulic_structures(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
if ext == "_tmp":
|
||||||
|
return True
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
return True
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE hydraulic_structures_basic " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "hydraulic_structures_basic"
|
||||||
|
hs = data['id2pid']['hydraulic_structures']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
cls._db_update_to_0_2_0_set_hs_pid(execute, table, hs)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, name, type, enabled, hs, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, type, enabled, hs, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_hs_pid(cls, execute, table, hs):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, hs FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
hs_id = next(it)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET hs = {hs[hs_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_ctor_from_type(cls, t):
|
def _get_ctor_from_type(cls, t):
|
||||||
@@ -94,58 +143,85 @@ class BasicHS(SQLSubModel):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data["status"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return []
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name, type, enabled, hs " +
|
"SELECT pamhyr_id, deleted, name, type, enabled, hs, scenario " +
|
||||||
"FROM hydraulic_structures_basic " +
|
"FROM hydraulic_structures_basic " +
|
||||||
f"WHERE hs = {data['hs_id']} "
|
f"WHERE hs = {data['hs_id']} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
bhs_id = row[0]
|
it = iter(row)
|
||||||
name = row[1]
|
|
||||||
type = row[2]
|
bhs_pid = next(it)
|
||||||
enabled = (row[3] == 1)
|
deleted = (next(it) == 1)
|
||||||
hs_id = row[4]
|
name = next(it)
|
||||||
|
type = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
hs_id = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
ctor = cls._get_ctor_from_type(type)
|
ctor = cls._get_ctor_from_type(type)
|
||||||
bhs = ctor(
|
bhs = ctor(
|
||||||
id=bhs_id,
|
id=bhs_pid, name=name,
|
||||||
name=name,
|
status=status, owner_scenario=owner_scenario
|
||||||
status=data['status']
|
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
bhs.set_as_deleted()
|
||||||
|
|
||||||
bhs.enabled = enabled
|
bhs.enabled = enabled
|
||||||
|
|
||||||
data['bhs_id'] = bhs_id
|
data['bhs_id'] = bhs_pid
|
||||||
bhs._data = BHSValue._db_load(
|
bhs._data = BHSValue._db_load(
|
||||||
execute, data
|
execute, data
|
||||||
)
|
)
|
||||||
|
print(f"{bhs_pid} : {deleted}")
|
||||||
|
if deleted:
|
||||||
|
bhs.set_as_deleted()
|
||||||
|
|
||||||
new.append(bhs)
|
new.append(bhs)
|
||||||
|
loaded.add(bhs_pid)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
hs_id = data['hs_id']
|
hs_id = data['hs_id']
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"hydraulic_structures_basic(id, name, type, enabled, hs) " +
|
"hydraulic_structures_basic(pamhyr_id, deleted, " +
|
||||||
|
"name, type, enabled, hs, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, " +
|
f"{self.pamhyr_id}, " +
|
||||||
|
f"{self._db_format(self.is_deleted())}, " +
|
||||||
f"'{self._db_format(self._name)}', " +
|
f"'{self._db_format(self._name)}', " +
|
||||||
f"'{self._db_format(self._type)}', " +
|
f"'{self._db_format(self._type)}', " +
|
||||||
f"{self._db_format(self.enabled)}, " +
|
f"{self._db_format(self.enabled)}, " +
|
||||||
f"{hs_id} " +
|
f"{hs_id}, " +
|
||||||
|
f"{self._status.scenario_id}"
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
data['bhs_id'] = self.id
|
data['bhs_id'] = self.pamhyr_id
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM hydraulic_structures_basic_value " +
|
"DELETE FROM hydraulic_structures_basic_value " +
|
||||||
f"WHERE bhs = {self.id}"
|
f"WHERE bhs = {self.pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
for values in self._data:
|
for values in self._data:
|
||||||
@@ -153,20 +229,30 @@ class BasicHS(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self._data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._name == "":
|
if self._name == "":
|
||||||
return f"{self._type}{self.id + 1}"
|
return f"{self._type} #{self.pamhyr_id}"
|
||||||
|
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
@@ -175,7 +261,7 @@ class BasicHS(SQLSubModel):
|
|||||||
@type.setter
|
@type.setter
|
||||||
def type(self, type):
|
def type(self, type):
|
||||||
self._type = type
|
self._type = type
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
@@ -184,7 +270,7 @@ class BasicHS(SQLSubModel):
|
|||||||
@enabled.setter
|
@enabled.setter
|
||||||
def enabled(self, enabled):
|
def enabled(self, enabled):
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parameters(self):
|
def parameters(self):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Types.py -- Pamhyr
|
# Types.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,10 +27,11 @@ from Model.HydraulicStructures.Basic.Value import (
|
|||||||
|
|
||||||
class NotDefined(BasicHS):
|
class NotDefined(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(NotDefined, self).__init__(
|
super(NotDefined, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "ND"
|
self._type = "ND"
|
||||||
@@ -39,197 +40,208 @@ class NotDefined(BasicHS):
|
|||||||
|
|
||||||
class DischargeWeir(BasicHS):
|
class DischargeWeir(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(DischargeWeir, self).__init__(
|
super(DischargeWeir, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "S1"
|
self._type = "S1"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("width", float, 1.0, status=status),
|
BHSValue(-1, "width", float, 1.0, status=status),
|
||||||
BHSValue("elevation", float, 1.0, status=status),
|
BHSValue(-1, "elevation", float, 1.0, status=status),
|
||||||
BHSValue("discharge_coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge_coefficient", float, 0.4, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class TrapezoidalWeir(BasicHS):
|
class TrapezoidalWeir(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(TrapezoidalWeir, self).__init__(
|
super(TrapezoidalWeir, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "S2"
|
self._type = "S2"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("width", float, 1.0, status=status),
|
BHSValue(-1, "width", float, 1.0, status=status),
|
||||||
BHSValue("elevation", float, 1.0, status=status),
|
BHSValue(-1, "elevation", float, 1.0, status=status),
|
||||||
BHSValue("loading_elevation", float, 9999.999, status=status),
|
BHSValue(-1, "loading_elevation", float, 9999.999, status=status),
|
||||||
BHSValue("discharge_coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge_coefficient", float, 0.4, status=status),
|
||||||
BHSValue("half-angle_tangent", float, 0.0, status=status),
|
BHSValue(-1, "half-angle_tangent", float, 0.0, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class TriangularWeir(BasicHS):
|
class TriangularWeir(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(TriangularWeir, self).__init__(
|
super(TriangularWeir, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "S3"
|
self._type = "S3"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("elevation", float, 1.0, status=status),
|
BHSValue(-1, "elevation", float, 1.0, status=status),
|
||||||
BHSValue("loading_elevation", float, 9999.999, status=status),
|
BHSValue(-1, "loading_elevation", float, 9999.999, status=status),
|
||||||
BHSValue("discharge_coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge_coefficient", float, 0.31, status=status),
|
||||||
BHSValue("half-angle_tangent", float, 0.0, status=status),
|
BHSValue(-1, "half-angle_tangent", float, 1.0, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RectangularOrifice(BasicHS):
|
class RectangularOrifice(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(RectangularOrifice, self).__init__(
|
super(RectangularOrifice, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "OR"
|
self._type = "OR"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("width", float, 0.0, status=status),
|
BHSValue(-1, "width", float, 0.0, status=status),
|
||||||
BHSValue("elevation", float, 0.0, status=status),
|
BHSValue(-1, "elevation", float, 0.0, status=status),
|
||||||
BHSValue("loading_elevation", float, 9999.999,
|
BHSValue(-1, "loading_elevation", float, 9999.999,
|
||||||
status=status),
|
status=status),
|
||||||
BHSValue("discharge_coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge_coefficient", float, 0.4, status=status),
|
||||||
BHSValue("maximal_loading_elevation", float, 9999.999,
|
BHSValue(-1, "maximal_loading_elevation", float, 9999.999,
|
||||||
status=status),
|
status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class CircularOrifice(BasicHS):
|
class CircularOrifice(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(CircularOrifice, self).__init__(
|
super(CircularOrifice, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "OC"
|
self._type = "OC"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("diameter", float, 0.0, status=status),
|
BHSValue(-1, "diameter", float, 0.0, status=status),
|
||||||
BHSValue("elevation", float, 0.0, status=status),
|
BHSValue(-1, "elevation", float, 0.0, status=status),
|
||||||
BHSValue("siltation_height", float, 0.0, status=status),
|
BHSValue(-1, "siltation_height", float, 0.0, status=status),
|
||||||
BHSValue("discharge_coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge_coefficient", float, 0.4, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class VaultedOrifice(BasicHS):
|
class VaultedOrifice(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(VaultedOrifice, self).__init__(
|
super(VaultedOrifice, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "OV"
|
self._type = "OV"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("elevation", float, 1.0, status=status),
|
BHSValue(-1, "elevation", float, 1.0, status=status),
|
||||||
BHSValue("width", float, 1.0, status=status),
|
BHSValue(-1, "width", float, 1.0, status=status),
|
||||||
BHSValue("top_of_the_vault", float, 0.0, status=status),
|
BHSValue(-1, "top_of_the_vault", float, 0.0, status=status),
|
||||||
BHSValue("bottom_of_the_vault", float, 0.0, status=status),
|
BHSValue(-1, "bottom_of_the_vault", float, 0.0, status=status),
|
||||||
BHSValue("discharge_coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge_coefficient", float, 0.4, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RectangularGate(BasicHS):
|
class RectangularGate(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(RectangularGate, self).__init__(
|
super(RectangularGate, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "V1"
|
self._type = "V1"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("width", float, 1.0, status=status),
|
BHSValue(-1, "width", float, 1.0, status=status),
|
||||||
BHSValue("elevation", float, 0.0, status=status),
|
BHSValue(-1, "elevation", float, 0.0, status=status),
|
||||||
BHSValue("discharge coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge coefficient", float, 0.4, status=status),
|
||||||
BHSValue("opening", float, 1.0, status=status),
|
BHSValue(-1, "opening", float, 1.0, status=status),
|
||||||
BHSValue("maximal_opening", float, 1.0, status=status),
|
BHSValue(-1, "maximal_opening", float, 1.0, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SimplifiedRectangularGate(BasicHS):
|
class SimplifiedRectangularGate(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(SimplifiedRectangularGate, self).__init__(
|
super(SimplifiedRectangularGate, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "V2"
|
self._type = "V2"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("width", float, 1.0, status=status),
|
BHSValue(-1, "width", float, 1.0, status=status),
|
||||||
BHSValue("elevation", float, 0.0, status=status),
|
BHSValue(-1, "elevation", float, 0.0, status=status),
|
||||||
BHSValue("discharge coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge coefficient", float, 0.4, status=status),
|
||||||
BHSValue("opening", float, 1.0, status=status),
|
BHSValue(-1, "opening", float, 1.0, status=status),
|
||||||
BHSValue("maximal_opening", float, 1.0, status=status),
|
BHSValue(-1, "maximal_opening", float, 1.0, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Borda(BasicHS):
|
class Borda(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(Borda, self).__init__(
|
super(Borda, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "BO"
|
self._type = "BO"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("step_space", float, 0.1, status=status),
|
BHSValue(-1, "step_space", float, 0.1, status=status),
|
||||||
BHSValue("weir", float, 0.15, status=status),
|
BHSValue(-1, "weir", float, 0.15, status=status),
|
||||||
BHSValue("coefficient", float, 0.4, status=status),
|
BHSValue(-1, "coefficient", float, 0.4, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class CheckValve(BasicHS):
|
class CheckValve(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(CheckValve, self).__init__(
|
super(CheckValve, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "CV"
|
self._type = "CV"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("width", float, 0.0, status=status),
|
BHSValue(-1, "width", float, 0.0, status=status),
|
||||||
BHSValue("elevation", float, 0.0, status=status),
|
BHSValue(-1, "elevation", float, 0.0, status=status),
|
||||||
BHSValue("loading_elevation", float, 9999.999,
|
BHSValue(-1, "loading_elevation", float, 9999.999,
|
||||||
status=status),
|
status=status),
|
||||||
BHSValue("discharge_coefficient", float, 0.4, status=status),
|
BHSValue(-1, "discharge_coefficient", float, 0.4, status=status),
|
||||||
BHSValue("maximal_loading_elevation", float, 9999.999,
|
BHSValue(-1, "maximal_loading_elevation", float, 9999.999,
|
||||||
status=status),
|
status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class UserDefined(BasicHS):
|
class UserDefined(BasicHS):
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(UserDefined, self).__init__(
|
super(UserDefined, self).__init__(
|
||||||
id=id, name=name,
|
id=id, name=name,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
|
||||||
self._type = "UD"
|
self._type = "UD"
|
||||||
self._data = [
|
self._data = [
|
||||||
BHSValue("parameter_1", float, 0.0, status=status),
|
BHSValue(-1, "parameter_1", float, 0.0, status=status),
|
||||||
BHSValue("parameter_2", float, 0.0, status=status),
|
BHSValue(-1, "parameter_2", float, 0.0, status=status),
|
||||||
BHSValue("parameter_3", float, 0.0, status=status),
|
BHSValue(-1, "parameter_3", float, 0.0, status=status),
|
||||||
BHSValue("parameter_4", float, 0.0, status=status),
|
BHSValue(-1, "parameter_4", float, 0.0, status=status),
|
||||||
BHSValue("parameter_5", float, 0.0, status=status),
|
BHSValue(-1, "parameter_5", float, 0.0, status=status),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Value.py -- Pamhyr
|
# Value.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -17,45 +17,92 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
|
|
||||||
class BHSValue(SQLSubModel):
|
class BHSValue(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, name: str = "", type=float, value=0.0,
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
type=float, value=0.0,
|
||||||
super(BHSValue, self).__init__()
|
status=None, owner_scenario=-1):
|
||||||
|
super(BHSValue, self).__init__(
|
||||||
self._status = status
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._type = type
|
self._type = type
|
||||||
self._value = type(value)
|
self._value = type(value)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE hydraulic_structures_basic_value(
|
CREATE TABLE hydraulic_structures_basic_value{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type TEXT NOT NULL,
|
type TEXT NOT NULL,
|
||||||
value TEXT NOT NULL,
|
value TEXT NOT NULL,
|
||||||
bhs INTEGER,
|
bhs INTEGER,
|
||||||
FOREIGN KEY(bhs) REFERENCES hydraulic_structures_basic(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(bhs) REFERENCES hydraulic_structures_basic(id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
return True
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "hydraulic_structures_basic_value"
|
||||||
|
bhs = data['id2pid']['hydraulic_structures_basic']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
cls._db_update_to_0_2_0_set_bhs_pid(execute, table, bhs)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, name, type, value, bhs, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, type, value, bhs, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_bhs_pid(cls, execute, table, bhs):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, bhs FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
bhs_id = next(it)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET bhs = {bhs[bhs_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _str_to_type(cls, type):
|
def _str_to_type(cls, type):
|
||||||
@@ -86,44 +133,62 @@ class BHSValue(SQLSubModel):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data["status"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
bhs_id = data["bhs_id"]
|
bhs_id = data["bhs_id"]
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return []
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT name, type, value " +
|
"SELECT pamhyr_id, name, type, value, scenario " +
|
||||||
"FROM hydraulic_structures_basic_value " +
|
"FROM hydraulic_structures_basic_value " +
|
||||||
f"WHERE bhs = '{bhs_id}'"
|
f"WHERE bhs = '{bhs_id}' " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
name = row[0]
|
it = iter(row)
|
||||||
type = cls._str_to_type(row[1])
|
|
||||||
value = row[2]
|
pid = next(it)
|
||||||
|
name = next(it)
|
||||||
|
type = cls._str_to_type(next(it))
|
||||||
|
value = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
val = cls(
|
val = cls(
|
||||||
name=name,
|
id=pid, name=name,
|
||||||
type=type,
|
type=type, value=value,
|
||||||
value=value,
|
status=status, owner_scenario=owner_scenario
|
||||||
status=data['status']
|
|
||||||
)
|
)
|
||||||
|
|
||||||
new.append(val)
|
new.append(val)
|
||||||
|
loaded.add(pid)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
bhs_id = data["bhs_id"]
|
bhs_id = data["bhs_id"]
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"hydraulic_structures_basic_value(name, type, value, bhs) " +
|
"hydraulic_structures_basic_value" +
|
||||||
|
"(pamhyr_id, name, type, value, bhs, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
|
f"{self._pamhyr_id}, " +
|
||||||
f"'{self._db_format(self._name)}', " +
|
f"'{self._db_format(self._name)}', " +
|
||||||
f"'{self._db_format(self._type_to_str(self._type))}', " +
|
f"'{self._db_format(self._type_to_str(self._type))}', " +
|
||||||
f"'{self._db_format(self._value)}', " +
|
f"'{self._db_format(self._value)}', " +
|
||||||
f"{bhs_id}" +
|
f"{bhs_id}, " +
|
||||||
|
f"{self._status.scenario_id}"
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -142,4 +207,4 @@ class BHSValue(SQLSubModel):
|
|||||||
@value.setter
|
@value.setter
|
||||||
def value(self, value):
|
def value(self, value):
|
||||||
self._value = self._type(value)
|
self._value = self._type(value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# HydraulicStructures.py -- Pamhyr
|
# HydraulicStructures.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,6 +22,7 @@ from functools import reduce
|
|||||||
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Scenario import Scenario
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.HydraulicStructures.Basic.HydraulicStructures import BasicHS
|
from Model.HydraulicStructures.Basic.HydraulicStructures import BasicHS
|
||||||
@@ -36,163 +37,289 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
BasicHS,
|
BasicHS,
|
||||||
]
|
]
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(HydraulicStructure, self).__init__()
|
super(HydraulicStructure, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
self._status = status
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
if id == -1:
|
|
||||||
self.id = HydraulicStructure._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._input_rk = None
|
self._input_section = None
|
||||||
self._output_rk = None
|
self._output_section = None
|
||||||
self._input_reach = None
|
self._input_reach = None
|
||||||
self._output_reach = None
|
self._output_reach = None
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
HydraulicStructure._id_cnt = max(
|
|
||||||
HydraulicStructure._id_cnt + 1,
|
|
||||||
self.id
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
execute("""
|
CREATE TABLE hydraulic_structures{ext} (
|
||||||
CREATE TABLE hydraulic_structures(
|
{cls.create_db_add_pamhyr_id()},
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
enabled BOOLEAN NOT NULL,
|
enabled BOOLEAN NOT NULL,
|
||||||
input_rk REAL NOT NULL,
|
|
||||||
output_rk REAL NOT NULL,
|
|
||||||
input_reach INTEGER,
|
input_reach INTEGER,
|
||||||
output_reach INTEGER,
|
output_reach INTEGER,
|
||||||
FOREIGN KEY(input_reach) REFERENCES river_reach(id),
|
input_section INTEGER,
|
||||||
FOREIGN KEY(output_reach) REFERENCES river_reach(id)
|
output_section INTEGER,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(input_reach) REFERENCES river_reach(pamhyr_id),
|
||||||
|
FOREIGN KEY(output_reach) REFERENCES river_reach(pamhyr_id),
|
||||||
|
FOREIGN KEY(input_section)
|
||||||
|
REFERENCES geometry_profileXYZ(pamhyr_id),
|
||||||
|
FOREIGN KEY(output_section)
|
||||||
|
REFERENCES geometry_profileXYZ(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
if ext == "_tmp":
|
||||||
|
return True
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
rl = int(release)
|
||||||
rl = int(release)
|
|
||||||
|
|
||||||
|
if major == minor == "0":
|
||||||
if rl < 6:
|
if rl < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
return True
|
||||||
|
|
||||||
if rl < 11:
|
if rl < 11:
|
||||||
|
for v in ["input", "output"]:
|
||||||
|
execute(
|
||||||
|
f"""
|
||||||
|
ALTER TABLE hydraulic_structures
|
||||||
|
RENAME COLUMN {v}_kp TO {v}_rk
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if rl < 1:
|
||||||
|
cls._db_update_to_0_1_1(execute, data)
|
||||||
|
|
||||||
|
if rl < 2:
|
||||||
execute(
|
execute(
|
||||||
"""
|
"ALTER TABLE hydraulic_structures " +
|
||||||
ALTER TABLE hydraulic_structures
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
RENAME COLUMN input_kp TO input_rk
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
execute(
|
|
||||||
"""
|
|
||||||
ALTER TABLE hydraulic_structures
|
|
||||||
RENAME COLUMN output_kp TO output_rk
|
|
||||||
"""
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "hydraulic_structures"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table, reachs)
|
||||||
|
cls._db_update_to_0_1_1(
|
||||||
|
execute, data,
|
||||||
|
origin_version="0.0.*"
|
||||||
|
)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, name, enabled, input_section, output_section, " +
|
||||||
|
"input_reach, output_reach, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, enabled, " +
|
||||||
|
"input_section, output_section, " +
|
||||||
|
"input_reach, output_reach, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_reach_pid(cls, execute, table, reachs):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, input_reach, output_reach FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
in_reach_id = next(it)
|
||||||
|
out_reach_id = next(it)
|
||||||
|
|
||||||
|
if in_reach_id == -1:
|
||||||
|
return
|
||||||
|
|
||||||
|
if out_reach_id == -1:
|
||||||
|
out_reach_id = in_reach_id
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET input_reach = {reachs[in_reach_id]}, " +
|
||||||
|
f"output_reach = {reachs[out_reach_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_1_1(cls, execute, data,
|
||||||
|
origin_version="0.1.0"):
|
||||||
|
for v in ["input", "output"]:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE hydraulic_structures " +
|
||||||
|
f"ADD COLUMN {v}_section INTEGER"
|
||||||
|
)
|
||||||
|
|
||||||
|
cls._db_update_to_0_1_1_assoc_section_from_rk(
|
||||||
|
execute, "hydraulic_structures",
|
||||||
|
reach_column=f"{v}_reach",
|
||||||
|
rk_column=f"{v}_rk",
|
||||||
|
section_column=f"{v}_section",
|
||||||
|
origin_version=origin_version
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data["status"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return []
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name, enabled, " +
|
"SELECT pamhyr_id, deleted, name, enabled, " +
|
||||||
"input_rk, output_rk, " +
|
"input_section, output_section, " +
|
||||||
"input_reach, output_reach " +
|
"input_reach, output_reach, scenario " +
|
||||||
"FROM hydraulic_structures "
|
"FROM hydraulic_structures " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
it = iter(row)
|
new.append(cls._db_load_new(execute, data, row))
|
||||||
|
|
||||||
hs_id = next(it)
|
data["scenario"] = scenario.parent
|
||||||
name = next(it)
|
new += cls._db_load(execute, data)
|
||||||
enabled = (next(it) == 1)
|
data["scenario"] = scenario
|
||||||
input_rk = next(it)
|
|
||||||
output_rk = next(it)
|
|
||||||
input_reach_id = next(it)
|
|
||||||
output_reach_id = next(it)
|
|
||||||
|
|
||||||
hs = cls(
|
|
||||||
id=hs_id,
|
|
||||||
name=name,
|
|
||||||
status=data['status']
|
|
||||||
)
|
|
||||||
|
|
||||||
hs.enabled = enabled
|
|
||||||
hs.input_rk = input_rk if input_rk != -1 else None
|
|
||||||
hs.output_rk = output_rk if output_rk != -1 else None
|
|
||||||
|
|
||||||
hs.input_reach, hs.output_reach = reduce(
|
|
||||||
lambda acc, n: (
|
|
||||||
n if n.id == input_reach_id else acc[0],
|
|
||||||
n if n.id == output_reach_id else acc[1]
|
|
||||||
),
|
|
||||||
data["edges"],
|
|
||||||
[None, None]
|
|
||||||
)
|
|
||||||
|
|
||||||
data['hs_id'] = hs_id
|
|
||||||
hs._data = BasicHS._db_load(execute, data)
|
|
||||||
|
|
||||||
new.append(hs)
|
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load_new(cls, execute, data, row):
|
||||||
|
it = iter(row)
|
||||||
|
status = data["status"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
hs_id = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
input_section_id = next(it)
|
||||||
|
input_section_id = (
|
||||||
|
-1 if input_section_id is None else input_section_id
|
||||||
|
)
|
||||||
|
output_section_id = next(it)
|
||||||
|
output_section_id = (
|
||||||
|
-1 if output_section_id is None else output_section_id
|
||||||
|
)
|
||||||
|
input_reach_id = next(it)
|
||||||
|
output_reach_id = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
hs = cls(
|
||||||
|
id=hs_id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
hs.set_as_deleted()
|
||||||
|
|
||||||
|
hs.enabled = enabled
|
||||||
|
hs.input_reach, hs.output_reach = reduce(
|
||||||
|
lambda acc, n: (
|
||||||
|
n if n.pamhyr_id == input_reach_id else acc[0],
|
||||||
|
n if n.pamhyr_id == output_reach_id else acc[1]
|
||||||
|
),
|
||||||
|
data["edges"],
|
||||||
|
[None, None]
|
||||||
|
)
|
||||||
|
sections = []
|
||||||
|
if hs.input_reach is not None:
|
||||||
|
sections += hs.input_reach.reach.profiles
|
||||||
|
if hs.output_reach is not None:
|
||||||
|
sections += hs.output_reach.reach.profiles
|
||||||
|
|
||||||
|
hs.input_section, hs.output_section = reduce(
|
||||||
|
lambda acc, s: (
|
||||||
|
s if s.pamhyr_id == input_section_id else acc[0],
|
||||||
|
s if s.pamhyr_id == output_section_id else acc[1]
|
||||||
|
),
|
||||||
|
sections,
|
||||||
|
[None, None]
|
||||||
|
)
|
||||||
|
|
||||||
|
loaded.add(hs_id)
|
||||||
|
|
||||||
|
data['hs_id'] = hs_id
|
||||||
|
hs._data = BasicHS._db_load(execute, data)
|
||||||
|
|
||||||
|
return hs
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
print("save hs unit")
|
execute(
|
||||||
execute(f"DELETE FROM hydraulic_structures WHERE id = {self.id}")
|
"DELETE FROM hydraulic_structures " +
|
||||||
|
f"WHERE pamhyr_id = {self.pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
input_reach_id = -1
|
input_reach_id = -1
|
||||||
if self._input_reach is not None:
|
if self._input_reach is not None:
|
||||||
input_reach_id = self._input_reach.id
|
input_reach_id = self._input_reach.pamhyr_id
|
||||||
|
|
||||||
output_reach_id = -1
|
output_reach_id = -1
|
||||||
if self._output_reach is not None:
|
if self._output_reach is not None:
|
||||||
output_reach_id = self._output_reach.id
|
output_reach_id = self._output_reach.pamhyr_id
|
||||||
|
|
||||||
input_rk = -1
|
input_section = 'NULL'
|
||||||
if self.input_rk is not None:
|
if self.input_section is not None:
|
||||||
input_rk = self.input_rk
|
input_section = self.input_section.pamhyr_id
|
||||||
|
|
||||||
output_rk = -1
|
output_section = 'NULL'
|
||||||
if self.output_rk is not None:
|
if self.output_section is not None:
|
||||||
output_rk = self.output_rk
|
output_section = self.output_section.pamhyr_id
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"hydraulic_structures(" +
|
"hydraulic_structures(" +
|
||||||
" id, name, enabled, input_rk, output_rk, " +
|
" pamhyr_id, deleted, name, enabled, " +
|
||||||
" input_reach, output_reach" +
|
" input_section, output_section, " +
|
||||||
|
" input_reach, output_reach, " +
|
||||||
|
" scenario" +
|
||||||
") " +
|
") " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._db_format(self._name)}', " +
|
f"{self.pamhyr_id}, " +
|
||||||
|
f"{self._db_format(self.is_deleted())}, " +
|
||||||
|
f"'{self._db_format(self._name)}', " +
|
||||||
f"{self._db_format(self.enabled)}, " +
|
f"{self._db_format(self.enabled)}, " +
|
||||||
f"{input_rk}, {output_rk}, " +
|
f"{input_section}, {output_section}, " +
|
||||||
f"{input_reach_id}, {output_reach_id}" +
|
f"{input_reach_id}, {output_reach_id}, " +
|
||||||
|
f"{self._status.scenario_id}"
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
data['hs_id'] = self.id
|
data['hs_id'] = self.pamhyr_id
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM hydraulic_structures_basic " +
|
"DELETE FROM hydraulic_structures_basic " +
|
||||||
f"WHERE hs = {self.id}"
|
f"WHERE hs = {self.pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
for basic in self._data:
|
for basic in self._data:
|
||||||
@@ -200,41 +327,71 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self.lst)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lst(self):
|
||||||
|
return list(
|
||||||
|
filter(
|
||||||
|
lambda bhs: not bhs.is_deleted(),
|
||||||
|
self._data,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._name == "":
|
if self._name == "":
|
||||||
return f"HS{self.id + 1}"
|
return f"HS #{self.pamhyr_id}"
|
||||||
|
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def input_rk(self):
|
def input_rk(self):
|
||||||
return self._input_rk
|
if self._input_section is None:
|
||||||
|
return None
|
||||||
|
|
||||||
@input_rk.setter
|
return self._input_section
|
||||||
def input_rk(self, input_rk):
|
|
||||||
if input_rk is not None:
|
|
||||||
input_rk = float(input_rk)
|
|
||||||
|
|
||||||
self._input_rk = input_rk
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def output_rk(self):
|
def output_rk(self):
|
||||||
return self._output_rk
|
if self._output_section is None:
|
||||||
|
return None
|
||||||
|
|
||||||
@output_rk.setter
|
return self._output_section
|
||||||
def output_rk(self, output_rk):
|
|
||||||
self._output_rk = output_rk
|
@property
|
||||||
self._status.modified()
|
def input_section(self):
|
||||||
|
return self._input_section
|
||||||
|
|
||||||
|
@input_section.setter
|
||||||
|
def input_section(self, input_section):
|
||||||
|
self._input_section = input_section
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def output_section(self):
|
||||||
|
return self._output_section
|
||||||
|
|
||||||
|
@output_section.setter
|
||||||
|
def output_section(self, output_section):
|
||||||
|
self._output_section = output_section
|
||||||
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
@@ -243,7 +400,7 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
@enabled.setter
|
@enabled.setter
|
||||||
def enabled(self, enabled):
|
def enabled(self, enabled):
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def input_reach(self):
|
def input_reach(self):
|
||||||
@@ -252,7 +409,7 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
@input_reach.setter
|
@input_reach.setter
|
||||||
def input_reach(self, input_reach):
|
def input_reach(self, input_reach):
|
||||||
self._input_reach = input_reach
|
self._input_reach = input_reach
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def output_reach(self):
|
def output_reach(self):
|
||||||
@@ -261,26 +418,34 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
@output_reach.setter
|
@output_reach.setter
|
||||||
def output_reach(self, output_reach):
|
def output_reach(self, output_reach):
|
||||||
self._output_reach = output_reach
|
self._output_reach = output_reach
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def basic_structures(self):
|
def basic_structures(self):
|
||||||
return self._data.copy()
|
return self.lst.copy()
|
||||||
|
|
||||||
def basic_structure(self, index: int):
|
def basic_structure(self, index: int):
|
||||||
return self._data[index]
|
if len(self._data) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.lst[index]
|
||||||
|
|
||||||
def add(self, index: int):
|
def add(self, index: int):
|
||||||
value = NotDefined(status=self._status)
|
value = NotDefined(status=self._status)
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
|
||||||
|
self.modified()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def insert(self, index: int, value: BasicHS):
|
def insert(self, index: int, value: BasicHS):
|
||||||
self._data.insert(index, value)
|
if value in self._data:
|
||||||
self._status.modified()
|
value.set_as_not_deleted()
|
||||||
|
else:
|
||||||
|
self._data.insert(index, value)
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
self.modified()
|
||||||
|
|
||||||
|
def hard_delete_i(self, indexes):
|
||||||
self._data = list(
|
self._data = list(
|
||||||
map(
|
map(
|
||||||
lambda e: e[1],
|
lambda e: e[1],
|
||||||
@@ -290,20 +455,30 @@ class HydraulicStructure(SQLSubModel):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete(self, els):
|
def delete_i(self, indexes):
|
||||||
self._data = list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda e: e not in els,
|
lambda e: e[1].set_as_deleted(),
|
||||||
self._data
|
filter(
|
||||||
|
lambda e: e[0] in indexes,
|
||||||
|
enumerate(self.lst)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
|
def delete(self, els):
|
||||||
|
for el in els:
|
||||||
|
el.set_as_deleted()
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def sort(self, _reverse=False, key=None):
|
def sort(self, _reverse=False, key=None):
|
||||||
if key is None:
|
if key is None:
|
||||||
self._data.sort(reverse=_reverse)
|
self._data.sort(reverse=_reverse)
|
||||||
else:
|
else:
|
||||||
self._data.sort(reverse=_reverse, key=key)
|
self._data.sort(reverse=_reverse, key=key)
|
||||||
self._status.modified()
|
|
||||||
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# HydraulicStructuresList.py -- Pamhyr
|
# HydraulicStructuresList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.HydraulicStructures.HydraulicStructures import HydraulicStructure
|
from Model.HydraulicStructures.HydraulicStructures import HydraulicStructure
|
||||||
|
|
||||||
|
|
||||||
@@ -42,10 +42,10 @@ class HydraulicStructureList(PamhyrModelList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM hydraulic_structures")
|
execute(
|
||||||
|
"DELETE FROM hydraulic_structures " +
|
||||||
if data is None:
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
data = {}
|
)
|
||||||
|
|
||||||
for hs in self._lst:
|
for hs in self._lst:
|
||||||
hs._db_save(execute, data=data)
|
hs._db_save(execute, data=data)
|
||||||
@@ -53,9 +53,12 @@ class HydraulicStructureList(PamhyrModelList):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def new(self, lst, index):
|
def new(self, lst, index):
|
||||||
n = HydraulicStructure(status=self._status)
|
n = HydraulicStructure(
|
||||||
|
status=self._status,
|
||||||
|
owner_scenario=self._status.scenario_id
|
||||||
|
)
|
||||||
self._lst.insert(index, n)
|
self._lst.insert(index, n)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def __copy__(self):
|
def __copy__(self):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# InitialConditions.py -- Pamhyr
|
# InitialConditions.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,32 +24,34 @@ from functools import reduce
|
|||||||
from numpy import interp
|
from numpy import interp
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Data(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
def __init__(self, name: str = "",
|
def __init__(self, id: int = -1,
|
||||||
comment: str = "", reach=None,
|
name: str = "", comment: str = "",
|
||||||
rk: float = 0.0, discharge: float = 0.0,
|
reach=None, section=None,
|
||||||
|
discharge: float = 0.0,
|
||||||
height: float = 0.0,
|
height: float = 0.0,
|
||||||
status=None):
|
status=None,
|
||||||
super(Data, self).__init__()
|
owner_scenario=-1):
|
||||||
|
super(Data, self).__init__(
|
||||||
self._status = status
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._comment = comment
|
self._comment = comment
|
||||||
|
|
||||||
self._rk = rk
|
self._section = section
|
||||||
self._discharge = discharge
|
self._discharge = discharge
|
||||||
self._speed = 0.0
|
self._speed = 0.0
|
||||||
self._elevation = 0.0
|
self._elevation = 0.0
|
||||||
self._height = height
|
self._height = height
|
||||||
|
|
||||||
if self._rk != 0.0:
|
if self._section is not None:
|
||||||
self._update_from_rk()
|
self._update_from_rk()
|
||||||
if self._height != 0.0:
|
if self._height != 0.0:
|
||||||
self._update_from_height()
|
self._update_from_height()
|
||||||
@@ -57,25 +59,29 @@ class Data(SQLSubModel):
|
|||||||
self._update_from_discharge()
|
self._update_from_discharge()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE initial_conditions(
|
CREATE TABLE initial_conditions{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
ind INTEGER NOT NULL,
|
ind INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
comment TEXT NOT NULL,
|
comment TEXT NOT NULL,
|
||||||
reach INTEGER,
|
reach INTEGER,
|
||||||
rk REAL NOT NULL,
|
section INTEGER,
|
||||||
discharge REAL NOT NULL,
|
discharge REAL NOT NULL,
|
||||||
height REAL NOT NULL,
|
height REAL NOT NULL,
|
||||||
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 11:
|
if int(release) < 11:
|
||||||
@@ -83,41 +89,138 @@ class Data(SQLSubModel):
|
|||||||
"ALTER TABLE initial_conditions RENAME COLUMN kp TO rk"
|
"ALTER TABLE initial_conditions RENAME COLUMN kp TO rk"
|
||||||
)
|
)
|
||||||
|
|
||||||
return cls._update_submodel(execute, version)
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 1:
|
||||||
|
cls._db_update_to_0_1_1(execute, data)
|
||||||
|
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE initial_conditions " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "initial_conditions"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table, reachs)
|
||||||
|
cls._db_update_to_0_1_1(
|
||||||
|
execute, data,
|
||||||
|
origin_version="0.0.*"
|
||||||
|
)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, ind, name, comment, reach, section, " +
|
||||||
|
"discharge, height, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ind, name, comment, reach, section, " +
|
||||||
|
"discharge, height, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_1_1(cls, execute, data,
|
||||||
|
origin_version="0.1.0"):
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE initial_conditions " +
|
||||||
|
f"ADD COLUMN section INTEGER"
|
||||||
|
)
|
||||||
|
|
||||||
|
cls._db_update_to_0_1_1_assoc_section_from_rk(
|
||||||
|
execute, "initial_conditions",
|
||||||
|
origin_version=origin_version
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
id = data["reach"].id
|
new = []
|
||||||
|
reach = data["reach"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
id = reach.pamhyr_id
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT ind, name, comment, rk, discharge, height " +
|
"SELECT pamhyr_id, deleted, ind, name, comment, " +
|
||||||
|
"section, discharge, height, scenario " +
|
||||||
"FROM initial_conditions " +
|
"FROM initial_conditions " +
|
||||||
f"WHERE reach = {id}"
|
f"WHERE reach = {id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
|
||||||
|
"ORDER BY ind ASC"
|
||||||
)
|
)
|
||||||
|
|
||||||
new = []
|
ok = True
|
||||||
|
|
||||||
for _ in table:
|
|
||||||
new.append(None)
|
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
ind = row[0]
|
it = iter(row)
|
||||||
name = row[1]
|
|
||||||
comment = row[2]
|
pid = next(it)
|
||||||
rk = row[3]
|
deleted = (next(it) == 1)
|
||||||
discharge = row[4]
|
ind = next(it)
|
||||||
height = row[5]
|
name = next(it)
|
||||||
|
comment = next(it)
|
||||||
|
section_id = next(it)
|
||||||
|
discharge = next(it)
|
||||||
|
height = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
section = reduce(
|
||||||
|
lambda acc, s: (
|
||||||
|
s if s.pamhyr_id == section_id else acc
|
||||||
|
),
|
||||||
|
reach.reach.profiles,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
if section is None:
|
||||||
|
logger.debug(
|
||||||
|
f"Section ID {section_id} do not exist in reach " +
|
||||||
|
f"{reach.name} ({reach.pamhyr_id})"
|
||||||
|
)
|
||||||
|
ok = False
|
||||||
|
continue
|
||||||
|
|
||||||
d = cls(
|
d = cls(
|
||||||
|
id=pid,
|
||||||
reach=data["reach"],
|
reach=data["reach"],
|
||||||
status=data["status"],
|
status=data["status"],
|
||||||
name=name,
|
name=name,
|
||||||
comment=comment,
|
comment=comment,
|
||||||
rk=rk,
|
section=section,
|
||||||
discharge=discharge,
|
discharge=discharge,
|
||||||
height=height,
|
height=height,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
d.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(d)
|
||||||
|
|
||||||
|
if not ok:
|
||||||
|
logger.info(
|
||||||
|
"Please regenerate/defined the inital conditions " +
|
||||||
|
f"for reach {reach.name} ({reach.pamhyr_id})"
|
||||||
)
|
)
|
||||||
|
|
||||||
new[ind] = d
|
# Recution only if no data found
|
||||||
|
if len(new) == 0:
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
@@ -126,13 +229,14 @@ class Data(SQLSubModel):
|
|||||||
|
|
||||||
execute(
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"initial_conditions(ind, name, comment, rk, " +
|
"initial_conditions(pamhyr_id, deleted, ind, name, comment, " +
|
||||||
"discharge, height, reach) " +
|
"section, discharge, height, reach, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
|
f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"{ind}, '{self._db_format(self.name)}', " +
|
f"{ind}, '{self._db_format(self.name)}', " +
|
||||||
f"'{self._db_format(self._comment)}', " +
|
f"'{self._db_format(self._comment)}', " +
|
||||||
f"{self._rk}, {self._discharge}, {self._height}, " +
|
f"{self._section.id}, {self._discharge}, {self._height}, " +
|
||||||
f"{self._reach.id}" +
|
f"{self._reach.id}, {self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -142,7 +246,7 @@ class Data(SQLSubModel):
|
|||||||
new = Data(
|
new = Data(
|
||||||
name=self.name,
|
name=self.name,
|
||||||
comment=self._comment,
|
comment=self._comment,
|
||||||
rk=self._rk,
|
section=self._section,
|
||||||
discharge=self._discharge,
|
discharge=self._discharge,
|
||||||
height=self._height,
|
height=self._height,
|
||||||
reach=self._reach,
|
reach=self._reach,
|
||||||
@@ -161,8 +265,8 @@ class Data(SQLSubModel):
|
|||||||
val = self._name
|
val = self._name
|
||||||
elif key == "comment":
|
elif key == "comment":
|
||||||
val = self._comment
|
val = self._comment
|
||||||
elif key == "rk":
|
elif key == "rk" or key == "section":
|
||||||
val = self._rk
|
val = self._section
|
||||||
elif key == "speed":
|
elif key == "speed":
|
||||||
val = self._speed
|
val = self._speed
|
||||||
elif key == "discharge":
|
elif key == "discharge":
|
||||||
@@ -175,9 +279,9 @@ class Data(SQLSubModel):
|
|||||||
return val
|
return val
|
||||||
|
|
||||||
def _update_get_min(self):
|
def _update_get_min(self):
|
||||||
profile = self._reach.reach.get_profiles_from_rk(self._rk)
|
profile = self._section
|
||||||
if len(profile) > 0:
|
if profile is not None:
|
||||||
min = profile[0].z_min()
|
min = profile.z_min()
|
||||||
else:
|
else:
|
||||||
min = 0.0
|
min = 0.0
|
||||||
|
|
||||||
@@ -204,8 +308,8 @@ class Data(SQLSubModel):
|
|||||||
self._name = str(value)
|
self._name = str(value)
|
||||||
elif key == "comment":
|
elif key == "comment":
|
||||||
self._comment = str(value)
|
self._comment = str(value)
|
||||||
elif key == "rk":
|
elif key == "rk" or key == "section":
|
||||||
self._rk = float(value)
|
self._section = value
|
||||||
self._update_from_rk()
|
self._update_from_rk()
|
||||||
elif key == "speed":
|
elif key == "speed":
|
||||||
# Not supposed to be modified
|
# Not supposed to be modified
|
||||||
@@ -220,7 +324,7 @@ class Data(SQLSubModel):
|
|||||||
self._height = float(value)
|
self._height = float(value)
|
||||||
self._update_from_height()
|
self._update_from_height()
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
|
|
||||||
class InitialConditions(SQLSubModel):
|
class InitialConditions(SQLSubModel):
|
||||||
@@ -241,8 +345,8 @@ class InitialConditions(SQLSubModel):
|
|||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
@@ -270,8 +374,18 @@ class InitialConditions(SQLSubModel):
|
|||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self.data)
|
||||||
|
|
||||||
def lst(self):
|
def lst(self):
|
||||||
return self._data
|
return self._data
|
||||||
@@ -283,49 +397,69 @@ class InitialConditions(SQLSubModel):
|
|||||||
@reach.setter
|
@reach.setter
|
||||||
def reach(self, new):
|
def reach(self, new):
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data(self):
|
def data(self):
|
||||||
return self._data.copy()
|
return list(
|
||||||
|
filter(
|
||||||
|
lambda el: not el.is_deleted(),
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@data.setter
|
@data.setter
|
||||||
def data(self, data):
|
def data(self, data):
|
||||||
self._data = data
|
self._data = data
|
||||||
|
|
||||||
def get(self, index):
|
def get(self, index):
|
||||||
return self._data[index]
|
return self.data[index]
|
||||||
|
|
||||||
def set(self, index, data):
|
def set(self, index, data):
|
||||||
self._data.insert(index, data)
|
self._data.insert(index, data)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = Data(reach=self._reach, status=self._status)
|
n = Data(reach=self._reach, status=self._status)
|
||||||
self._data.insert(index, n)
|
self._data.insert(index, n)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def new_from_data(self, rk, discharge, elevation):
|
def new_from_data(self, rk, discharge, elevation):
|
||||||
n = Data(reach=self._reach, status=self._status)
|
n = Data(reach=self._reach, status=self._status)
|
||||||
|
|
||||||
n['rk'] = rk
|
section = reduce(
|
||||||
|
lambda acc, s: (
|
||||||
|
s if s.rk == rk else acc
|
||||||
|
),
|
||||||
|
self._reach.reach.profiles,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
n['section'] = section
|
||||||
n['discharge'] = discharge
|
n['discharge'] = discharge
|
||||||
n['elevation'] = elevation
|
n['elevation'] = elevation
|
||||||
|
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, index, data):
|
def insert(self, index, data):
|
||||||
self._data.insert(index, data)
|
if data in self._data:
|
||||||
self._status.modified()
|
data.set_as_not_deleted()
|
||||||
|
else:
|
||||||
|
self._data.insert(index, data)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def delete(self, data):
|
def delete(self, data):
|
||||||
self._data = list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda x: x not in data,
|
lambda x: x.set_as_deleted(),
|
||||||
self._data
|
filter(
|
||||||
|
lambda x: x in data,
|
||||||
|
self._data
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
def delete_i(self, indexes):
|
||||||
data = list(
|
data = list(
|
||||||
@@ -341,18 +475,23 @@ class InitialConditions(SQLSubModel):
|
|||||||
|
|
||||||
def sort(self, reverse=False, key=None):
|
def sort(self, reverse=False, key=None):
|
||||||
self._data.sort(reverse=reverse, key=key)
|
self._data.sort(reverse=reverse, key=key)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def _data_get(self, key):
|
def _data_get(self, key):
|
||||||
return list(
|
return list(
|
||||||
map(
|
map(
|
||||||
lambda d: d[key],
|
lambda d: d[key],
|
||||||
self._data
|
self.data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_rk(self):
|
def get_rk(self):
|
||||||
return self._data_get("rk")
|
return list(
|
||||||
|
map(
|
||||||
|
lambda d: d["rk"].rk,
|
||||||
|
self.data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def get_elevation(self):
|
def get_elevation(self):
|
||||||
return self._data_get("elevation")
|
return self._data_get("elevation")
|
||||||
@@ -360,12 +499,13 @@ class InitialConditions(SQLSubModel):
|
|||||||
def get_discharge(self):
|
def get_discharge(self):
|
||||||
return self._data_get("discharge")
|
return self._data_get("discharge")
|
||||||
|
|
||||||
|
def clear_data(self):
|
||||||
|
for data in self._data:
|
||||||
|
data.set_as_deleted()
|
||||||
|
|
||||||
def generate_growing_constant_depth(self, height: float,
|
def generate_growing_constant_depth(self, height: float,
|
||||||
compute_discharge: bool):
|
compute_discharge: bool):
|
||||||
|
|
||||||
profiles = self._reach.reach.profiles.copy()
|
profiles = self._reach.reach.profiles.copy()
|
||||||
profiles.reverse()
|
|
||||||
|
|
||||||
previous_elevation = -99999.99
|
previous_elevation = -99999.99
|
||||||
|
|
||||||
data_discharge = {}
|
data_discharge = {}
|
||||||
@@ -375,18 +515,24 @@ class InitialConditions(SQLSubModel):
|
|||||||
data_discharge[profile.rk] = 0.0
|
data_discharge[profile.rk] = 0.0
|
||||||
else:
|
else:
|
||||||
for data in self._data:
|
for data in self._data:
|
||||||
data_discharge[data["rk"]] = data["discharge"]
|
data_discharge[data["rk"].rk] = data["discharge"]
|
||||||
|
|
||||||
incline = self._reach.reach.get_incline_median_mean()
|
incline = self._reach.reach.get_incline_median_mean()
|
||||||
logger.debug(f"incline = {incline}")
|
logger.debug(f"incline = {incline}")
|
||||||
self._data = []
|
|
||||||
for profile in profiles:
|
self.clear_data()
|
||||||
|
|
||||||
|
for profile in reversed(profiles):
|
||||||
width = profile.wet_width(profile.z_min() + height)
|
width = profile.wet_width(profile.z_min() + height)
|
||||||
|
area = profile.wet_area(profile.z_min() + height)
|
||||||
|
radius = profile.wet_radius(profile.z_min() + height)
|
||||||
frictions = self._reach.frictions.frictions
|
frictions = self._reach.frictions.frictions
|
||||||
strickler = None
|
strickler = None
|
||||||
for f in frictions:
|
if frictions is not None:
|
||||||
if f.contains_rk(profile.rk):
|
if len(frictions) >= 1:
|
||||||
strickler = f.get_friction(profile.rk)[0]
|
for f in frictions:
|
||||||
|
if f.contains_rk(profile.rk):
|
||||||
|
strickler = f.get_friction(profile.rk)[0]
|
||||||
if strickler is None:
|
if strickler is None:
|
||||||
strickler = 25.0
|
strickler = 25.0
|
||||||
|
|
||||||
@@ -394,9 +540,12 @@ class InitialConditions(SQLSubModel):
|
|||||||
discharge = data_discharge[profile.rk]
|
discharge = data_discharge[profile.rk]
|
||||||
else:
|
else:
|
||||||
discharge = (
|
discharge = (
|
||||||
((width * 0.8)
|
# ((width * 0.8)
|
||||||
* strickler
|
# * strickler
|
||||||
* (height ** (5/3))
|
# * (height ** (5/3))
|
||||||
|
# * (abs(incline) ** (0.5)))
|
||||||
|
(area * strickler
|
||||||
|
* (radius ** (2/3))
|
||||||
* (abs(incline) ** (0.5)))
|
* (abs(incline) ** (0.5)))
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -411,19 +560,17 @@ class InitialConditions(SQLSubModel):
|
|||||||
logger.debug(f" discharge = {discharge}")
|
logger.debug(f" discharge = {discharge}")
|
||||||
|
|
||||||
new = Data(reach=self._reach, status=self._status)
|
new = Data(reach=self._reach, status=self._status)
|
||||||
new["rk"] = profile.rk
|
new["rk"] = profile
|
||||||
new["discharge"] = discharge
|
new["discharge"] = discharge
|
||||||
new["elevation"] = elevation
|
new["elevation"] = elevation
|
||||||
|
|
||||||
previous_elevation = elevation
|
previous_elevation = elevation
|
||||||
self._data.append(new)
|
self._data.append(new)
|
||||||
|
|
||||||
self._data.reverse()
|
|
||||||
|
|
||||||
def generate_discharge(self, discharge: float, compute_height: bool):
|
def generate_discharge(self, discharge: float, compute_height: bool):
|
||||||
|
|
||||||
profiles = self._reach.reach.profiles.copy()
|
profiles = self._reach.reach.profiles.copy()
|
||||||
profiles.reverse()
|
if profiles is None:
|
||||||
|
return None
|
||||||
|
|
||||||
previous_elevation = -99999.99
|
previous_elevation = -99999.99
|
||||||
|
|
||||||
@@ -434,29 +581,41 @@ class InitialConditions(SQLSubModel):
|
|||||||
data_height[profile.rk] = 0.0
|
data_height[profile.rk] = 0.0
|
||||||
else:
|
else:
|
||||||
for data in self._data:
|
for data in self._data:
|
||||||
data_height[data["rk"]] = data["height"]
|
data_height[data["rk"].rk] = data["height"]
|
||||||
|
|
||||||
|
print(data_height)
|
||||||
|
|
||||||
incline = self._reach.reach.get_incline_median_mean()
|
incline = self._reach.reach.get_incline_median_mean()
|
||||||
logger.debug(f"incline = {incline}")
|
logger.debug(f"incline = {incline}")
|
||||||
self._data = []
|
|
||||||
for profile in profiles:
|
self.clear_data()
|
||||||
|
|
||||||
|
for profile in reversed(profiles):
|
||||||
width = profile.width_approximation()
|
width = profile.width_approximation()
|
||||||
frictions = self._reach.frictions.frictions
|
frictions = self._reach.frictions.frictions
|
||||||
strickler = None
|
strickler = None
|
||||||
for f in frictions:
|
|
||||||
if f.contains_rk(profile.rk):
|
if frictions is not None:
|
||||||
strickler = f.get_friction(profile.rk)[0]
|
if len(frictions) >= 1:
|
||||||
|
for f in frictions:
|
||||||
|
if f.contains_rk(profile.rk):
|
||||||
|
strickler = f.get_friction(profile.rk)[0]
|
||||||
|
|
||||||
if strickler is None:
|
if strickler is None:
|
||||||
strickler = 25.0
|
strickler = 25.0
|
||||||
|
|
||||||
if not compute_height:
|
if not compute_height:
|
||||||
height = data_height[profile.rk]
|
height = data_height[profile.rk]
|
||||||
else:
|
else:
|
||||||
height = (
|
if abs(incline) <= 0:
|
||||||
discharge
|
height = 0.0
|
||||||
/
|
else:
|
||||||
((width * 0.8) * strickler * (abs(incline) ** (0.5)))
|
height = (
|
||||||
) ** (0.6)
|
discharge
|
||||||
|
/ ((width * 0.8)
|
||||||
|
* strickler
|
||||||
|
* (abs(incline) ** (0.5)))
|
||||||
|
) ** (0.6)
|
||||||
|
|
||||||
elevation = max(
|
elevation = max(
|
||||||
profile.z_min() + height,
|
profile.z_min() + height,
|
||||||
@@ -469,15 +628,13 @@ class InitialConditions(SQLSubModel):
|
|||||||
logger.debug(f" height = {height}")
|
logger.debug(f" height = {height}")
|
||||||
|
|
||||||
new = Data(reach=self._reach, status=self._status)
|
new = Data(reach=self._reach, status=self._status)
|
||||||
new["rk"] = profile.rk
|
new["section"] = profile
|
||||||
new["discharge"] = discharge
|
new["discharge"] = discharge
|
||||||
new["elevation"] = elevation
|
new["elevation"] = elevation
|
||||||
|
|
||||||
previous_elevation = elevation
|
previous_elevation = elevation
|
||||||
self._data.append(new)
|
self._data.append(new)
|
||||||
|
|
||||||
self._data.reverse()
|
|
||||||
|
|
||||||
def generate_height(self,
|
def generate_height(self,
|
||||||
elevation1: float,
|
elevation1: float,
|
||||||
elevation2: float,
|
elevation2: float,
|
||||||
@@ -493,9 +650,9 @@ class InitialConditions(SQLSubModel):
|
|||||||
data_discharge[profile.rk] = 0.0
|
data_discharge[profile.rk] = 0.0
|
||||||
else:
|
else:
|
||||||
for data in self._data:
|
for data in self._data:
|
||||||
data_discharge[data["rk"]] = data["discharge"]
|
data_discharge[data["rk"].rk] = data["discharge"]
|
||||||
|
|
||||||
self._data = []
|
self.clear_data()
|
||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
|
|
||||||
if not compute_discharge:
|
if not compute_discharge:
|
||||||
@@ -506,7 +663,7 @@ class InitialConditions(SQLSubModel):
|
|||||||
[upstream_rk, downstream_rk],
|
[upstream_rk, downstream_rk],
|
||||||
[elevation1, elevation2])
|
[elevation1, elevation2])
|
||||||
new = Data(reach=self._reach, status=self._status)
|
new = Data(reach=self._reach, status=self._status)
|
||||||
new["rk"] = profile.rk
|
new["rk"] = profile
|
||||||
new["discharge"] = d
|
new["discharge"] = d
|
||||||
new["elevation"] = elevation
|
new["elevation"] = elevation
|
||||||
self._data.append(new)
|
self._data.append(new)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# InitialConditionsDict.py -- Pamhyr
|
# InitialConditionsDict.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -64,7 +64,8 @@ class InitialConditionsDict(PamhyrModelDict):
|
|||||||
|
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM initial_conditions " +
|
"DELETE FROM initial_conditions " +
|
||||||
f"WHERE reach = '{reach.id}'"
|
f"WHERE reach = '{reach.id}' " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
ok &= self._dict[reach]._db_save(execute, data)
|
ok &= self._dict[reach]._db_save(execute, data)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# InitialConditionsAdisTS.py -- Pamhyr
|
# InitialConditionsAdisTS.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,6 +23,7 @@ from tools import trace, timer, old_pamhyr_date_to_timestamp
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSSpec \
|
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSSpec \
|
||||||
import ICAdisTSSpec
|
import ICAdisTSSpec
|
||||||
@@ -34,19 +35,17 @@ class InitialConditionsAdisTS(SQLSubModel):
|
|||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
ICAdisTSSpec,
|
ICAdisTSSpec,
|
||||||
]
|
]
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "default",
|
def __init__(self, id: int = -1, name: str = "default",
|
||||||
pollutant: int = -1, status=None):
|
pollutant: int = -1, status=None,
|
||||||
super(InitialConditionsAdisTS, self).__init__()
|
owner_scenario=-1):
|
||||||
|
super(InitialConditionsAdisTS, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
self.id = InitialConditionsAdisTS._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._pollutant = pollutant
|
self._pollutant = pollutant
|
||||||
self._concentration = None
|
self._concentration = None
|
||||||
@@ -56,81 +55,159 @@ class InitialConditionsAdisTS(SQLSubModel):
|
|||||||
self._enabled = True
|
self._enabled = True
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
InitialConditionsAdisTS._id_cnt = max(
|
|
||||||
InitialConditionsAdisTS._id_cnt + 1,
|
|
||||||
self.id
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE initial_conditions_adists(
|
CREATE TABLE initial_conditions_adists{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
pollutant INTEGER NOT NULL,
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
pollutant INTEGER NOT NULL,
|
||||||
concentration REAL NOT NULL,
|
name TEXT NOT NULL,
|
||||||
eg REAL NOT NULL,
|
concentration REAL NOT NULL,
|
||||||
em REAL NOT NULL,
|
eg REAL NOT NULL,
|
||||||
ed REAL NOT NULL,
|
em REAL NOT NULL,
|
||||||
enabled BOOLEAN NOT NULL,
|
ed REAL NOT NULL,
|
||||||
FOREIGN KEY(pollutant) REFERENCES Pollutants(id)
|
enabled BOOLEAN NOT NULL,
|
||||||
)
|
{Scenario.create_db_add_scenario()},
|
||||||
""")
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES Pollutants(pamhyr_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == 0 and minor < 1:
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "initial_conditions_adists"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, pollutant, name, concentration, " +
|
||||||
|
"eg, em, ed, enabled, scenario) " +
|
||||||
|
"SELECT pamhyr_id, pollutant, name, concentration, " +
|
||||||
|
"eg, em, ed, enabled, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_pollutants_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_pollutants_pid(cls, execute, data):
|
||||||
|
pid_pol = data["id2pid"]["Pollutants"]
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, pollutant " +
|
||||||
|
"FROM initial_conditions_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
pol_id = next(it)
|
||||||
|
|
||||||
|
if pol_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE initial_conditions_adists " +
|
||||||
|
f"SET pollutant = {pid_pol[pol_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, pollutant, name, concentration, eg, em, ed, " +
|
"SELECT pamhyr_id, deleted, " +
|
||||||
"enabled " +
|
"pollutant, name, concentration, eg, em, ed, " +
|
||||||
"FROM initial_conditions_adists"
|
"enabled, scenario " +
|
||||||
|
"FROM initial_conditions_adists " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
IC_id = row[0]
|
it = iter(row)
|
||||||
pollutant = row[1]
|
|
||||||
name = row[2]
|
|
||||||
concentration = row[3]
|
|
||||||
eg = row[4]
|
|
||||||
em = row[5]
|
|
||||||
ed = row[6]
|
|
||||||
enabled = (row[7] == 1)
|
|
||||||
|
|
||||||
IC = cls(
|
pid = next(it)
|
||||||
id=IC_id,
|
deleted = (next(it) == 1)
|
||||||
|
pollutant = next(it)
|
||||||
|
name = next(it)
|
||||||
|
concentration = next(it)
|
||||||
|
eg = next(it)
|
||||||
|
em = next(it)
|
||||||
|
ed = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
ic = cls(
|
||||||
|
id=pid,
|
||||||
name=name,
|
name=name,
|
||||||
status=data['status']
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
ic.set_as_deleted()
|
||||||
|
|
||||||
IC.pollutant = pollutant
|
ic.pollutant = pollutant
|
||||||
IC.concentration = concentration
|
ic.concentration = concentration
|
||||||
IC.eg = eg
|
ic.eg = eg
|
||||||
IC.em = em
|
ic.em = em
|
||||||
IC.ed = ed
|
ic.ed = ed
|
||||||
IC.enabled = enabled
|
ic.enabled = enabled
|
||||||
|
|
||||||
data['ic_default_id'] = IC_id
|
data['ic_default_id'] = pid
|
||||||
IC._data = ICAdisTSSpec._db_load(execute, data)
|
ic._data = ICAdisTSSpec._db_load(execute, data)
|
||||||
|
|
||||||
new.append(IC)
|
loaded.add(pid)
|
||||||
|
new.append(ic)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute(f"DELETE FROM initial_conditions_adists WHERE id = {self.id}")
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"DELETE FROM initial_conditions_adists " +
|
||||||
|
f"WHERE pamhyr_id = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
pollutant = -1
|
pollutant = -1
|
||||||
if self.pollutant is not None:
|
if self.pollutant is not None:
|
||||||
@@ -155,12 +232,14 @@ class InitialConditionsAdisTS(SQLSubModel):
|
|||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"initial_conditions_adists(" +
|
"initial_conditions_adists(" +
|
||||||
"id, pollutant, name, concentration, " +
|
"pamhyr_id, deleted, pollutant, name, concentration, " +
|
||||||
"eg, em, ed, enabled" +
|
"eg, em, ed, enabled, scenario" +
|
||||||
") " +
|
") " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {pollutant}, '{self._db_format(self._name)}', " +
|
f"{self.id}, {self.is_deleted()}, " +
|
||||||
f"{concentration}, {eg}, {em}, {ed}, {self._enabled}" +
|
f"{pollutant}, '{self._db_format(self._name)}', " +
|
||||||
|
f"{concentration}, {eg}, {em}, {ed}, {self._enabled}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -168,8 +247,9 @@ class InitialConditionsAdisTS(SQLSubModel):
|
|||||||
|
|
||||||
data['ic_default_id'] = self.id
|
data['ic_default_id'] = self.id
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM initial_conditions_spec " +
|
"DELETE FROM initial_conditions_adists_spec " +
|
||||||
f"WHERE ic_default = {self.id}"
|
f"WHERE ic_default = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
for ic_spec in self._data:
|
for ic_spec in self._data:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# InitialConditionsAdisTSList.py -- Pamhyr
|
# InitialConditionsAdisTSList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.InitialConditionsAdisTS.InitialConditionsAdisTS \
|
from Model.InitialConditionsAdisTS.InitialConditionsAdisTS \
|
||||||
import InitialConditionsAdisTS
|
import InitialConditionsAdisTS
|
||||||
|
|
||||||
@@ -43,7 +43,10 @@ class InitialConditionsAdisTSList(PamhyrModelList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM initial_conditions_adists")
|
execute(
|
||||||
|
"DELETE FROM initial_conditions_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# InitialConditionsAdisTSSpec.py -- Pamhyr
|
# InitialConditionsAdisTSSpec.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,14 +22,13 @@ from tools import trace, timer
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class ICAdisTSSpec(SQLSubModel):
|
class ICAdisTSSpec(SQLSubModel):
|
||||||
_sub_classes = [
|
_sub_classes = []
|
||||||
]
|
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status=None):
|
status=None):
|
||||||
@@ -37,11 +36,6 @@ class ICAdisTSSpec(SQLSubModel):
|
|||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
self.id = ICAdisTSSpec._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name_section = name
|
self._name_section = name
|
||||||
self._reach = None
|
self._reach = None
|
||||||
self._start_rk = None
|
self._start_rk = None
|
||||||
@@ -53,73 +47,142 @@ class ICAdisTSSpec(SQLSubModel):
|
|||||||
self._rate = None
|
self._rate = None
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
|
|
||||||
ICAdisTSSpec._id_cnt = max(ICAdisTSSpec._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE initial_conditions_spec(
|
CREATE TABLE initial_conditions_adists_spec{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
ic_default INTEGER NOT NULL,
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
ic_default INTEGER NOT NULL,
|
||||||
reach INTEGER NOT NULL,
|
name TEXT NOT NULL,
|
||||||
start_rk REAL NOT NULL,
|
reach INTEGER NOT NULL,
|
||||||
end_rk REAL NOT NULL,
|
start_rk REAL NOT NULL,
|
||||||
concentration REAL NOT NULL,
|
end_rk REAL NOT NULL,
|
||||||
eg REAL NOT NULL,
|
concentration REAL NOT NULL,
|
||||||
em REAL NOT NULL,
|
eg REAL NOT NULL,
|
||||||
ed REAL NOT NULL,
|
em REAL NOT NULL,
|
||||||
rate REAL NOT NULL,
|
ed REAL NOT NULL,
|
||||||
enabled BOOLEAN NOT NULL,
|
rate REAL NOT NULL,
|
||||||
FOREIGN KEY(ic_default) REFERENCES initial_conditions_adists(id),
|
enabled BOOLEAN NOT NULL,
|
||||||
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
)
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
""")
|
FOREIGN KEY(ic_default)
|
||||||
|
REFERENCES initial_conditions_adists(pamhyr_id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
if major == 0 and minor < 1:
|
if major == 0 and minor < 1:
|
||||||
if int(release) < 6:
|
if int(release) < 6:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "initial_conditions_spec"
|
||||||
|
table_new = "initial_conditions_adists_spec"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table_new}_tmp " +
|
||||||
|
"(pamhyr_id, ic_default, name, reach, start_rk, end_rk, " +
|
||||||
|
"concentration, eg, em, ed, rate, enabled, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ic_default, name, reach, start_rk, end_rk, " +
|
||||||
|
"concentration, eg, em, ed, rate, enabled, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table_new}_tmp RENAME TO {table_new}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table_new, reachs)
|
||||||
|
cls._db_update_to_0_2_0_set_ica_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_ica_pid(cls, execute, data):
|
||||||
|
pid_ica = data["id2pid"]["initial_conditions_adist"]
|
||||||
|
els = execute(
|
||||||
|
"SELECT pamhyr_id, ic_default " +
|
||||||
|
"FROM initial_conditions_adists_spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
ica_id = next(it)
|
||||||
|
|
||||||
|
if ica_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE initial_conditions_adists_spec " +
|
||||||
|
f"SET ic_default = {pid_ica[ica_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
reachs = data["edges"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, ic_default, name, reach, start_rk, end_rk, " +
|
"SELECT pamhyr_id, deleted, name, reach, start_rk, end_rk, " +
|
||||||
"concentration, eg, em, ed, rate, enabled " +
|
"concentration, eg, em, ed, rate, enabled, scenario " +
|
||||||
"FROM initial_conditions_spec " +
|
"FROM initial_conditions_adists_spec " +
|
||||||
f"WHERE ic_default = {data['ic_default_id']} "
|
f"WHERE ic_default = {data['ic_default_id']} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
name = row[2]
|
|
||||||
reach = row[3]
|
|
||||||
start_rk = row[4]
|
|
||||||
end_rk = row[5]
|
|
||||||
concentration = row[6]
|
|
||||||
eg = row[7]
|
|
||||||
em = row[8]
|
|
||||||
ed = row[9]
|
|
||||||
rate = row[10]
|
|
||||||
enabled = (row[11] == 1)
|
|
||||||
|
|
||||||
# new_spec = [name, reach, start_rk, end_rk,
|
id = next(it)
|
||||||
# concentration, eg, em, ed, rate, enabled]
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
reach = next(it)
|
||||||
|
start_rk = next(it)
|
||||||
|
end_rk = next(it)
|
||||||
|
concentration = next(it)
|
||||||
|
eg = next(it)
|
||||||
|
em = next(it)
|
||||||
|
ed = next(it)
|
||||||
|
rate = next(it)
|
||||||
|
enabled = (next(it) == 1)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
new_spec = cls(
|
new_spec = cls(
|
||||||
id=id,
|
id=id, name=name,
|
||||||
name=name,
|
status=status,
|
||||||
status=data['status']
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
new_spec.set_as_deleted()
|
||||||
|
|
||||||
new_spec.reach = reach
|
new_spec.reach = reach
|
||||||
new_spec.start_rk = start_rk
|
new_spec.start_rk = start_rk
|
||||||
@@ -131,30 +194,37 @@ class ICAdisTSSpec(SQLSubModel):
|
|||||||
new_spec.rate = rate
|
new_spec.rate = rate
|
||||||
new_spec.enabled = enabled
|
new_spec.enabled = enabled
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
new.append(new_spec)
|
new.append(new_spec)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
ic_default = data['ic_default_id']
|
ic_default = data['ic_default_id']
|
||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"initial_conditions_spec(id, ic_default, name, reach, " +
|
"initial_conditions_adists_spec(id, deleted, " +
|
||||||
"start_rk, end_rk, concentration, eg, em, ed, rate, enabled) " +
|
"ic_default, name, reach, " +
|
||||||
|
"start_rk, end_rk, concentration, eg, em, ed, rate, " +
|
||||||
|
"enabled, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, " +
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"{ic_default}, " +
|
f"{ic_default}, " +
|
||||||
f"'{self._db_format(self._name_section)}', " +
|
f"'{self._db_format(self._name_section)}', " +
|
||||||
f"{self._reach}, " +
|
f"{self._reach}, " +
|
||||||
f"{self._start_rk}, " +
|
f"{self._start_rk}, {self._end_rk}, " +
|
||||||
f"{self._end_rk}, " +
|
|
||||||
f"{self._concentration}, " +
|
f"{self._concentration}, " +
|
||||||
f"{self._eg}, " +
|
f"{self._eg}, {self._em}, {self._ed}, " +
|
||||||
f"{self._em}, " +
|
f"{self._rate}, {self._enabled}, " +
|
||||||
f"{self._ed}, " +
|
f"{self._status.scenario_id}" +
|
||||||
f"{self._rate}, " +
|
|
||||||
f"{self._enabled}" +
|
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# LateralContribution.py -- Pamhyr
|
# LateralContribution.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,66 +27,226 @@ from tools import (
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class LateralContribution(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self,
|
||||||
super(LateralContribution, self).__init__()
|
data0, data1,
|
||||||
|
id: int = -1,
|
||||||
|
types=[float, float],
|
||||||
|
status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
|
super(Data, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._types = types
|
||||||
|
self._data = [data0, data1]
|
||||||
if id == -1:
|
|
||||||
self.id = LateralContribution._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
|
||||||
self._type = ""
|
|
||||||
self._edge = None
|
|
||||||
self._begin_rk = 0.0
|
|
||||||
self._end_rk = 0.0
|
|
||||||
self._data = []
|
|
||||||
self._header = []
|
|
||||||
self._types = [float, float]
|
|
||||||
|
|
||||||
LateralContribution._id_cnt = max(
|
|
||||||
LateralContribution._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE lateral_contribution(
|
CREATE TABLE lateral_contribution_data{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
name TEXT NOT NULL,
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
type TEXT NOT NULL,
|
|
||||||
tab TEXT NOT NULL,
|
|
||||||
edge INTEGER,
|
|
||||||
begin_rk REAL NOT NULL,
|
|
||||||
end_rk REAL NOT NULL,
|
|
||||||
FOREIGN KEY(edge) REFERENCES river_reach(id)
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
execute("""
|
|
||||||
CREATE TABLE lateral_contribution_data(
|
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
ind INTEGER NOT NULL,
|
ind INTEGER NOT NULL,
|
||||||
data0 TEXT NOT NULL,
|
data0 TEXT NOT NULL,
|
||||||
data1 TEXT NOT NULL,
|
data1 TEXT NOT NULL,
|
||||||
lc INTEGER,
|
lc INTEGER,
|
||||||
FOREIGN KEY(lc) REFERENCES lateral_contribution(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(lc) REFERENCES lateral_contribution(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == minor == "0":
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE boundary_condition_data " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data=None):
|
||||||
|
table = "lateral_contribution_data"
|
||||||
|
lcs = data['id2pid']['lateral_contribution']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table} " +
|
||||||
|
"(pamhyr_id, ind, data0, data1, lc, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ind, data0, data1, lc, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_lc_pid(execute, table, lcs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_lc_pid(cls, execute, table, lcs):
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, lc FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
lc_id = next(it)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET lc = {lcs[lc_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
lc = data["lc"]
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
values = execute(
|
||||||
|
"SELECT pamhyr_id, deleted, " +
|
||||||
|
"data0, data1, scenario " +
|
||||||
|
"FROM lateral_contribution_data " +
|
||||||
|
f"WHERE lc = {lc._pamhyr_id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
|
||||||
|
"ORDER BY ind ASC"
|
||||||
|
)
|
||||||
|
|
||||||
|
for v in values:
|
||||||
|
it = iter(v)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
delete = next(it)
|
||||||
|
data0 = bc._types[0](next(it))
|
||||||
|
data1 = bc._types[1](next(it))
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
nd = cls(
|
||||||
|
data0, data1,
|
||||||
|
id=pid,
|
||||||
|
types=lc._types,
|
||||||
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
nd.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(nd)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
pid = self._pamhyr_id
|
||||||
|
ind = data["ind"]
|
||||||
|
data0 = self._db_format(str(self[0]))
|
||||||
|
data1 = self._db_format(str(self[1]))
|
||||||
|
lc = data["lc"]
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"lateral_contribution_data (pamhyr_id, deleted, ind, " +
|
||||||
|
"data0, data1, lc, scenario) " +
|
||||||
|
f"VALUES ({pid}, {self._db_format(self.is_deleted())}, " +
|
||||||
|
f"{ind}, '{self._db_format(data0)}', {self._db_format(data1)}, " +
|
||||||
|
f"{lc._pamhyr_id}, {self._status.scenario_id}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._types[key](self._data[key])
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self._data[key] = self._types[key](value)
|
||||||
|
|
||||||
|
|
||||||
|
class LateralContribution(SQLSubModel):
|
||||||
|
_sub_classes = [Data]
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1,
|
||||||
|
name: str = "",
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
|
super(LateralContribution, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
self._name = name
|
||||||
|
self._type = ""
|
||||||
|
self._reach = None
|
||||||
|
self._begin_section = None
|
||||||
|
self._end_section = None
|
||||||
|
self._data = []
|
||||||
|
self._header = []
|
||||||
|
self._types = [float, float]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE lateral_contribution{ext}(
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
tab TEXT NOT NULL,
|
||||||
|
reach INTEGER,
|
||||||
|
begin_section INTEGER,
|
||||||
|
end_section INTEGER,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
|
||||||
|
FOREIGN KEY(begin_section)
|
||||||
|
REFERENCES geometry_profileXYZ(pamhyr_id),
|
||||||
|
FOREIGN KEY(end_section)
|
||||||
|
REFERENCES geometry_profileXYZ(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
if ext == "_tmp":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 11:
|
if int(release) < 11:
|
||||||
@@ -103,7 +263,45 @@ class LateralContribution(SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
execute(
|
||||||
|
"""
|
||||||
|
ALTER TABLE lateral_contribution
|
||||||
|
RENAME COLUMN edge TO reach
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE lateral_contribution " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "lateral_contribution"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table} " +
|
||||||
|
"(pamhyr_id, name, type, tab, reach, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, type, tab, reach, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table, reachs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_ctor_from_type(cls, t):
|
def _get_ctor_from_type(cls, t):
|
||||||
@@ -124,84 +322,142 @@ class LateralContribution(SQLSubModel):
|
|||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
status = data['status']
|
||||||
|
edges = data["edges"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name, type, edge, begin_rk, end_rk " +
|
"SELECT pamhyr_id, deleted, name, type, " +
|
||||||
f"FROM lateral_contribution WHERE tab = '{tab}'"
|
"reach, begin_section, end_section, scenario " +
|
||||||
|
"FROM lateral_contribution " +
|
||||||
|
f"WHERE tab = '{tab}'" +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
t = row[2]
|
it = iter(row)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = next(it)
|
||||||
|
name = next(it)
|
||||||
|
t = next(it)
|
||||||
|
reach = next(it)
|
||||||
|
b_section = next(it)
|
||||||
|
e_section = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
ctor = cls._get_ctor_from_type(t)
|
ctor = cls._get_ctor_from_type(t)
|
||||||
lc = ctor(
|
lc = ctor(
|
||||||
id=row[0],
|
id=pid, name=name,
|
||||||
name=row[1],
|
status=status,
|
||||||
status=data['status']
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
lc.edge = None
|
lc.reach = None
|
||||||
|
lc._begin_section = None
|
||||||
|
lc._end_section = None
|
||||||
|
|
||||||
if row[3] != -1:
|
if row[3] != -1:
|
||||||
lc.edge = next(filter(lambda e: e.id == row[3], data["edges"]))
|
lc.reach = next(
|
||||||
lc._begin_rk = row[4]
|
filter(
|
||||||
lc._end_rk = row[5]
|
lambda e: e.id == reach,
|
||||||
|
edges
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lc._begin_section = next(
|
||||||
|
filter(
|
||||||
|
lambda p: p.id == b_section,
|
||||||
|
lc.reach.reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lc._end_section = next(
|
||||||
|
filter(
|
||||||
|
lambda p: p.id == e_section,
|
||||||
|
lc.reach.reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
values = execute(
|
data["lc"] = lc
|
||||||
"SELECT ind, data0, data1 FROM lateral_contribution_data " +
|
lc._data = Data._db_load(execute, data=data)
|
||||||
f"WHERE lc = '{lc.id}'"
|
|
||||||
)
|
|
||||||
# Create dummy data list
|
|
||||||
for _ in values:
|
|
||||||
lc.add(0)
|
|
||||||
# Write data
|
|
||||||
for v in values:
|
|
||||||
ind = v[0]
|
|
||||||
data0 = lc._types[0](v[1])
|
|
||||||
data1 = lc._types[1](v[2])
|
|
||||||
# Replace data at pos ind
|
|
||||||
lc._data[ind] = (data0, data1)
|
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
new.append(lc)
|
new.append(lc)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
data["lc"] = self
|
||||||
|
|
||||||
execute(f"DELETE FROM lateral_contribution WHERE id = {self.id}")
|
execute(
|
||||||
execute(f"DELETE FROM lateral_contribution_data WHERE lc = {self.id}")
|
"DELETE FROM lateral_contribution_data " +
|
||||||
|
f"WHERE lc = {self._pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
edge = -1
|
reach = -1
|
||||||
if self._edge is not None:
|
begin_section = -1
|
||||||
edge = self._edge.id
|
end_section = -1
|
||||||
|
|
||||||
sql = (
|
if self._reach is not None:
|
||||||
|
reach = self._reach._pamhyr_id
|
||||||
|
begin_section = self._begin_section._pamhyr_id
|
||||||
|
end_section = self._end_section._pamhyr_id
|
||||||
|
|
||||||
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"lateral_contribution(id, name, type, tab, " +
|
"lateral_contribution(" +
|
||||||
"edge, begin_rk, end_rk) " +
|
"pamhyr_id, deleted, name, type, tab, " +
|
||||||
|
"reach, begin_section, end_section, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._db_format(self._name)}', " +
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"'{self._db_format(self._type)}', '{tab}', {edge}, " +
|
f"'{self._db_format(self._name)}', " +
|
||||||
f"{self._begin_rk}, {self._end_rk}" +
|
f"'{self._db_format(self._type)}', '{tab}', {reach}, " +
|
||||||
|
f"{begin_section}, {end_section}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for d in self._data:
|
for d in self._data:
|
||||||
data0 = self._db_format(str(d[0]))
|
data["ind"] = ind
|
||||||
data1 = self._db_format(str(d[1]))
|
|
||||||
|
d._db_save(execute, data)
|
||||||
|
|
||||||
sql = (
|
|
||||||
"INSERT INTO " +
|
|
||||||
"lateral_contribution_data(ind, data0, data1, lc) " +
|
|
||||||
f"VALUES ({ind}, '{data0}', {data1}, {self.id})"
|
|
||||||
)
|
|
||||||
execute(sql)
|
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(
|
||||||
|
list(
|
||||||
|
filter(
|
||||||
|
lambda el: not el.is_deleted(),
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def compatibility(cls):
|
def compatibility(cls):
|
||||||
@@ -226,67 +482,66 @@ class LateralContribution(SQLSubModel):
|
|||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._name == "":
|
if self._name == "":
|
||||||
return f"L{self.id + 1}"
|
return f"LC #{self.id}"
|
||||||
|
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lctype(self):
|
def lctype(self):
|
||||||
return self._type
|
return self._type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def edge(self):
|
def reach(self):
|
||||||
return self._edge
|
return self._reach
|
||||||
|
|
||||||
@edge.setter
|
@reach.setter
|
||||||
def edge(self, edge):
|
def reach(self, reach):
|
||||||
self._edge = edge
|
self._reach = reach
|
||||||
if edge is not None:
|
if reach is not None:
|
||||||
self._begin_rk = self._edge.reach.get_rk_min()
|
self._begin_section = self._reach.reach.profiles[0]
|
||||||
self._end_rk = self._edge.reach.get_rk_max()
|
self._end_section = self._reach.reach.profiles[-1]
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def has_edge(self):
|
self.modified()
|
||||||
return self._edge is not None
|
|
||||||
|
def has_reach(self):
|
||||||
|
return self._reach is not None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def begin_rk(self):
|
def begin_rk(self):
|
||||||
return self._begin_rk
|
if self._begin_section is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
@begin_rk.setter
|
return self._begin_section.rk
|
||||||
def begin_rk(self, begin_rk):
|
|
||||||
if self._edge is None:
|
|
||||||
self._begin_rk = begin_rk
|
|
||||||
else:
|
|
||||||
_min = self._edge.reach.get_rk_min()
|
|
||||||
_max = self._edge.reach.get_rk_max()
|
|
||||||
|
|
||||||
if _min <= begin_rk <= _max:
|
@property
|
||||||
self._begin_rk = begin_rk
|
def begin_section(self):
|
||||||
|
return self._begin_section
|
||||||
|
|
||||||
self._status.modified()
|
@begin_section.setter
|
||||||
|
def begin_section(self, section):
|
||||||
|
self._begin_section = section
|
||||||
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def end_rk(self):
|
def end_rk(self):
|
||||||
return self._end_rk
|
if self._end_section is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
@end_rk.setter
|
return self._end_section.rk
|
||||||
def end_rk(self, end_rk):
|
|
||||||
if self._edge is None:
|
|
||||||
self._end_rk = end_rk
|
|
||||||
else:
|
|
||||||
_min = self._edge.reach.get_rk_min()
|
|
||||||
_max = self._edge.reach.get_rk_max()
|
|
||||||
|
|
||||||
if _min <= end_rk <= _max:
|
@property
|
||||||
self._end_rk = end_rk
|
def end_section(self):
|
||||||
|
return self._end_section
|
||||||
|
|
||||||
self._status.modified()
|
@end_section.setter
|
||||||
|
def end_section(self, section):
|
||||||
|
self._end_section = section
|
||||||
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def header(self):
|
def header(self):
|
||||||
@@ -294,7 +549,12 @@ class LateralContribution(SQLSubModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def data(self):
|
def data(self):
|
||||||
return self._data.copy()
|
return list(
|
||||||
|
filter(
|
||||||
|
lambda el: not el.is_deleted(),
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def get_type_column(self, column):
|
def get_type_column(self, column):
|
||||||
if 0 <= column < 2:
|
if 0 <= column < 2:
|
||||||
@@ -328,17 +588,17 @@ class LateralContribution(SQLSubModel):
|
|||||||
new_0 = self._types[0](data[0].replace(",", "."))
|
new_0 = self._types[0](data[0].replace(",", "."))
|
||||||
new_1 = self._types[1](data[1].replace(",", "."))
|
new_1 = self._types[1](data[1].replace(",", "."))
|
||||||
|
|
||||||
return (new_0, new_1)
|
return Data(new_0, new_1, status=self._status)
|
||||||
|
|
||||||
def add(self, index: int):
|
def add(self, index: int):
|
||||||
value = (self._default_0, self._default_1)
|
value = Data(self._default_0, self._default_1, status=self._status)
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def insert(self, index: int, value):
|
def insert(self, index: int, value):
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
def delete_i(self, indexes):
|
||||||
self._data = list(
|
self._data = list(
|
||||||
@@ -350,7 +610,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete(self, els):
|
def delete(self, els):
|
||||||
self._data = list(
|
self._data = list(
|
||||||
@@ -359,14 +619,14 @@ class LateralContribution(SQLSubModel):
|
|||||||
self.data
|
self.data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def sort(self, _reverse=False, key=None):
|
def sort(self, _reverse=False, key=None):
|
||||||
if key is None:
|
if key is None:
|
||||||
self._data.sort(reverse=_reverse)
|
self._data.sort(reverse=_reverse)
|
||||||
else:
|
else:
|
||||||
self._data.sort(reverse=_reverse, key=key)
|
self._data.sort(reverse=_reverse, key=key)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def get_i(self, index):
|
def get_i(self, index):
|
||||||
return self.data[index]
|
return self.data[index]
|
||||||
@@ -378,10 +638,10 @@ class LateralContribution(SQLSubModel):
|
|||||||
return lst
|
return lst
|
||||||
|
|
||||||
def _set_i_c_v(self, index, column, value):
|
def _set_i_c_v(self, index, column, value):
|
||||||
v = list(self._data[index])
|
v = self._data[index]
|
||||||
v[column] = self._types[column](value)
|
v[column] = self._types[column](value)
|
||||||
self._data[index] = tuple(v)
|
self._data[index] = v
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def set_i_0(self, index: int, value):
|
def set_i_0(self, index: int, value):
|
||||||
self._set_i_c_v(index, 0, value)
|
self._set_i_c_v(index, 0, value)
|
||||||
@@ -392,9 +652,9 @@ class LateralContribution(SQLSubModel):
|
|||||||
@timer
|
@timer
|
||||||
def convert(self, cls):
|
def convert(self, cls):
|
||||||
new = cls(name=self.name, status=self._status)
|
new = cls(name=self.name, status=self._status)
|
||||||
new.edge = self.edge
|
new.reach = self.reach
|
||||||
new.begin_rk = self.begin_rk
|
new.begin_section = self.begin_section
|
||||||
new.end_rk = self.end_rk
|
new.end_section = self.end_section
|
||||||
|
|
||||||
for i, _ in enumerate(self.data):
|
for i, _ in enumerate(self.data):
|
||||||
new.add(i)
|
new.add(i)
|
||||||
@@ -408,7 +668,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(e)
|
logger.info(e)
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def move_up(self, index):
|
def move_up(self, index):
|
||||||
@@ -416,11 +676,11 @@ class LateralContribution(SQLSubModel):
|
|||||||
next = index - 1
|
next = index - 1
|
||||||
d = self._data
|
d = self._data
|
||||||
d[index], d[next] = d[next], d[index]
|
d[index], d[next] = d[next], d[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def move_down(self, index):
|
def move_down(self, index):
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
d = self._data
|
d = self._data
|
||||||
d[index], d[prev] = d[prev], d[index]
|
d[index], d[prev] = d[prev], d[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# LateralContributionList.py -- Pamhyr
|
# LateralContributionList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelListWithTab
|
from Model.Tools.PamhyrListExt import PamhyrModelListWithTab
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.LateralContribution.LateralContribution import LateralContribution
|
from Model.LateralContribution.LateralContribution import LateralContribution
|
||||||
@@ -50,7 +50,10 @@ class LateralContributionList(PamhyrModelListWithTab):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM lateral_contribution")
|
execute(
|
||||||
|
"DELETE FROM lateral_contribution " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# LateralContributionTypes.py -- Pamhyr
|
# LateralContributionTypes.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,8 +22,12 @@ from Model.LateralContribution.LateralContribution import LateralContribution
|
|||||||
|
|
||||||
|
|
||||||
class NotDefined(LateralContribution):
|
class NotDefined(LateralContribution):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(NotDefined, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(NotDefined, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "ND"
|
self._type = "ND"
|
||||||
self._header = ["x", "y"]
|
self._header = ["x", "y"]
|
||||||
@@ -34,8 +38,12 @@ class NotDefined(LateralContribution):
|
|||||||
|
|
||||||
|
|
||||||
class LateralContrib(LateralContribution):
|
class LateralContrib(LateralContribution):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(LateralContrib, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(LateralContrib, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "LC"
|
self._type = "LC"
|
||||||
self._header = ["time", "discharge"]
|
self._header = ["time", "discharge"]
|
||||||
@@ -47,8 +55,12 @@ class LateralContrib(LateralContribution):
|
|||||||
|
|
||||||
|
|
||||||
class Rain(LateralContribution):
|
class Rain(LateralContribution):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(Rain, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(Rain, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "RA"
|
self._type = "RA"
|
||||||
self._header = ["time", "discharge"]
|
self._header = ["time", "discharge"]
|
||||||
@@ -60,8 +72,12 @@ class Rain(LateralContribution):
|
|||||||
|
|
||||||
|
|
||||||
class Evaporation(LateralContribution):
|
class Evaporation(LateralContribution):
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
super(Evaporation, self).__init__(id=id, name=name, status=status)
|
status=None, owner_scenario=-1):
|
||||||
|
super(Evaporation, self).__init__(
|
||||||
|
id=id, name=name, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._type = "EV"
|
self._type = "EV"
|
||||||
self._header = ["time", "discharge"]
|
self._header = ["time", "discharge"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# LateralContributionAdisTS.py -- Pamhyr
|
# LateralContributionAdisTS.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,137 +27,390 @@ from tools import (
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class LateralContributionAdisTS(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
def __init__(self,
|
||||||
|
data0, data1,
|
||||||
|
id: int = -1,
|
||||||
|
types=[float, float],
|
||||||
|
status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
|
super(Data, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
self._types = types
|
||||||
|
self._data = [data0, data1]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE lateral_contribution_data_adists{ext}(
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
data0 TEXT NOT NULL,
|
||||||
|
data1 TEXT NOT NULL,
|
||||||
|
lca INTEGER,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(lca) REFERENCES lateral_contribution_adists(pamhyr_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 7:
|
||||||
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "lateral_contribution_data_adists"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, data0, data1, lca, scenario) " +
|
||||||
|
"SELECT pamhyr_id, data0, data1, lc, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
cls._db_update_to_0_2_0_set_lca_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_lca_pid(cls, execute, data):
|
||||||
|
pid_lca = data["id2pid"]["lateral_contribution_adists"]
|
||||||
|
els = execute(
|
||||||
|
"SELECT pamhyr_id, lca " +
|
||||||
|
"FROM lateral_contribution_data_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
lca_id = next(it)
|
||||||
|
|
||||||
|
if lca_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE lateral_contribution_data_adists " +
|
||||||
|
f"SET lca = {pid_lca[lca_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, deleted, data0, data1 " +
|
||||||
|
"FROM lateral_contribution_data_adists " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
|
f"AND lca = '{lca.id}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
it = iter(row)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
data0 = next(it)
|
||||||
|
data1 = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
data = cls(
|
||||||
|
data0, data1,
|
||||||
|
id=pid, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
data.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(data)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
lca = data["lca"]
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"lateral_contribution_adists(pamhyr_id, deleted," +
|
||||||
|
"data0, data1, lca, scenario) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
|
f"{self._data[0]}, {self._data[1]}, " +
|
||||||
|
f"{lca.id}, {self._status.scenario_id}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._types[key](self._data[key])
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self._data[key] = self._types[key](value)
|
||||||
|
|
||||||
|
|
||||||
|
class LateralContributionAdisTS(SQLSubModel):
|
||||||
|
_sub_classes = [Data]
|
||||||
|
|
||||||
def __init__(self, id: int = -1, pollutant: int = -1,
|
def __init__(self, id: int = -1, pollutant: int = -1,
|
||||||
name: str = "", status=None):
|
name: str = "", status=None,
|
||||||
super(LateralContributionAdisTS, self).__init__()
|
owner_scenario=-1):
|
||||||
|
super(LateralContributionAdisTS, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
self.id = LateralContributionAdisTS._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._pollutant = pollutant
|
self._pollutant = pollutant
|
||||||
self._edge = None
|
self._reach = None
|
||||||
self._begin_rk = 0.0
|
self._begin_rk = 0.0
|
||||||
self._end_rk = 0.0
|
self._end_rk = 0.0
|
||||||
self._data = []
|
self._data = []
|
||||||
self._header = ["time", "rate"]
|
self._header = ["time", "rate"]
|
||||||
self._types = [self.time_convert, float]
|
self._types = [self.time_convert, float]
|
||||||
|
|
||||||
LateralContributionAdisTS._id_cnt = max(
|
|
||||||
LateralContributionAdisTS._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE lateral_contribution_adists(
|
CREATE TABLE lateral_contribution_adists{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
pollutant INTEGER NOT NULL,
|
pollutant INTEGER NOT NULL,
|
||||||
edge INTEGER NOT NULL,
|
reach INTEGER NOT NULL,
|
||||||
begin_rk REAL NOT NULL,
|
begin_rk REAL NOT NULL,
|
||||||
end_rk REAL NOT NULL,
|
end_rk REAL NOT NULL,
|
||||||
FOREIGN KEY(pollutant) REFERENCES Pollutants(id),
|
{Scenario.create_db_add_scenario()},
|
||||||
FOREIGN KEY(edge) REFERENCES river_reach(id)
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES Pollutants(pamhyr_id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
execute("""
|
if ext != "":
|
||||||
CREATE TABLE lateral_contribution_data_adists(
|
return True
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
data0 TEXT NOT NULL,
|
|
||||||
data1 TEXT NOT NULL,
|
|
||||||
lc INTEGER,
|
|
||||||
FOREIGN KEY(lc) REFERENCES lateral_contribution(id)
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 7:
|
||||||
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "lateral_contribution_adists"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, pollutant, reach, begin_rk, end_rk, scenario) " +
|
||||||
|
"SELECT pamhyr_id, pollutant, edge, begin_rk, end_rk, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table, reachs)
|
||||||
|
cls._db_update_to_0_2_0_set_pollutants_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_pollutants_pid(cls, execute, data):
|
||||||
|
pid_pol = data["id2pid"]["Pollutants"]
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, pollutant " +
|
||||||
|
"FROM lateral_contribution_adists"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
pol_id = next(it)
|
||||||
|
|
||||||
|
if pol_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE lateral_contribution_adists " +
|
||||||
|
f"SET pollutant = {pid_pol[pol_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, pollutant, edge, begin_rk, end_rk " +
|
"SELECT pamhyr_id, deleted, pollutant, reach, " +
|
||||||
"FROM lateral_contribution_adists"
|
"begin_rk, end_rk, scenario " +
|
||||||
|
"FROM lateral_contribution_adists " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
lc = cls(
|
it = iter(row)
|
||||||
id=row[0],
|
|
||||||
pollutant=row[1],
|
pid = next(it)
|
||||||
status=data['status']
|
deleted = (next(it) == 1)
|
||||||
|
pollutant = next(it)
|
||||||
|
reach = next(it)
|
||||||
|
brk = next(it)
|
||||||
|
erk = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
lca = cls(
|
||||||
|
id=pid,
|
||||||
|
pollutant=pollutant,
|
||||||
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
lca.set_as_deleted()
|
||||||
|
|
||||||
lc.edge = row[2]
|
lca.reach = reach
|
||||||
lc.begin_rk = row[3]
|
lca.begin_rk = brk
|
||||||
lc.end_rk = row[4]
|
lca.end_rk = erk
|
||||||
|
|
||||||
values = execute(
|
data["lca"] = lca
|
||||||
"SELECT data0," +
|
lca._data = Data._db_load(execute, data=data)
|
||||||
" data1 FROM lateral_contribution_data_adists " +
|
|
||||||
f"WHERE lc = '{lc.id}'"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Write data
|
loaded.add(pid)
|
||||||
for v in values:
|
new.append(lca)
|
||||||
data0 = lc._types[0](v[0])
|
|
||||||
data1 = lc._types[1](v[1])
|
|
||||||
# Replace data at pos ind
|
|
||||||
lc._data.append((data0, data1))
|
|
||||||
|
|
||||||
new.append(lc)
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
execute(f"DELETE FROM lateral_contribution_adists" +
|
execute(
|
||||||
f" WHERE id = {self.id}")
|
f"DELETE FROM lateral_contribution_adists " +
|
||||||
execute(f"DELETE FROM lateral_contribution_data_adists" +
|
f"WHERE pamhyr_id = {self.id} " +
|
||||||
f" WHERE lc = {self.id}")
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
f"DELETE FROM lateral_contribution_data_adists " +
|
||||||
|
f"WHERE lca = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"lateral_contribution_adists(id, " +
|
"lateral_contribution_adists(id, deleted," +
|
||||||
"pollutant, edge, begin_rk, end_rk) " +
|
"pollutant, reach, begin_rk, end_rk, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {self._pollutant}, {self.edge}, " +
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
|
f"{self._pollutant}, {self.reach}, " +
|
||||||
f"{self._begin_rk}, {self._end_rk}" +
|
f"{self._begin_rk}, {self._end_rk}" +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
|
ind = 0
|
||||||
for d in self._data:
|
for d in self._data:
|
||||||
data0 = self._db_format(str(d[0]))
|
data["ind"] = ind
|
||||||
data1 = self._db_format(str(d[1]))
|
|
||||||
|
|
||||||
sql = (
|
d._db_save(execute, data)
|
||||||
"INSERT INTO " +
|
|
||||||
"lateral_contribution_data_adists(data0, data1, lc) " +
|
ind += 1
|
||||||
f"VALUES ('{data0}', {data1}, {self.id})"
|
|
||||||
)
|
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(
|
||||||
|
list(
|
||||||
|
filter(
|
||||||
|
lambda el: not el.is_deleted(),
|
||||||
|
self._data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def time_convert(cls, data):
|
def time_convert(cls, data):
|
||||||
@@ -176,13 +429,13 @@ class LateralContributionAdisTS(SQLSubModel):
|
|||||||
return int(data)
|
return int(data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def edge(self):
|
def reach(self):
|
||||||
return self._edge
|
return self._reach
|
||||||
|
|
||||||
@edge.setter
|
@reach.setter
|
||||||
def edge(self, edge):
|
def reach(self, reach):
|
||||||
self._edge = edge
|
self._reach = reach
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def header(self):
|
def header(self):
|
||||||
@@ -191,7 +444,7 @@ class LateralContributionAdisTS(SQLSubModel):
|
|||||||
@header.setter
|
@header.setter
|
||||||
def header(self, header):
|
def header(self, header):
|
||||||
self._header = header
|
self._header = header
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pollutant(self):
|
def pollutant(self):
|
||||||
@@ -208,7 +461,7 @@ class LateralContributionAdisTS(SQLSubModel):
|
|||||||
@begin_rk.setter
|
@begin_rk.setter
|
||||||
def begin_rk(self, begin_rk):
|
def begin_rk(self, begin_rk):
|
||||||
self._begin_rk = begin_rk
|
self._begin_rk = begin_rk
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def end_rk(self):
|
def end_rk(self):
|
||||||
@@ -217,4 +470,4 @@ class LateralContributionAdisTS(SQLSubModel):
|
|||||||
@end_rk.setter
|
@end_rk.setter
|
||||||
def end_rk(self, end_rk):
|
def end_rk(self, end_rk):
|
||||||
self._end_rk = end_rk
|
self._end_rk = end_rk
|
||||||
self._status.modified()
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# LateralContributionsAdisTSList.py -- Pamhyr
|
# LateralContributionsAdisTSList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.LateralContributionsAdisTS.LateralContributionAdisTS \
|
from Model.LateralContributionsAdisTS.LateralContributionAdisTS \
|
||||||
@@ -45,8 +45,14 @@ class LateralContributionsAdisTSList(PamhyrModelList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM lateral_contribution_adists")
|
execute(
|
||||||
execute("DELETE FROM lateral_condition_data_adists")
|
"DELETE FROM lateral_contribution_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM lateral_contribution_data_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
+16
-22
@@ -1,5 +1,5 @@
|
|||||||
# Edge.py -- Pamhyr
|
# Edge.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,28 +16,18 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Network.Node import Node
|
from Model.Network.Node import Node
|
||||||
|
|
||||||
|
|
||||||
class Edge(object):
|
class Edge(SQLSubModel):
|
||||||
_id_cnt = 0
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
|
|
||||||
def __init__(self, id: int, name: str,
|
|
||||||
node1: Node = None,
|
node1: Node = None,
|
||||||
node2: Node = None,
|
node2: Node = None,
|
||||||
status=None):
|
**kwargs):
|
||||||
super(Edge, self).__init__()
|
super(Edge, self).__init__(id=id, **kwargs)
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
type(self)._id_cnt += 1
|
|
||||||
self.id = type(self)._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
|
|
||||||
self.node1 = node1
|
self.node1 = node1
|
||||||
self.node2 = node2
|
self.node2 = node2
|
||||||
|
|
||||||
@@ -49,7 +39,7 @@ class Edge(object):
|
|||||||
if name == "name":
|
if name == "name":
|
||||||
ret = self.name
|
ret = self.name
|
||||||
elif name == "id":
|
elif name == "id":
|
||||||
ret = self.id
|
ret = self.pamhyr_id
|
||||||
elif name == "node1":
|
elif name == "node1":
|
||||||
ret = self.node1
|
ret = self.node1
|
||||||
elif name == "node2":
|
elif name == "node2":
|
||||||
@@ -63,7 +53,7 @@ class Edge(object):
|
|||||||
if name == "name":
|
if name == "name":
|
||||||
self._name = value
|
self._name = value
|
||||||
elif name == "id":
|
elif name == "id":
|
||||||
self.id = value
|
self.pamhyr_id = value
|
||||||
elif name == "node1":
|
elif name == "node1":
|
||||||
self.node1 = value
|
self.node1 = value
|
||||||
elif name == "node2":
|
elif name == "node2":
|
||||||
@@ -71,7 +61,11 @@ class Edge(object):
|
|||||||
elif name == "enable":
|
elif name == "enable":
|
||||||
self._enable = value
|
self._enable = value
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
return self.pamhyr_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -85,14 +79,14 @@ class Edge(object):
|
|||||||
|
|
||||||
def enable(self, enable=True):
|
def enable(self, enable=True):
|
||||||
self._enable = enable
|
self._enable = enable
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
self._enable = False
|
self._enable = False
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def reverse(self):
|
def reverse(self):
|
||||||
tmp = self.node1
|
tmp = self.node1
|
||||||
self.node1 = self.node2
|
self.node1 = self.node2
|
||||||
self.node2 = tmp
|
self.node2 = tmp
|
||||||
self._status.modified()
|
self.modified()
|
||||||
+40
-34
@@ -1,5 +1,5 @@
|
|||||||
# Graph.py -- Pamhyr
|
# Graph.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,15 +18,15 @@
|
|||||||
|
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
from Model.Network.Node import Node
|
from Model.Network.Node import Node
|
||||||
from Model.Network.Edge import Edge
|
from Model.Network.Edge import Edge
|
||||||
|
|
||||||
|
|
||||||
class Graph(object):
|
class Graph(SQLSubModel):
|
||||||
def __init__(self, status=None):
|
def __init__(self, **kwargs):
|
||||||
super(Graph, self).__init__()
|
super(Graph, self).__init__(**kwargs)
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._node_ctor = Node
|
self._node_ctor = Node
|
||||||
self._edge_ctor = Edge
|
self._edge_ctor = Edge
|
||||||
@@ -38,13 +38,13 @@ class Graph(object):
|
|||||||
return f"Graph {{nodes: {self._nodes}, edges: {self._edges}}}"
|
return f"Graph {{nodes: {self._nodes}, edges: {self._edges}}}"
|
||||||
|
|
||||||
def nodes(self):
|
def nodes(self):
|
||||||
return self._nodes
|
return list(filter(lambda n: not n.is_deleted(), self._nodes))
|
||||||
|
|
||||||
def nodes_names(self):
|
def nodes_names(self):
|
||||||
return list(map(lambda n: n.name, self._nodes))
|
return list(map(lambda n: n.name, self.nodes()))
|
||||||
|
|
||||||
def edges(self):
|
def edges(self):
|
||||||
return self._edges
|
return list(filter(lambda e: not e.is_deleted(), self._edges))
|
||||||
|
|
||||||
def enable_edges(self):
|
def enable_edges(self):
|
||||||
return list(
|
return list(
|
||||||
@@ -54,44 +54,44 @@ class Graph(object):
|
|||||||
def _enable_edges(self):
|
def _enable_edges(self):
|
||||||
"""Return a generator"""
|
"""Return a generator"""
|
||||||
return filter(
|
return filter(
|
||||||
lambda e: e.is_enable(),
|
lambda e: e.is_enable() and not e.is_deleted(),
|
||||||
self._edges
|
self.edges()
|
||||||
)
|
)
|
||||||
|
|
||||||
def edges_names(self):
|
def edges_names(self):
|
||||||
return list(map(lambda e: e.name, self._edges))
|
return list(map(lambda e: e.name, self.edges()))
|
||||||
|
|
||||||
def nodes_counts(self):
|
def nodes_counts(self):
|
||||||
return len(self._nodes)
|
return len(self.nodes())
|
||||||
|
|
||||||
def edges_counts(self):
|
def edges_counts(self):
|
||||||
return len(self._edges)
|
return len(self.edges())
|
||||||
|
|
||||||
def enable_nodes_counts(self):
|
def enable_nodes_counts(self):
|
||||||
return reduce(
|
return reduce(
|
||||||
lambda acc, n: acc + 1 if self.is_enable_node(n) else acc,
|
lambda acc, n: acc + 1 if self.is_enable_node(n) else acc,
|
||||||
self._nodes,
|
self.nodes(),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
||||||
def enable_edges_counts(self):
|
def enable_edges_counts(self):
|
||||||
return reduce(
|
return reduce(
|
||||||
lambda acc, e: acc + 1 if e.is_enable() else acc,
|
lambda acc, e: acc + 1 if e.is_enable() else acc,
|
||||||
self._edges,
|
self.edges(),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_node_exists(self, node_name):
|
def is_node_exists(self, node_name):
|
||||||
return reduce(
|
return reduce(
|
||||||
lambda acc, n: (acc or (n.name == node_name)),
|
lambda acc, n: (acc or (n.name == node_name)),
|
||||||
self._nodes,
|
self.nodes(),
|
||||||
False
|
False
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_edge_exists(self, edge_name):
|
def is_edge_exists(self, edge_name):
|
||||||
return reduce(
|
return reduce(
|
||||||
lambda acc, e: (acc or (e.name == edge_name)),
|
lambda acc, e: (acc or (e.name == edge_name)),
|
||||||
self._edges,
|
self.edges(),
|
||||||
False
|
False
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ class Graph(object):
|
|||||||
node = list(
|
node = list(
|
||||||
filter(
|
filter(
|
||||||
lambda n: n.name == node_name,
|
lambda n: n.name == node_name,
|
||||||
self._nodes
|
self.nodes()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ class Graph(object):
|
|||||||
edge = list(
|
edge = list(
|
||||||
filter(
|
filter(
|
||||||
lambda e: e.name == edge_name,
|
lambda e: e.name == edge_name,
|
||||||
self._edges
|
self.edges()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,18 +121,23 @@ class Graph(object):
|
|||||||
|
|
||||||
return edge[0]
|
return edge[0]
|
||||||
|
|
||||||
|
def reach(self, reach_name: str):
|
||||||
|
return self.edge(reach_name)
|
||||||
|
|
||||||
def _create_node(self, x: float, y: float):
|
def _create_node(self, x: float, y: float):
|
||||||
node = self._node_ctor(
|
node = self._node_ctor(
|
||||||
-1,
|
id=-1, name="", x=x, y=y,
|
||||||
"",
|
|
||||||
x=x, y=y,
|
|
||||||
status=self._status
|
status=self._status
|
||||||
)
|
)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def _add_node(self, node):
|
def _add_node(self, node):
|
||||||
self._nodes.append(node)
|
if node in self._nodes:
|
||||||
self._status.modified()
|
node.set_as_not_deleted()
|
||||||
|
else:
|
||||||
|
self._nodes.append(node)
|
||||||
|
|
||||||
|
self.modified()
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def add_node(self, x: float = 0.0, y: float = 0.0):
|
def add_node(self, x: float = 0.0, y: float = 0.0):
|
||||||
@@ -143,9 +148,9 @@ class Graph(object):
|
|||||||
return self._add_node(node)
|
return self._add_node(node)
|
||||||
|
|
||||||
def remove_node(self, node):
|
def remove_node(self, node):
|
||||||
self._nodes.remove(node)
|
node.set_as_deleted()
|
||||||
self._remove_associated_edge(node)
|
self._remove_associated_edge(node)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def _remove_associated_edge(self, node: str):
|
def _remove_associated_edge(self, node: str):
|
||||||
edges = list(
|
edges = list(
|
||||||
@@ -164,8 +169,7 @@ class Graph(object):
|
|||||||
|
|
||||||
def _create_edge(self, n1: Node, n2: Node):
|
def _create_edge(self, n1: Node, n2: Node):
|
||||||
edge = self._edge_ctor(
|
edge = self._edge_ctor(
|
||||||
-1,
|
node1=n1, node2=n2,
|
||||||
"", n1, n2,
|
|
||||||
status=self._status
|
status=self._status
|
||||||
)
|
)
|
||||||
return edge
|
return edge
|
||||||
@@ -176,10 +180,12 @@ class Graph(object):
|
|||||||
# e.node2 == edge.node2),
|
# e.node2 == edge.node2),
|
||||||
# self._edges)):
|
# self._edges)):
|
||||||
# return None
|
# return None
|
||||||
|
if edge in self._edges:
|
||||||
|
edge.set_as_not_deleted()
|
||||||
|
else:
|
||||||
|
self._edges.append(edge)
|
||||||
|
|
||||||
self._edges.append(edge)
|
self.modified()
|
||||||
|
|
||||||
self._status.modified()
|
|
||||||
return edge
|
return edge
|
||||||
|
|
||||||
def add_edge(self, n1: Node, n2: Node):
|
def add_edge(self, n1: Node, n2: Node):
|
||||||
@@ -193,8 +199,8 @@ class Graph(object):
|
|||||||
return self._create_edge(n1, n2)
|
return self._create_edge(n1, n2)
|
||||||
|
|
||||||
def remove_edge(self, edge):
|
def remove_edge(self, edge):
|
||||||
self._edges.remove(edge)
|
edge.set_as_deleted()
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def is_upstream_node(self, node):
|
def is_upstream_node(self, node):
|
||||||
return reduce(
|
return reduce(
|
||||||
|
|||||||
+10
-19
@@ -1,5 +1,5 @@
|
|||||||
# Node.py -- Pamhyr
|
# Node.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,24 +16,15 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Network.Point import Point
|
from Model.Network.Point import Point
|
||||||
|
|
||||||
|
|
||||||
class Node(object):
|
class Node(SQLSubModel):
|
||||||
_id_cnt = 0
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
|
|
||||||
def __init__(self, id: int, name: str,
|
|
||||||
x: float = 0.0, y: float = 0.0,
|
x: float = 0.0, y: float = 0.0,
|
||||||
status=None):
|
**kwargs):
|
||||||
super(Node, self).__init__()
|
super(Node, self).__init__(id=id, **kwargs)
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
if id == -1:
|
|
||||||
type(self)._id_cnt += 1
|
|
||||||
self.id = type(self)._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self.pos = Point(x, y)
|
self.pos = Point(x, y)
|
||||||
@@ -44,7 +35,7 @@ class Node(object):
|
|||||||
if key == "name":
|
if key == "name":
|
||||||
ret = self._name
|
ret = self._name
|
||||||
elif key == "id":
|
elif key == "id":
|
||||||
ret = self.id
|
ret = self.pamhyr_id
|
||||||
elif key == "pos":
|
elif key == "pos":
|
||||||
ret = f"({self.pos.x},{self.pos.y})"
|
ret = f"({self.pos.x},{self.pos.y})"
|
||||||
|
|
||||||
@@ -54,9 +45,9 @@ class Node(object):
|
|||||||
if key == "name":
|
if key == "name":
|
||||||
self._name = value
|
self._name = value
|
||||||
elif key == "id":
|
elif key == "id":
|
||||||
self.id = value
|
self.pamhyr_id = value
|
||||||
|
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -76,4 +67,4 @@ class Node(object):
|
|||||||
def setPos(self, x, y):
|
def setPos(self, x, y):
|
||||||
self.pos.x = x
|
self.pos.x = x
|
||||||
self.pos.y = y
|
self.pos.y = y
|
||||||
self._status.modified()
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Point.py -- Pamhyr
|
# Point.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# __init__.py -- Pamhyr
|
# __init__.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# test_Network.py -- Pamhyr
|
# test_Network.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,7 +20,7 @@ import os
|
|||||||
import unittest
|
import unittest
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from Model.Saved import SavedStatus
|
from Model.Status import StudyStatus
|
||||||
|
|
||||||
from Model.Network.Graph import Graph
|
from Model.Network.Graph import Graph
|
||||||
from Model.Network.Edge import Edge
|
from Model.Network.Edge import Edge
|
||||||
@@ -28,7 +28,7 @@ from Model.Network.Node import Node
|
|||||||
|
|
||||||
|
|
||||||
def new_graph():
|
def new_graph():
|
||||||
status = SavedStatus()
|
status = StudyStatus()
|
||||||
g = Graph(status=status)
|
g = Graph(status=status)
|
||||||
|
|
||||||
return g
|
return g
|
||||||
@@ -60,6 +60,9 @@ class GraphTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
e0 = g.add_edge(n0, n1)
|
e0 = g.add_edge(n0, n1)
|
||||||
|
|
||||||
|
self.assertEqual(g.nodes_counts(), 2)
|
||||||
|
self.assertEqual(g.edges_counts(), 1)
|
||||||
|
|
||||||
g.remove_edge(e0)
|
g.remove_edge(e0)
|
||||||
|
|
||||||
self.assertEqual(g.nodes_counts(), 2)
|
self.assertEqual(g.nodes_counts(), 2)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OutputRKAdists.py -- Pamhyr
|
# OutputRKAdists.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,33 +27,27 @@ from tools import (
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class OutputRKAdists(SQLSubModel):
|
class OutputRKAdists(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, reach=None,
|
def __init__(self, id: int = -1, reach=None,
|
||||||
rk=None, title: str = "", status=None):
|
rk=None, title: str = "", status=None,
|
||||||
super(OutputRKAdists, self).__init__()
|
owner_scenario=-1):
|
||||||
|
super(OutputRKAdists, self).__init__(
|
||||||
self._status = status
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
if id == -1:
|
)
|
||||||
self.id = OutputRKAdists._id_cnt
|
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
self._rk = rk
|
self._rk = rk
|
||||||
self._title = str(title)
|
self._title = str(title)
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
|
|
||||||
OutputRKAdists._id_cnt = max(
|
|
||||||
OutputRKAdists._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
return self._reach
|
return self._reach
|
||||||
@@ -82,70 +76,129 @@ class OutputRKAdists(SQLSubModel):
|
|||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
sql = (
|
CREATE TABLE output_rk_adists{ext}(
|
||||||
"CREATE TABLE OutputRKAdists(" +
|
{cls.create_db_add_pamhyr_id()},
|
||||||
"id INTEGER NOT NULL PRIMARY KEY, " +
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
"reach INTEGER NOT NULL, " +
|
reach INTEGER NOT NULL,
|
||||||
"rk REAL NOT NULL, " +
|
rk REAL NOT NULL,
|
||||||
"title TEXT NOT NULL, " +
|
title TEXT NOT NULL,
|
||||||
"FOREIGN KEY(reach) REFERENCES river_reach(id)" +
|
{Scenario.create_db_add_scenario()},
|
||||||
")"
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
)
|
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
||||||
|
)
|
||||||
execute(sql)
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 7:
|
||||||
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "OutputRKAdists"
|
||||||
|
table_new = "output_rk_adists"
|
||||||
|
reachs = data['id2pid']['river_reach']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table_new}_tmp " +
|
||||||
|
"(pamhyr_id, reach, rk, title, scenario) " +
|
||||||
|
"SELECT pamhyr_id, reach, rk, title, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table_new}_tmp RENAME TO {table_new}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_reach_pid(execute, table_new, reachs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
# reach = data["reach"]
|
# reach = data["reach"]
|
||||||
# profile = data["profile"]
|
# profile = data["profile"]
|
||||||
status = data["status"]
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, reach, rk, title " +
|
"SELECT pamhyr_id, deleted, reach, rk, title, scenario " +
|
||||||
f"FROM OutputRKAdists"
|
f"FROM output_rk_adists"
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
id_reach = row[1]
|
|
||||||
id_rk = row[2]
|
pid = next(it)
|
||||||
title = row[3]
|
deleted = (next(it) == 1)
|
||||||
|
id_reach = next(it)
|
||||||
|
id_rk = next(it)
|
||||||
|
title = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
new_output = cls(
|
new_output = cls(
|
||||||
id=id, reach=id_reach,
|
id=pid, reach=id_reach,
|
||||||
rk=id_rk, title=title,
|
rk=id_rk, title=title,
|
||||||
status=status
|
status=status,
|
||||||
|
owner_scenario=owner_scenario,
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
new_output.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
new.append(new_output)
|
new.append(new_output)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
execute(f"DELETE FROM OutputRKAdists WHERE id = {self.id}")
|
execute(
|
||||||
|
"DELETE FROM output_rk_adists " +
|
||||||
sql = (
|
f"WHERE pamhyr_id = {self.id} " +
|
||||||
"INSERT INTO " +
|
f"AND scenario = {self._status.scenario_id} "
|
||||||
"OutputRKAdists(id, reach, rk, title) " +
|
|
||||||
"VALUES (" +
|
|
||||||
f"{self.id}, {self._reach}, {self._rk}, " +
|
|
||||||
f"'{self._db_format(self._title)}'" +
|
|
||||||
")"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
execute(sql)
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"output_rk_adists(pamhyr_id, deleted, " +
|
||||||
|
"reach, rk, title, scenario) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {self._db_format(self.is_deleted())}" +
|
||||||
|
f"{self._reach}, {self._rk}, " +
|
||||||
|
f"'{self._db_format(self._title)}', " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# OutputRKListAdists.py -- Pamhyr
|
# OutputRKListAdists.py -- Pamhyr
|
||||||
# Copyright (C) 2024 INRAE
|
# Copyright (C) 2024-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.OutputRKAdists.OutputRKAdists import OutputRKAdists
|
from Model.OutputRKAdists.OutputRKAdists import OutputRKAdists
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,10 @@ class OutputRKAdistsList(PamhyrModelList):
|
|||||||
ok = True
|
ok = True
|
||||||
|
|
||||||
# Delete previous data
|
# Delete previous data
|
||||||
execute("DELETE FROM OutputRKAdists")
|
execute(
|
||||||
|
"DELETE FROM output_rk_adists " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
for sl in self._lst:
|
for sl in self._lst:
|
||||||
ok &= sl._db_save(execute, data)
|
ok &= sl._db_save(execute, data)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Pollutants.py -- Pamhyr
|
# Pollutants.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,32 +27,273 @@ from tools import (
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Pollutants(SQLSubModel):
|
class PollutantCharacteristics(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "", status=None):
|
def __init__(self, id: int = -1, type=-1,
|
||||||
super(Pollutants, self).__init__()
|
diametre=-1, rho=-1,
|
||||||
|
porosity=-1,
|
||||||
|
cdc_riv=-1, cdc_cas=-1,
|
||||||
|
apd=-1, ac=-1, bc=-1,
|
||||||
|
pollutant=None,
|
||||||
|
status=None,
|
||||||
|
owner_scenario=-1):
|
||||||
|
super(PollutantCharacteristics, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
if id == -1:
|
self._type = type
|
||||||
self.id = Pollutants._id_cnt
|
self._diametre = diametre
|
||||||
else:
|
self._rho = rho
|
||||||
self.id = id
|
self._porosity = porosity
|
||||||
|
self._cdc_riv = cdc_riv
|
||||||
|
self._cdc_cas = cdc_cas
|
||||||
|
self._apd = apd
|
||||||
|
self._ac = ac
|
||||||
|
self._bc = bc
|
||||||
|
self._pollutant = pollutant
|
||||||
|
|
||||||
self._name = str(name)
|
# FIXME: This four next method is dirty work, just an hack to keep
|
||||||
|
# the View API working... Must be refactoring
|
||||||
|
def to_list(self):
|
||||||
|
return [
|
||||||
|
self._type,
|
||||||
|
self._diametre,
|
||||||
|
self._rho,
|
||||||
|
self._porosity,
|
||||||
|
self._cdc_riv,
|
||||||
|
self._cdc_cas,
|
||||||
|
self._apd,
|
||||||
|
self._ac,
|
||||||
|
self._bc,
|
||||||
|
]
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.to_list())
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.to_list()[key]
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
if key == 0:
|
||||||
|
self._type = value
|
||||||
|
elif key == 1:
|
||||||
|
self._diametre = value
|
||||||
|
elif key == 2:
|
||||||
|
self._rho = value
|
||||||
|
elif key == 3:
|
||||||
|
self._porosity = value
|
||||||
|
elif key == 4:
|
||||||
|
self._cdc_riv = value
|
||||||
|
elif key == 5:
|
||||||
|
self._cdc_cas = value
|
||||||
|
elif key == 6:
|
||||||
|
self._apd = value
|
||||||
|
elif key == 7:
|
||||||
|
self._ac = value
|
||||||
|
elif key == 8:
|
||||||
|
self._bc = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE pollutants_characteristics{ext}(
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
type INTEGER NOT NULL,
|
||||||
|
diametre REAL NOT NULL,
|
||||||
|
rho REAL NOT NULL,
|
||||||
|
porosity REAL NOT NULL,
|
||||||
|
cdc_riv REAL NOT NULL,
|
||||||
|
cdc_cas REAL NOT NULL,
|
||||||
|
apd REAL NOT NULL,
|
||||||
|
ac REAL NOT NULL,
|
||||||
|
bc REAL NOT NULL,
|
||||||
|
pollutant INTEGER NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(pollutant) REFERENCES pollutants(pamhyr_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 7:
|
||||||
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "Pollutants_characteristics"
|
||||||
|
table_new = "pollutants_characteristics"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table_new}_tmp " +
|
||||||
|
"(pamhyr_id, type, diametre, rho, porosity, " +
|
||||||
|
"cdc_riv, cdc_cas, apd, ac, bc, pollutant, scenario) " +
|
||||||
|
"SELECT pamhyr_id, type, diametre, rho, porosity, " +
|
||||||
|
"cdc_riv, cdc_cas, apd, ac, bc, pollutant, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table_new}_tmp RENAME TO {table_new}")
|
||||||
|
|
||||||
|
cls._db_update_to_0_2_0_set_pollutants_pid(execute, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_pollutants_pid(cls, execute, data):
|
||||||
|
pid_pol = data["id2pid"]["Pollutants"]
|
||||||
|
els = execute(
|
||||||
|
f"SELECT pamhyr_id, pollutant " +
|
||||||
|
"FROM pollutants_characteristics"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in els:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
pol_id = next(it)
|
||||||
|
|
||||||
|
if pol_id == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE pollutants_characteristics " +
|
||||||
|
f"SET pollutant = {pid_pol[pol_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
status = data["status"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
pollutant = data['pollutant']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, deleted, type, diametre, rho, porosity, " +
|
||||||
|
"cdc_riv, cdc_cas, apd, ac, bc, scenario " +
|
||||||
|
"FROM pollutants_characteristics " +
|
||||||
|
f"WHERE pollutant = {pollutant.id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is not None:
|
||||||
|
for row in table:
|
||||||
|
it = iter(row)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
type = next(it)
|
||||||
|
diametre = next(it)
|
||||||
|
rho = next(it)
|
||||||
|
porosity = next(it)
|
||||||
|
cdc_riv = next(it)
|
||||||
|
cdc_cas = next(it)
|
||||||
|
apd = next(it)
|
||||||
|
ac = next(it)
|
||||||
|
bc = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
pc = cls(
|
||||||
|
id=pid, type=type,
|
||||||
|
diametre=diametre,
|
||||||
|
rho=rho,
|
||||||
|
porosity=porosity,
|
||||||
|
cdc_riv=cdc_riv, cdc_cas=cdc_cas,
|
||||||
|
apd=apd, ac=ac, bc=bc,
|
||||||
|
pollutant=pollutant,
|
||||||
|
status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
pc.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(pc)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"pollutants_characteristics(pamhyr_id, deleted, " +
|
||||||
|
"type, diametre, rho, porosity, " +
|
||||||
|
"cdc_riv, cdc_cas, apd, ac, bc, " +
|
||||||
|
"pollutant, scenario) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
|
f"{self._type}, " +
|
||||||
|
f"{self._diametre}, {self._rho}, " +
|
||||||
|
f"{self._porosity}, " +
|
||||||
|
f"{self._cdc_riv}, {self._cdc_cas}, " +
|
||||||
|
f"{self._apd}, {self._ac}, {self._bc}, " +
|
||||||
|
f"{self._pollutant.id}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class Pollutants(SQLSubModel):
|
||||||
|
_sub_classes = [PollutantCharacteristics]
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
|
super(Pollutants, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
if name is None or name == "":
|
||||||
|
self.name = f"pol{self.id}"
|
||||||
|
else:
|
||||||
|
self._name = str(name)
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
|
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
Pollutants._id_cnt = max(
|
|
||||||
Pollutants._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._name
|
return self._name
|
||||||
@@ -64,106 +305,151 @@ class Pollutants(SQLSubModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def data(self):
|
def data(self):
|
||||||
return self._data.copy()
|
return self._data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE Pollutants(
|
CREATE TABLE pollutants{ext}(
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
name TEXT NOT NULL UNIQUE
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()}
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
execute("""
|
if ext != "":
|
||||||
CREATE TABLE Pollutants_characteristics(
|
return True
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
|
||||||
type INTEGER NOT NULL,
|
|
||||||
diametre REAL NOT NULL,
|
|
||||||
rho REAL NOT NULL,
|
|
||||||
porosity REAL NOT NULL,
|
|
||||||
cdc_riv REAL NOT NULL,
|
|
||||||
cdc_cas REAL NOT NULL,
|
|
||||||
apd REAL NOT NULL,
|
|
||||||
ac REAL NOT NULL,
|
|
||||||
bc REAL NOT NULL,
|
|
||||||
pollutant INTEGER NOT NULL,
|
|
||||||
FOREIGN KEY(pollutant) REFERENCES Pollutants(id)
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
created = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 7:
|
||||||
|
cls._db_create(execute)
|
||||||
|
created = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
if not created:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if not created:
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "Pollutants"
|
||||||
|
table_new = "pollutants"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table_new}_tmp " +
|
||||||
|
"(pamhyr_id, name, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table_new}_tmp RENAME TO {table_new}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name " +
|
"SELECT pamhyr_id, deleted, name FROM pollutants " +
|
||||||
f"FROM Pollutants"
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
if table is not None:
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
name = row[1]
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
|
||||||
new_pollutant = cls(
|
new_pollutant = cls(
|
||||||
id=id, name=name,
|
id=pid, name=name,
|
||||||
status=status
|
status=status
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
new_pollutant.set_as_deleted()
|
||||||
|
|
||||||
new_data = []
|
data["pollutant"] = new_pollutant
|
||||||
table = execute(
|
new_pollutant._data = PollutantCharacteristics._db_load(
|
||||||
"SELECT * " +
|
execute, data.copy()
|
||||||
"FROM Pollutants_characteristics " +
|
|
||||||
f"WHERE pollutant = {id}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if table is not None:
|
loaded.add(pid)
|
||||||
for t in table:
|
|
||||||
new_data = t[1:-1]
|
|
||||||
|
|
||||||
new_pollutant._data.append(new_data)
|
|
||||||
|
|
||||||
new.append(new_pollutant)
|
new.append(new_pollutant)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
execute(f"DELETE FROM Pollutants WHERE id = {self.id}")
|
ok = True
|
||||||
execute(f"DELETE FROM Pollutants_characteristics" +
|
|
||||||
f" WHERE pollutant = {self.id}")
|
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
|
"DELETE FROM pollutants " +
|
||||||
|
f"WHERE pamhyr_id = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
f"DELETE FROM pollutants_characteristics " +
|
||||||
|
f"WHERE pollutant = {self.id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"Pollutants(id, name) " +
|
"pollutants(pamhyr_id, deleted, name, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, " +
|
f"{self.id}, {self._db_format(self.is_deleted())}, " +
|
||||||
f"'{self._db_format(self._name)}'" +
|
f"'{self._db_format(self._name)}', " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
|
|
||||||
execute(sql)
|
for d in self._data:
|
||||||
|
ok &= d._db_save(execute, data)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
for d in self._data:
|
for d in self._data:
|
||||||
sql = (
|
d._data_traversal(predicate, modifier, data)
|
||||||
"INSERT INTO " +
|
|
||||||
"Pollutants_characteristics(type, diametre, rho, porosity, " +
|
|
||||||
"cdc_riv, cdc_cas, apd, ac, bc, pollutant) " +
|
|
||||||
f"VALUES ({d[0]}, {d[1]}, {d[2]},{d[3]}, {d[4]}, "
|
|
||||||
f"{d[5]}, {d[6]}, {d[7]}, {d[8]}, {self.id})"
|
|
||||||
)
|
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
@@ -178,8 +464,6 @@ class Pollutants(SQLSubModel):
|
|||||||
return len(self._data) != 0
|
return len(self._data) != 0
|
||||||
|
|
||||||
def new_from_data(self, data):
|
def new_from_data(self, data):
|
||||||
|
|
||||||
print("from_data before : ", data)
|
|
||||||
try:
|
try:
|
||||||
new = [int(data[0])]
|
new = [int(data[0])]
|
||||||
new += [float(d) for d in data[1:]]
|
new += [float(d) for d in data[1:]]
|
||||||
@@ -187,8 +471,6 @@ class Pollutants(SQLSubModel):
|
|||||||
logger.error(e)
|
logger.error(e)
|
||||||
new = None
|
new = None
|
||||||
|
|
||||||
print("from_data after : ", new)
|
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# PollutantsList.py -- Pamhyr
|
# PollutantsList.py -- Pamhyr
|
||||||
# Copyright (C) 2024 INRAE
|
# Copyright (C) 2024-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -38,7 +38,10 @@ class PollutantsList(PamhyrModelList):
|
|||||||
ok = True
|
ok = True
|
||||||
|
|
||||||
# Delete previous data
|
# Delete previous data
|
||||||
execute("DELETE FROM Pollutants")
|
execute(
|
||||||
|
"DELETE FROM Pollutants " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
for sl in self._lst:
|
for sl in self._lst:
|
||||||
ok &= sl._db_save(execute, data)
|
ok &= sl._db_save(execute, data)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# REPLine.py -- Pamhyr
|
# REPLine.py -- Pamhyr
|
||||||
# Copyright (C) 2024 INRAE
|
# Copyright (C) 2024-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,31 +22,25 @@ from tools import trace, timer
|
|||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
|
|
||||||
class REPLine(SQLSubModel):
|
class REPLine(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, enabled=True,
|
def __init__(self, id: int = -1, enabled=True,
|
||||||
name="", line="", solvers=set(),
|
name="", line="", solvers=set(),
|
||||||
status=None):
|
status=None, owner_scenario=-1):
|
||||||
super(REPLine, self).__init__()
|
super(REPLine, self).__init__(
|
||||||
|
id, status=status,
|
||||||
if id == -1:
|
owner_scenario=owner_scenario
|
||||||
self.id = REPLine._id_cnt
|
)
|
||||||
else:
|
|
||||||
self.id = id
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._enabled = enabled
|
self._enabled = enabled
|
||||||
self._name = f"Line{self.id}" if name == "" else name
|
self._name = f"Line #{self._pamhyr_id}" if name == "" else name
|
||||||
self._line = line
|
self._line = line
|
||||||
self._solvers = solvers
|
self._solvers = solvers
|
||||||
|
|
||||||
REPLine._id_cnt = max(id, REPLine._id_cnt+1)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
value = None
|
value = None
|
||||||
|
|
||||||
@@ -113,35 +107,75 @@ class REPLine(SQLSubModel):
|
|||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE rep_lines(
|
CREATE TABLE rep_lines{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
enabled BOOLEAN NOT NULL,
|
enabled BOOLEAN NOT NULL,
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
line TEXT NOT NULL,
|
line TEXT NOT NULL,
|
||||||
solvers TEXT NOT NULL
|
solvers TEXT NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 9:
|
if int(release) < 9:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
cls._db_update_to_0_0_14(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE rep_lines " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_0_14(cls, execute, data):
|
||||||
|
table = "rep_lines"
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, enabled, name, line, solvers, scenario) " +
|
||||||
|
"SELECT pamhyr_id, enabled, name, line, solvers, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, enabled, name, line, solvers " +
|
"SELECT pamhyr_id, enabled, deleted, name, line, " +
|
||||||
"FROM rep_lines"
|
"solvers, scenario " +
|
||||||
|
"FROM rep_lines " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
@@ -149,32 +183,47 @@ class REPLine(SQLSubModel):
|
|||||||
|
|
||||||
id = next(it)
|
id = next(it)
|
||||||
enabled = (next(it) == 1)
|
enabled = (next(it) == 1)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
name = next(it)
|
name = next(it)
|
||||||
line = next(it)
|
line = next(it)
|
||||||
solvers = set(next(it).split(";;"))
|
solvers = set(next(it).split(";;"))
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
f = cls(
|
f = cls(
|
||||||
id=id, enabled=enabled, name=name, line=line,
|
id=id, enabled=enabled,
|
||||||
solvers=solvers, status=data['status']
|
name=name, line=line, solvers=solvers,
|
||||||
|
status=data['status'], owner_scenario=owner_scenario
|
||||||
)
|
)
|
||||||
|
if deleted:
|
||||||
|
f.set_as_deleted()
|
||||||
|
|
||||||
|
loaded.add(id)
|
||||||
new.append(f)
|
new.append(f)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
solvers = ";;".join(self._solvers)
|
solvers = ";;".join(self._solvers)
|
||||||
|
|
||||||
sql = (
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"rep_lines(id, enabled, name, line, solvers) " +
|
"rep_lines(pamhyr_id, enabled, deleted, " +
|
||||||
|
"name, line, solvers, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {self._enabled}, " +
|
f"{self._pamhyr_id}, {self._enabled}, " +
|
||||||
|
f"{self._db_format(self.is_deleted())}, " +
|
||||||
f"'{self._db_format(self._name)}', " +
|
f"'{self._db_format(self._name)}', " +
|
||||||
f"'{self._db_format(self._line)}', " +
|
f"'{self._db_format(self._line)}', " +
|
||||||
f"'{self._db_format(solvers)}'" +
|
f"'{self._db_format(solvers)}', " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# REPLineList.py -- Pamhyr
|
# REPLineList.py -- Pamhyr
|
||||||
# Copyright (C) 2024 INRAE
|
# Copyright (C) 2024-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.REPLine.REPLine import REPLine
|
from Model.REPLine.REPLine import REPLine
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,10 @@ class REPLineList(PamhyrModelList):
|
|||||||
ok = True
|
ok = True
|
||||||
|
|
||||||
# Delete previous data
|
# Delete previous data
|
||||||
execute("DELETE FROM rep_lines")
|
execute(
|
||||||
|
"DELETE FROM rep_lines " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
for af in self._lst:
|
for af in self._lst:
|
||||||
ok &= af._db_save(execute, data)
|
ok &= af._db_save(execute, data)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Reservoir.py -- Pamhyr
|
# Reservoir.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,148 +19,386 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Reservoir(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
|
||||||
|
|
||||||
def __init__(self, id: int = -1, name: str = "",
|
def __init__(self, id: int = -1,
|
||||||
status=None):
|
elevation: float = 0.,
|
||||||
super(Reservoir, self).__init__()
|
surface: float = 0.,
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
|
super(Data, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._status = status
|
self._data = [elevation, surface]
|
||||||
|
|
||||||
if id == -1:
|
@classmethod
|
||||||
self.id = Reservoir._id_cnt
|
def _db_create(cls, execute, ext=""):
|
||||||
else:
|
execute(f"""
|
||||||
self.id = id
|
CREATE TABLE reservoir_data{ext}(
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
ind INTEGER NOT NULL,
|
||||||
|
elevation REAL NOT NULL,
|
||||||
|
surface REAL NOT NULL,
|
||||||
|
reservoir INTEGER,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(reservoir) REFERENCES reservoir(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
if ext == "_tmp":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == minor == "0":
|
||||||
|
if int(release) > 5:
|
||||||
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and int(minor) <= 1:
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE reservoir_data " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "reservoir_data"
|
||||||
|
id2pid = data['id2pid']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(
|
||||||
|
execute, table,
|
||||||
|
data=data
|
||||||
|
)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, ind, elevation, surface, reservoir, scenario) " +
|
||||||
|
"SELECT pamhyr_id, ind, elevation, surface, reservoir, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
|
if 'reservoir' in id2pid:
|
||||||
|
reservoirs = id2pid['reservoir']
|
||||||
|
cls._db_update_to_0_2_0_set_reservoir_pid(
|
||||||
|
execute, table, reservoirs
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0_set_reservoir_pid(cls, execute, table, reservoirs):
|
||||||
|
bcs = execute(
|
||||||
|
f"SELECT pamhyr_id, reservoir FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for row in bcs:
|
||||||
|
it = iter(row)
|
||||||
|
pid = next(it)
|
||||||
|
reservoir_id = next(it)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
f"UPDATE {table} " +
|
||||||
|
f"SET reservoir = {reservoirs[reservoir_id]} " +
|
||||||
|
f"WHERE pamhyr_id = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
scenario = data["scenario"]
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
reseroire = data["reservoir"]
|
||||||
|
|
||||||
|
values = execute(
|
||||||
|
"SELECT pamhyr_id, deleted, ind, " +
|
||||||
|
"elevation, surface, scenario " +
|
||||||
|
"FROM reservoir_data " +
|
||||||
|
f"WHERE reservoir = {reseroire.pamhyr_id} " +
|
||||||
|
f"AND scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
|
||||||
|
"ORDER BY ind ASC"
|
||||||
|
)
|
||||||
|
|
||||||
|
for v in values:
|
||||||
|
it = iter(v)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
deleted = (next(it) == 1)
|
||||||
|
ind = next(it)
|
||||||
|
elevation = next(it)
|
||||||
|
surface = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
nd = cls(
|
||||||
|
id=pid, status=data['status'],
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
nd.set_as_deleted()
|
||||||
|
|
||||||
|
nd._data = [elevation, surface]
|
||||||
|
|
||||||
|
loaded.add(pid)
|
||||||
|
new.append(nd)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
|
pid = self._pamhyr_id
|
||||||
|
ind = data["ind"]
|
||||||
|
elevation = self._db_format(str(self[0]))
|
||||||
|
surface = self._db_format(str(self[1]))
|
||||||
|
reservoir = data["reservoir"]
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO reservoir_data " +
|
||||||
|
"(pamhyr_id, deleted, ind, " +
|
||||||
|
"elevation, surface, reservoir, scenario) " +
|
||||||
|
"VALUES (" +
|
||||||
|
f"{pid}, " +
|
||||||
|
f"{self._db_format(self.is_deleted())}, " +
|
||||||
|
f"{ind}, '{elevation}', {surface}, " +
|
||||||
|
f"{reservoir._pamhyr_id}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._data[key]
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
self._data[key] = float(value)
|
||||||
|
|
||||||
|
|
||||||
|
class Reservoir(SQLSubModel):
|
||||||
|
_sub_classes = [Data]
|
||||||
|
|
||||||
|
def __init__(self, id: int = -1,
|
||||||
|
name: str = "",
|
||||||
|
status=None, owner_scenario=-1):
|
||||||
|
super(Reservoir, self).__init__(
|
||||||
|
id=id, status=status,
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._node = None
|
self._node = None
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
Reservoir._id_cnt = max(Reservoir._id_cnt + 1, self.id)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_create(cls, execute):
|
def _db_create(cls, execute, ext=""):
|
||||||
execute("""
|
execute(f"""
|
||||||
CREATE TABLE reservoir(
|
CREATE TABLE reservoir{ext} (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
node INTEGER,
|
node INTEGER,
|
||||||
FOREIGN KEY(node) REFERENCES river_node(id)
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(node) REFERENCES river_node(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
execute("""
|
if ext == "_tmp":
|
||||||
CREATE TABLE reservoir_data(
|
return True
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
|
||||||
ind INTEGER NOT NULL,
|
|
||||||
elevation REAL NOT NULL,
|
|
||||||
surface REAL NOT NULL,
|
|
||||||
reservoir INTEGER,
|
|
||||||
FOREIGN KEY(reservoir) REFERENCES reservoir(id)
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_update(cls, execute, version):
|
def _db_update(cls, execute, version, data=None):
|
||||||
major, minor, release = version.strip().split(".")
|
major, minor, release = version.strip().split(".")
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 5:
|
if int(release) < 5:
|
||||||
cls._db_create(execute)
|
cls._db_create(execute)
|
||||||
|
return True
|
||||||
|
|
||||||
return True
|
cls._db_update_to_0_2_0(execute, data)
|
||||||
|
|
||||||
|
if major == "0" and minor == "1":
|
||||||
|
if int(release) < 2:
|
||||||
|
execute(
|
||||||
|
"ALTER TABLE additional_files " +
|
||||||
|
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update_to_0_2_0(cls, execute, data):
|
||||||
|
table = "reservoir"
|
||||||
|
nodes = data['id2pid']['river_node']
|
||||||
|
|
||||||
|
cls.update_db_add_pamhyr_id(execute, table, data=data)
|
||||||
|
cls._db_update_to_0_2_0_set_node_pid(execute, table, nodes)
|
||||||
|
Scenario.update_db_add_scenario(execute, table)
|
||||||
|
|
||||||
|
print(execute(f"SELECT * FROM {table}"))
|
||||||
|
|
||||||
|
cls._db_create(execute, ext="_tmp")
|
||||||
|
execute(
|
||||||
|
f"INSERT INTO {table}_tmp " +
|
||||||
|
"(pamhyr_id, name, node, scenario) " +
|
||||||
|
"SELECT pamhyr_id, name, node, scenario " +
|
||||||
|
f"FROM {table}"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute(f"DROP TABLE {table}")
|
||||||
|
execute(f"ALTER TABLE {table}_tmp RENAME TO {table}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _db_load(cls, execute, data=None):
|
def _db_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
|
||||||
|
if scenario is None:
|
||||||
|
return new
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, name, node " +
|
"SELECT pamhyr_id, deleted, name, node, scenario " +
|
||||||
"FROM reservoir "
|
"FROM reservoir " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
|
||||||
)
|
)
|
||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
id = row[0]
|
it = iter(row)
|
||||||
name = row[1]
|
|
||||||
node_id = row[2]
|
id = next(it)
|
||||||
new_reservoir = cls(id, name, status=data["status"])
|
deleted = (next(it) == 1)
|
||||||
|
name = next(it)
|
||||||
|
node_id = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
new_reservoir = cls(
|
||||||
|
id, name,
|
||||||
|
status=data["status"],
|
||||||
|
owner_scenario=owner_scenario
|
||||||
|
)
|
||||||
|
if deleted:
|
||||||
|
new_reservoir.set_as_deleted()
|
||||||
|
|
||||||
new_reservoir._node = None
|
new_reservoir._node = None
|
||||||
if node_id != -1:
|
if node_id != -1 and node_id is not None:
|
||||||
new_reservoir._node = next(
|
new_reservoir._node = next(
|
||||||
filter(
|
filter(
|
||||||
lambda n: n.id == node_id, data["nodes"]
|
lambda n: n.id == node_id, data["nodes"]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
new_data = []
|
data["reservoir"] = new_reservoir
|
||||||
table = execute(
|
new_reservoir._data = Data._db_load(
|
||||||
"SELECT elevation, surface " +
|
execute, data=data
|
||||||
"FROM reservoir_data " +
|
|
||||||
f"WHERE reservoir = {id} " +
|
|
||||||
"ORDER BY ind ASC"
|
|
||||||
)
|
)
|
||||||
for t in table:
|
|
||||||
new_data.append((t[0], t[1]))
|
|
||||||
|
|
||||||
new_reservoir._data = new_data
|
|
||||||
|
|
||||||
|
loaded.add(id)
|
||||||
new.append(new_reservoir)
|
new.append(new_reservoir)
|
||||||
|
|
||||||
|
data["scenario"] = scenario.parent
|
||||||
|
new += cls._db_load(execute, data)
|
||||||
|
data["scenario"] = scenario
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
|
if not self.must_be_saved():
|
||||||
|
return True
|
||||||
|
|
||||||
execute(f"DELETE FROM reservoir WHERE id = {self.id}")
|
execute(
|
||||||
execute(f"DELETE FROM reservoir_data WHERE reservoir = {self.id}")
|
"DELETE FROM reservoir " +
|
||||||
|
f"WHERE pamhyr_id = {self.pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM reservoir_data " +
|
||||||
|
f"WHERE reservoir = {self.pamhyr_id} " +
|
||||||
|
f"AND scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
node_id = -1
|
node_id = 'NULL'
|
||||||
if self._node is not None:
|
if self._node is not None:
|
||||||
node_id = self._node.id
|
node_id = self._node.pamhyr_id
|
||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"reservoir(id, name, node) " +
|
"reservoir(pamhyr_id, deleted, name, node, scenario) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._db_format(self._name)}', " +
|
f"{self.pamhyr_id}, " +
|
||||||
f"{node_id}" +
|
f"{self._db_format(self.is_deleted())}, " +
|
||||||
|
f"'{self._db_format(self._name)}', " +
|
||||||
|
f"{node_id}, " +
|
||||||
|
f"{self._status.scenario_id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
|
|
||||||
|
data["reservoir"] = self
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for d in self._data:
|
for d in self._data:
|
||||||
sql = (
|
data["ind"] = ind
|
||||||
"INSERT INTO " +
|
|
||||||
"reservoir_data(ind, elevation, surface, reservoir) " +
|
d._db_save(execute, data)
|
||||||
f"VALUES ({ind}, '{d[0]}', {d[1]}, {self.id})"
|
|
||||||
)
|
|
||||||
execute(sql)
|
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _data_traversal(self,
|
||||||
|
predicate=lambda obj, data: True,
|
||||||
|
modifier=lambda obj, data: None,
|
||||||
|
data={}):
|
||||||
|
if predicate(self, data):
|
||||||
|
modifier(self, data)
|
||||||
|
|
||||||
|
for d in self._data:
|
||||||
|
d._data_traversal(predicate, modifier, data)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self._data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._name == "":
|
if self._name == "":
|
||||||
return f"R{self.id + 1}"
|
return f"Reservoir #{self.pamhyr_id}"
|
||||||
|
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@name.setter
|
@name.setter
|
||||||
def name(self, name):
|
def name(self, name):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def node(self):
|
def node(self):
|
||||||
@@ -169,7 +407,7 @@ class Reservoir(SQLSubModel):
|
|||||||
@node.setter
|
@node.setter
|
||||||
def node(self, node):
|
def node(self, node):
|
||||||
self._node = node
|
self._node = node
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def has_node(self):
|
def has_node(self):
|
||||||
return self._node is not None
|
return self._node is not None
|
||||||
@@ -202,42 +440,63 @@ class Reservoir(SQLSubModel):
|
|||||||
return (new_0, new_1)
|
return (new_0, new_1)
|
||||||
|
|
||||||
def add(self, index: int):
|
def add(self, index: int):
|
||||||
value = (self._default_elevation, self._default_surface)
|
data = Data(
|
||||||
self._data.insert(index, value)
|
elevation=self._default_elevation,
|
||||||
self._status.modified()
|
surface=self._default_surface,
|
||||||
return value
|
status=self._status,
|
||||||
|
)
|
||||||
|
|
||||||
|
self._data.insert(index, data)
|
||||||
|
self.modified()
|
||||||
|
return data
|
||||||
|
|
||||||
def insert(self, index: int, value):
|
def insert(self, index: int, value):
|
||||||
self._data.insert(index, value)
|
if type(value) is tuple or type(value) is list:
|
||||||
self._status.modified()
|
value = Data(
|
||||||
|
elevation=value[0],
|
||||||
|
surface=value[1]
|
||||||
|
)
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
self._data.insert(index, value)
|
||||||
|
self.modified()
|
||||||
|
|
||||||
|
def hard_delete_i(self, indexes):
|
||||||
self._data = list(
|
self._data = list(
|
||||||
map(
|
map(
|
||||||
lambda e: e[1],
|
lambda e: e[1],
|
||||||
filter(
|
filter(
|
||||||
lambda e: e[0] not in indexes,
|
lambda e: e[0] not in indexes,
|
||||||
enumerate(self.data)
|
enumerate(self._data)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def delete(self, els):
|
def delete_i(self, indexes):
|
||||||
self._data = list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda e: e not in els,
|
lambda e: e[1].set_as_deleted(),
|
||||||
self.data
|
filter(
|
||||||
|
lambda e: e[0] in indexes,
|
||||||
|
enumerate(self.lst)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
|
def delete(self, els):
|
||||||
|
for el in els:
|
||||||
|
el.set_as_deleted()
|
||||||
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def sort(self, _reverse=False, key=None):
|
def sort(self, _reverse=False, key=None):
|
||||||
if key is None:
|
if key is None:
|
||||||
self._data.sort(reverse=_reverse)
|
self._data.sort(reverse=_reverse, key=lambda d: d[0])
|
||||||
else:
|
else:
|
||||||
self._data.sort(reverse=_reverse, key=key)
|
self._data.sort(reverse=_reverse, key=key)
|
||||||
self._status.modified()
|
|
||||||
|
self.modified()
|
||||||
|
|
||||||
def get_i(self, index):
|
def get_i(self, index):
|
||||||
return self.data[index]
|
return self.data[index]
|
||||||
@@ -246,13 +505,12 @@ class Reservoir(SQLSubModel):
|
|||||||
lst = []
|
lst = []
|
||||||
for r in _range:
|
for r in _range:
|
||||||
lst.append(r)
|
lst.append(r)
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
def _set_i_c_v(self, index, column, value):
|
def _set_i_c_v(self, index, column, value):
|
||||||
v = list(self._data[index])
|
self._data[index][column] = value
|
||||||
v[column] = value
|
self.modified()
|
||||||
self._data[index] = tuple(v)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def set_i_elevation(self, index: int, value):
|
def set_i_elevation(self, index: int, value):
|
||||||
self._set_i_c_v(index, 0, value)
|
self._set_i_c_v(index, 0, value)
|
||||||
@@ -265,11 +523,11 @@ class Reservoir(SQLSubModel):
|
|||||||
next = index - 1
|
next = index - 1
|
||||||
d = self._data
|
d = self._data
|
||||||
d[index], d[next] = d[next], d[index]
|
d[index], d[next] = d[next], d[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
|
|
||||||
def move_down(self, index):
|
def move_down(self, index):
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
d = self._data
|
d = self._data
|
||||||
d[index], d[prev] = d[prev], d[index]
|
d[index], d[prev] = d[prev], d[index]
|
||||||
self._status.modified()
|
self.modified()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# ReservoirList.py -- Pamhyr
|
# ReservoirList.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.Tools.PamhyrList import PamhyrModelList
|
from Model.Tools.PamhyrListExt import PamhyrModelList
|
||||||
from Model.Reservoir.Reservoir import Reservoir
|
from Model.Reservoir.Reservoir import Reservoir
|
||||||
|
|
||||||
|
|
||||||
@@ -39,8 +39,14 @@ class ReservoirList(PamhyrModelList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def _db_save(self, execute, data=None):
|
def _db_save(self, execute, data=None):
|
||||||
execute("DELETE FROM reservoir")
|
execute(
|
||||||
execute("DELETE FROM reservoir_data")
|
"DELETE FROM reservoir " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM reservoir_data " +
|
||||||
|
f"WHERE scenario = {self._status.scenario_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Results.py -- Pamhyr
|
# Results.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -14,32 +14,174 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import struct
|
||||||
import logging
|
import logging
|
||||||
|
import itertools
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Results.River.River import River
|
from Model.Results.River.River import River
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Results(object):
|
class AdditionalData(SQLSubModel):
|
||||||
def __init__(self, study=None, solver=None,
|
_sub_classes = []
|
||||||
repertory="", name="0"):
|
|
||||||
|
def __init__(self, id=-1, study=None, data=None):
|
||||||
|
super(AdditionalData, self).__init__(
|
||||||
|
id=id, status=study.status,
|
||||||
|
owner_scenario=study.status.scenario.id
|
||||||
|
)
|
||||||
|
|
||||||
self._study = study
|
self._study = study
|
||||||
|
self._data = data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE results_add_data{ext} (
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
result INTEGER NOT NULL,
|
||||||
|
type_x TEXT NOT NULL,
|
||||||
|
type_y TEXT NOT NULL,
|
||||||
|
legend TEXT NOT NULL,
|
||||||
|
unit TEXT NOT NULL,
|
||||||
|
data_len INTEGER NOT NULL,
|
||||||
|
x BLOB NOT NULL,
|
||||||
|
y BLOB NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(result) REFERENCES results(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, result, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
if ext != "":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
if major == "0" and int(minor) == 2 and int(release) <= 1:
|
||||||
|
cls._db_create(execute)
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = []
|
||||||
|
|
||||||
|
study = data['study']
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, type_x, type_y, " +
|
||||||
|
"legend, unit, data_len, x, y, " +
|
||||||
|
"scenario " +
|
||||||
|
"FROM results_add_data " +
|
||||||
|
f"WHERE scenario = {scenario.id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is None:
|
||||||
|
return new
|
||||||
|
|
||||||
|
for v in table:
|
||||||
|
it = iter(v)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
type_x = next(it)
|
||||||
|
type_y = next(it)
|
||||||
|
legend = next(it)
|
||||||
|
unit = next(it)
|
||||||
|
data_len = next(it)
|
||||||
|
bx = next(it)
|
||||||
|
by = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
data_format = ">" + ''.join(itertools.repeat("d", data_len))
|
||||||
|
x = struct.unpack(data_format, bx)
|
||||||
|
y = struct.unpack(data_format, by)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'type_x': type_x,
|
||||||
|
'type_y': type_y,
|
||||||
|
'legend': legend,
|
||||||
|
'unit': unit,
|
||||||
|
'x': x, 'y': y
|
||||||
|
}
|
||||||
|
|
||||||
|
new_data = cls(study=study)
|
||||||
|
new_data._data = data
|
||||||
|
new.append(new_data)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if self._status.scenario.id != self._owner_scenario:
|
||||||
|
return
|
||||||
|
|
||||||
|
pid = self._pamhyr_id
|
||||||
|
data_len = len(self._data["x"])
|
||||||
|
|
||||||
|
data_format = ">" + ''.join(itertools.repeat("d", data_len))
|
||||||
|
bx = struct.pack(data_format, *self._data["x"])
|
||||||
|
by = struct.pack(data_format, *self._data["y"])
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"results_add_data (pamhyr_id, result, " +
|
||||||
|
"type_x, type_y, " +
|
||||||
|
"legend, unit, data_len, x, y, " +
|
||||||
|
"scenario) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
self._pamhyr_id, data["result"],
|
||||||
|
self._data["type_x"], self._data["type_y"],
|
||||||
|
self._data["legend"], self._data["unit"],
|
||||||
|
data_len, bx, by, self._owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class Results(SQLSubModel):
|
||||||
|
_sub_classes = [River, AdditionalData]
|
||||||
|
|
||||||
|
def __init__(self, id=-1, study=None, solver=None,
|
||||||
|
repertory="", name="0"):
|
||||||
|
super(Results, self).__init__(
|
||||||
|
id=id, status=study.status,
|
||||||
|
owner_scenario=study.status.scenario.id
|
||||||
|
)
|
||||||
|
|
||||||
|
self._name = name
|
||||||
|
self._study = study
|
||||||
|
self._river = River(self._study)
|
||||||
|
|
||||||
self._solver = solver
|
self._solver = solver
|
||||||
self._repertory = repertory
|
self._repertory = repertory
|
||||||
self._name = name
|
|
||||||
|
|
||||||
self._river = River(self._study)
|
|
||||||
|
|
||||||
self._meta_data = {
|
self._meta_data = {
|
||||||
# Keep results creation date
|
# Keep results creation date
|
||||||
"creation_date": datetime.now(),
|
"creation_date": datetime.now(),
|
||||||
|
"study_revision": study.status.version,
|
||||||
|
"additional_data": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if solver is not None:
|
||||||
|
self.set("solver_type", solver._type)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self):
|
def date(self):
|
||||||
date = self._meta_data["creation_date"]
|
date = self._meta_data["creation_date"]
|
||||||
@@ -56,6 +198,17 @@ class Results(object):
|
|||||||
def set(self, key, value):
|
def set(self, key, value):
|
||||||
self._meta_data[key] = value
|
self._meta_data[key] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self):
|
||||||
|
return ("timestamps" in self._meta_data)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def solver_name(self):
|
||||||
|
if self._solver is None:
|
||||||
|
return self._meta_data["solver_name"]
|
||||||
|
|
||||||
|
return self._solver.name
|
||||||
|
|
||||||
def get(self, key):
|
def get(self, key):
|
||||||
return self._meta_data[key]
|
return self._meta_data[key]
|
||||||
|
|
||||||
@@ -65,3 +218,164 @@ class Results(object):
|
|||||||
self._repertory,
|
self._repertory,
|
||||||
qlog=None,
|
qlog=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def timestamps_to_struct(self):
|
||||||
|
ts = self._meta_data["timestamps"]
|
||||||
|
sf = ">" + ''.join(itertools.repeat("d", len(ts)))
|
||||||
|
|
||||||
|
return struct.pack(sf, ts)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE results{ext} (
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
solver_name TEXT NOT NULL,
|
||||||
|
solver_type TEXT NOT NULL,
|
||||||
|
study_revision INTEGER NOT NULL,
|
||||||
|
creation_data DATE NOT NULL,
|
||||||
|
nb_timestamps INTEGER NOT NULL,
|
||||||
|
timestamps BLOB NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
PRIMARY KEY(pamhyr_id, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
if ext != "":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
create = False
|
||||||
|
|
||||||
|
if major == "0" and int(minor) < 2:
|
||||||
|
cls._db_create(execute)
|
||||||
|
create = True
|
||||||
|
|
||||||
|
if major == "0" and int(minor) == 2:
|
||||||
|
if int(release) < 1 and not create:
|
||||||
|
cls._db_create(execute)
|
||||||
|
create = True
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = None
|
||||||
|
|
||||||
|
study = data['study']
|
||||||
|
status = data['status']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
|
||||||
|
table = execute(
|
||||||
|
"SELECT pamhyr_id, solver_name, solver_type, " +
|
||||||
|
"study_revision, creation_data, nb_timestamps, timestamps, " +
|
||||||
|
"scenario " +
|
||||||
|
"FROM results " +
|
||||||
|
f"WHERE scenario = {scenario.id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if table is None:
|
||||||
|
yield
|
||||||
|
|
||||||
|
if len(table) > 1:
|
||||||
|
logger.warning("Multiple results for this scenario")
|
||||||
|
|
||||||
|
for v in table:
|
||||||
|
it = iter(v)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
solver_name = next(it)
|
||||||
|
solver_type = next(it)
|
||||||
|
revision = next(it)
|
||||||
|
creation_date = next(it)
|
||||||
|
nb_timestamps = next(it)
|
||||||
|
timestamps_bytes = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
new_results = cls(study=study)
|
||||||
|
|
||||||
|
new_results.set("solver_name", solver_name)
|
||||||
|
new_results.set("solver_type", solver_type)
|
||||||
|
new_results.set("study_revision", revision)
|
||||||
|
new_results.set("creation_date", creation_date)
|
||||||
|
|
||||||
|
sf = ">" + ''.join(itertools.repeat("d", nb_timestamps))
|
||||||
|
ts = struct.unpack(sf, timestamps_bytes)
|
||||||
|
new_results.set("timestamps", ts)
|
||||||
|
|
||||||
|
data["timestamps"] = sorted(ts)
|
||||||
|
new_results._river = River._db_load(execute, data)
|
||||||
|
|
||||||
|
new_results.set(
|
||||||
|
"additional_data",
|
||||||
|
AdditionalData._db_load(execute, data)
|
||||||
|
)
|
||||||
|
|
||||||
|
yield (solver_type, new_results)
|
||||||
|
|
||||||
|
def _db_save_clear(self, execute, solver_type, data=None):
|
||||||
|
old_pid = execute(
|
||||||
|
"SELECT pamhyr_id FROM results " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND solver_type = '{solver_type}'"
|
||||||
|
)
|
||||||
|
if len(old_pid) != 0:
|
||||||
|
for pid in old_pid:
|
||||||
|
pid = pid[0]
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"DELETE FROM results " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND solver_type = '{solver_type}'"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM results_data " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND result = {pid}"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"DELETE FROM results_add_data " +
|
||||||
|
f"WHERE scenario = {self._owner_scenario} " +
|
||||||
|
f"AND result = {pid}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
if self._status.scenario.id != self._owner_scenario:
|
||||||
|
return
|
||||||
|
|
||||||
|
pid = self._pamhyr_id
|
||||||
|
if self._solver is None:
|
||||||
|
solver_name = self.get("solver_name")
|
||||||
|
solver_type = self.get("solver_type")
|
||||||
|
else:
|
||||||
|
solver_name = self._solver._name
|
||||||
|
solver_type = self._solver._type
|
||||||
|
|
||||||
|
self._db_save_clear(execute, solver_type, data=data)
|
||||||
|
|
||||||
|
ts = sorted(self.get("timestamps"))
|
||||||
|
sf = ">" + ''.join(itertools.repeat("d", len(ts)))
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"results (pamhyr_id, solver_name, solver_type, " +
|
||||||
|
"study_revision, creation_data, " +
|
||||||
|
"nb_timestamps, timestamps, " +
|
||||||
|
"scenario) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
self._pamhyr_id, solver_name, solver_type,
|
||||||
|
self._status.version, self.get("creation_date"),
|
||||||
|
len(ts), struct.pack(sf, *ts), self._owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
data["result"] = self._pamhyr_id
|
||||||
|
self._river._db_save(execute, data)
|
||||||
|
|
||||||
|
for add_data in self.get("additional_data"):
|
||||||
|
add_data._db_save(execute, data)
|
||||||
|
|
||||||
|
return True
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Results.py -- Pamhyr
|
# Results.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import os
|
import os
|
||||||
import glob
|
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -41,17 +40,19 @@ class Results(object):
|
|||||||
# Keep results creation date
|
# Keep results creation date
|
||||||
"creation_date": datetime.now(),
|
"creation_date": datetime.now(),
|
||||||
}
|
}
|
||||||
repertory_results = os.path.join(repertory, "resultats")
|
filelist = [f for f in os.listdir(self._repertory)
|
||||||
self._pollutants_list = [
|
if os.path.isfile(os.path.join(self._repertory, f))
|
||||||
el.split("/")[-1][0:-4]
|
]
|
||||||
for el in glob.glob(repertory_results + "/*.bin")
|
self._pollutants_list = [f[0:-4] for f in filelist if f[-4:] == ".bin"]
|
||||||
]
|
|
||||||
self._pollutants_list.insert(0, self._pollutants_list.pop(
|
self._pollutants_list.insert(0, self._pollutants_list.pop(
|
||||||
self._pollutants_list.index("total_sediment"))
|
self._pollutants_list.index("total_sediment"))
|
||||||
)
|
)
|
||||||
|
|
||||||
self._phys_var_list = ["C", "G", "M", "D", "L", "N", "R"]
|
self._phys_var_list = ["C", "G", "M", "D", "L", "N", "R"]
|
||||||
|
|
||||||
|
if solver is not None:
|
||||||
|
self.set("solver_type", solver._type)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self):
|
def date(self):
|
||||||
date = self._meta_data["creation_date"]
|
date = self._meta_data["creation_date"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# River.py -- Pamhyr
|
# River.py -- Pamhyr
|
||||||
# Copyright (C) 2023-2024 INRAE
|
# Copyright (C) 2023-2025 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -14,15 +14,27 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import struct
|
||||||
import logging
|
import logging
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
from tools import flatten
|
||||||
|
from functools import reduce
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from Model.Scenario import Scenario
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Profile(object):
|
class Profile(SQLSubModel):
|
||||||
def __init__(self, profile, study):
|
def __init__(self, profile, study):
|
||||||
|
super(Profile, self).__init__(
|
||||||
|
id=-1, status=study.status,
|
||||||
|
owner_scenario=study.status.scenario.id
|
||||||
|
)
|
||||||
|
|
||||||
self._study = study
|
self._study = study
|
||||||
self._profile = profile # Source profile in the study
|
self._profile = profile # Source profile in the study
|
||||||
self._data = {} # Dict of dict {<ts>: {<key>: <value>, ...}, ...}
|
self._data = {} # Dict of dict {<ts>: {<key>: <value>, ...}, ...}
|
||||||
@@ -52,25 +64,215 @@ class Profile(object):
|
|||||||
return self._data[timestamp]
|
return self._data[timestamp]
|
||||||
|
|
||||||
def get_key(self, key):
|
def get_key(self, key):
|
||||||
return list(
|
res = list(
|
||||||
map(lambda ts: self._data[ts][key], self._data)
|
map(lambda ts: self._data[ts][key],
|
||||||
|
sorted(self._data.keys()))
|
||||||
)
|
)
|
||||||
|
return res
|
||||||
|
|
||||||
def get_ts_key(self, timestamp, key):
|
def get_ts_key(self, timestamp, key):
|
||||||
return self._data[timestamp][key]
|
if timestamp in self._data:
|
||||||
|
if key in self._data[timestamp]:
|
||||||
|
return self._data[timestamp][key]
|
||||||
|
return None
|
||||||
|
|
||||||
def has_sediment(self):
|
def has_sediment(self):
|
||||||
return any(map(lambda ts: "sl" in self._data[ts], self._data))
|
return any(map(lambda ts: "sl" in self._data[ts], self._data))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
execute(f"""
|
||||||
|
CREATE TABLE results_data{ext}(
|
||||||
|
{cls.create_db_add_pamhyr_id()},
|
||||||
|
result INTEGER NOT NULL,
|
||||||
|
key TEXT NOT NULL,
|
||||||
|
reach INTEGER NOT NULL,
|
||||||
|
section INTEGER NOT NULL,
|
||||||
|
len_data INTEGER NOT NULL,
|
||||||
|
data BLOB NOT NULL,
|
||||||
|
{Scenario.create_db_add_scenario()},
|
||||||
|
{Scenario.create_db_add_scenario_fk()},
|
||||||
|
FOREIGN KEY(result) REFERENCES results(pamhyr_id),
|
||||||
|
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
|
||||||
|
FOREIGN KEY(section)
|
||||||
|
REFERENCES geometry_profileXYZ(pamhyr_id),
|
||||||
|
PRIMARY KEY(pamhyr_id, result, key, scenario)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
major, minor, release = version.strip().split(".")
|
||||||
|
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
new = {}
|
||||||
|
status = data['status']
|
||||||
|
|
||||||
|
study = data['study']
|
||||||
|
reach = data['reach']
|
||||||
|
profile = data['profile']
|
||||||
|
scenario = data["scenario"]
|
||||||
|
loaded = data['loaded_pid']
|
||||||
|
timestamps = data['timestamps']
|
||||||
|
|
||||||
|
values = execute(
|
||||||
|
"SELECT pamhyr_id, result, key, " +
|
||||||
|
"len_data, data, scenario " +
|
||||||
|
"FROM results_data " +
|
||||||
|
f"WHERE scenario = {scenario.id} " +
|
||||||
|
f"AND reach = {reach.pamhyr_id} " +
|
||||||
|
f"AND section = {profile.pamhyr_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for v in values:
|
||||||
|
it = iter(v)
|
||||||
|
|
||||||
|
pid = next(it)
|
||||||
|
result = next(it)
|
||||||
|
key = next(it)
|
||||||
|
len_data = next(it)
|
||||||
|
data = next(it)
|
||||||
|
owner_scenario = next(it)
|
||||||
|
|
||||||
|
if profile not in new:
|
||||||
|
new_data = cls(profile, study)
|
||||||
|
new[profile] = new_data
|
||||||
|
else:
|
||||||
|
new_data = new[profile]
|
||||||
|
|
||||||
|
if key in ["Z", "Q", "V"]:
|
||||||
|
sf = ">" + ''.join(itertools.repeat("f", len_data))
|
||||||
|
len_values = len(values)
|
||||||
|
values = struct.unpack(sf, data)
|
||||||
|
elif key in ["sl"]:
|
||||||
|
sf = ">" + ''.join(itertools.repeat("f", len_data))
|
||||||
|
values = struct.unpack(sf, data)
|
||||||
|
values = cls._db_load_data_sl_format(
|
||||||
|
values, len_data, timestamps
|
||||||
|
)
|
||||||
|
|
||||||
|
for timestamp, value in zip(timestamps, values):
|
||||||
|
new_data.set(timestamp, key, value)
|
||||||
|
if key == "Z":
|
||||||
|
new_data.update_water_limits(timestamp, value)
|
||||||
|
|
||||||
|
return list(new.values())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load_data_sl_format(cls, values, len_data, timestamps):
|
||||||
|
tuple_size = 3
|
||||||
|
|
||||||
|
# HACK: Transforme list of value to list of n-tuple
|
||||||
|
# sediment results: (h, d50, sigma)
|
||||||
|
tmp_values = [[]]
|
||||||
|
for value in values:
|
||||||
|
t = tmp_values[-1]
|
||||||
|
if len(t) < tuple_size:
|
||||||
|
t.append(value)
|
||||||
|
else:
|
||||||
|
tmp_values.append([value])
|
||||||
|
|
||||||
|
tmp_values = list(map(tuple, tmp_values))
|
||||||
|
|
||||||
|
# HACK: Transforme list of n-tuple to list of n-list
|
||||||
|
# of n-tuple, where n is the number of layer.
|
||||||
|
nb_layer = len_data / len(timestamps) / tuple_size
|
||||||
|
values = [[]]
|
||||||
|
for value in tmp_values:
|
||||||
|
t = values[-1]
|
||||||
|
if len(t) < nb_layer:
|
||||||
|
t.append(value)
|
||||||
|
else:
|
||||||
|
values.append([value])
|
||||||
|
|
||||||
|
return list(map(lambda x: [x], values))
|
||||||
|
|
||||||
|
def update_water_limits(self, timestamp, z):
|
||||||
|
limits = self.geometry.get_water_limits(z)
|
||||||
|
self.set(
|
||||||
|
timestamp, "water_limits", limits
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_keys(self):
|
||||||
|
return reduce(
|
||||||
|
lambda acc, ts: acc.union(self._data[ts].keys()),
|
||||||
|
self._data.keys(), set()
|
||||||
|
)
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
pid = self._pamhyr_id
|
||||||
|
result = data["result"]
|
||||||
|
|
||||||
|
keys = self.get_keys()
|
||||||
|
logger.debug(f"{keys}...")
|
||||||
|
for key in keys:
|
||||||
|
values = self.get_key(key)
|
||||||
|
|
||||||
|
if key in ["Z", "Q", "V"]:
|
||||||
|
values = list(map(float, values))
|
||||||
|
sf = ">" + ''.join(itertools.repeat("f", len(values)))
|
||||||
|
len_values = len(values)
|
||||||
|
elif key == "sl":
|
||||||
|
# HACK: Some dirty code to transforme list of list of
|
||||||
|
# tuple to list of values and ensure the values is
|
||||||
|
# float type...
|
||||||
|
values = flatten(
|
||||||
|
flatten(
|
||||||
|
map(lambda v: list(
|
||||||
|
map(lambda t: list(
|
||||||
|
map(float, t)), v[0])),
|
||||||
|
values)))
|
||||||
|
len_values = len(values)
|
||||||
|
sf = ">" + ''.join(itertools.repeat("f", len_values))
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
data_bytes = struct.pack(sf, *values)
|
||||||
|
|
||||||
|
execute(
|
||||||
|
"INSERT INTO " +
|
||||||
|
"results_data (pamhyr_id, result, " +
|
||||||
|
"reach, section, " +
|
||||||
|
"key, len_data, data, " +
|
||||||
|
"scenario) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
pid, result,
|
||||||
|
data["reach"].pamhyr_id,
|
||||||
|
self._profile.pamhyr_id,
|
||||||
|
key, len_values, data_bytes,
|
||||||
|
self._owner_scenario
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class Reach(SQLSubModel):
|
||||||
|
_sub_classes = [Profile]
|
||||||
|
|
||||||
|
def __init__(self, reach, study, with_init=True):
|
||||||
|
super(Reach, self).__init__(
|
||||||
|
id=-1, status=study.status,
|
||||||
|
owner_scenario=study.status.scenario.id
|
||||||
|
)
|
||||||
|
|
||||||
class Reach(object):
|
|
||||||
def __init__(self, reach, study):
|
|
||||||
self._study = study
|
self._study = study
|
||||||
self._reach = reach # Source reach in the study
|
self._reach = reach # Source reach in the study
|
||||||
self._profiles = list(
|
self._profiles = []
|
||||||
|
if with_init:
|
||||||
|
self._profiles = list(
|
||||||
|
map(
|
||||||
|
lambda p: Profile(p, self._study),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._profile_mask = list(
|
||||||
map(
|
map(
|
||||||
lambda p: Profile(p, self._study),
|
lambda p: p.name[0:8] != 'interpol', self._profiles
|
||||||
reach.profiles
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,6 +291,10 @@ class Reach(object):
|
|||||||
def profiles(self):
|
def profiles(self):
|
||||||
return self._profiles.copy()
|
return self._profiles.copy()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def profile_mask(self):
|
||||||
|
return self._profile_mask
|
||||||
|
|
||||||
def profile(self, id):
|
def profile(self, id):
|
||||||
return self._profiles[id]
|
return self._profiles[id]
|
||||||
|
|
||||||
@@ -98,9 +304,44 @@ class Reach(object):
|
|||||||
def has_sediment(self):
|
def has_sediment(self):
|
||||||
return any(map(lambda profile: profile.has_sediment(), self._profiles))
|
return any(map(lambda profile: profile.has_sediment(), self._profiles))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
reach = data["reach"]
|
||||||
|
|
||||||
|
new_reach = cls(
|
||||||
|
data["reach"], data["study"], with_init=False
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, profile in enumerate(reach.profiles):
|
||||||
|
data["profile"] = profile
|
||||||
|
new_reach._profiles += Profile._db_load(execute, data)
|
||||||
|
|
||||||
|
return new_reach
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
logger.debug("Save reach...")
|
||||||
|
for profile in self._profiles:
|
||||||
|
data["profile"] = profile.geometry.pamhyr_id
|
||||||
|
profile._db_save(execute, data)
|
||||||
|
|
||||||
|
|
||||||
|
class River(SQLSubModel):
|
||||||
|
_sub_classes = [Reach]
|
||||||
|
|
||||||
class River(object):
|
|
||||||
def __init__(self, study):
|
def __init__(self, study):
|
||||||
|
super(River, self).__init__(
|
||||||
|
id=-1, status=study.status,
|
||||||
|
owner_scenario=study.status.scenario.id
|
||||||
|
)
|
||||||
|
|
||||||
self._study = study
|
self._study = study
|
||||||
|
|
||||||
# Dict with timestamps as key
|
# Dict with timestamps as key
|
||||||
@@ -134,3 +375,30 @@ class River(object):
|
|||||||
self._reachs
|
self._reachs
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_create(cls, execute, ext=""):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_update(cls, execute, version, data=None):
|
||||||
|
return cls._update_submodel(execute, version, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _db_load(cls, execute, data=None):
|
||||||
|
study = data["study"]
|
||||||
|
new_river = cls(study)
|
||||||
|
|
||||||
|
for reach in study.river.reachs():
|
||||||
|
data["reach"] = reach.reach
|
||||||
|
new_river._reachs.append(
|
||||||
|
Reach._db_load(execute, data)
|
||||||
|
)
|
||||||
|
|
||||||
|
return new_river
|
||||||
|
|
||||||
|
def _db_save(self, execute, data=None):
|
||||||
|
logger.debug("Save river...")
|
||||||
|
for reach in self._reachs:
|
||||||
|
data["reach"] = reach.geometry
|
||||||
|
reach._db_save(execute, data)
|
||||||
Loaded 100 of 399 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user