Compare commits

...
53 Commits
Author SHA1 Message Date
Theophile Terraz e6aa840633 debug custom plot (time) 2025-02-17 10:02:44 +01:00
Theophile Terraz 4b976d3b5f add copy/paste in pollutant BC + debug 2025-02-17 09:43:02 +01:00
Theophile Terraz e3315c8f81 add 'cancel' button when closing Pamhyr2 from x button 2025-02-14 14:48:40 +01:00
Theophile Terraz 6bcbd006f1 debug 2025-02-14 14:39:25 +01:00
Theophile Terraz c60a0938eb pep8 2025-02-13 15:10:53 +01:00
Theophile Terraz 4d026afb2c debug CI 2025-02-13 14:49:17 +01:00
Theophile Terraz 4e888d9db0 more debug 2025-02-11 12:16:17 +01:00
Theophile Terraz 440996b636 debug 2025-02-11 11:59:58 +01:00
Theophile Terraz ed1a1a71ac debug 2025-02-11 10:20:12 +01:00
Theophile Terraz cbe3ad0084 debug adists windows 2025-02-06 14:46:34 +01:00
Theophile Terraz 46935fde45 forgotten file 2025-02-04 18:06:11 +01:00
Theophile Terraz ca8dc19c83 work on export CSV compare results 2025-02-04 16:24:42 +01:00
Theophile Terraz e4a31b3497 move custom export to sub folder 2025-02-04 14:31:17 +01:00
Theophile Terraz 406dc2bdd4 update tuto2 2025-02-04 14:07:56 +01:00
Theophile Terraz c325f61fce debug 2025-02-04 13:58:50 +01:00
Theophile Terraz d3729cfe77 cosmetic 2025-02-04 11:50:41 +01:00
Theophile Terraz fa8f07b97e work on multiple results plot 2025-02-04 11:12:56 +01:00
Theophile Terraz 52c153fa84 debug water fill 2025-02-03 11:46:55 +01:00
Theophile Terraz 21bd87f74b debug 2025-02-03 11:17:19 +01:00
Theophile Terraz 4d08f3c271 pep8 2025-02-03 10:09:45 +01:00
Theophile Terraz e44bbd5a3c unit translation 2025-02-03 09:45:19 +01:00
Theophile Terraz f827f6bf13 area unit for reservoirs 2025-02-03 09:34:34 +01:00
Theophile Terraz 4be68ba98d work on custom plots and exports aof compare results 2025-01-31 11:59:08 +01:00
Theophile Terraz e47edea63b debug custom plots (compare resuts) 2025-01-31 10:08:05 +01:00
Theophile Terraz 8daf89d1c4 debug read_bin when .bin does not exist 2025-01-31 10:07:32 +01:00
Theophile Terraz 0fa3ca5fad debug compare results 2025-01-30 12:31:02 +01:00
Theophile Terraz e3229c8183 debug plotH 2025-01-29 15:50:56 +01:00
Theophile Terraz c8606cf445 Merge branch 'master' into compare_results 2025-01-29 14:38:36 +01:00
Theophile Terraz 09029dc993 add copy AdisTS results table 2025-01-29 14:29:28 +01:00
Theophile Terraz 0a97070b90 add copy results table 2025-01-29 14:19:42 +01:00
Theophile Terraz 4f57179a2e add TP in Windows release 2025-01-28 14:01:07 +01:00
Theophile Terraz d0d7d91ab7 update tuto charriage 2025-01-28 11:57:49 +01:00
Theophile Terraz 8497d151ab Merge branch 'master' of gitlab.com:pamhyr/pamhyr2 2025-01-28 11:13:17 +01:00
Theophile Terraz 8a98f2bbca debug CI 2025-01-28 11:12:52 +01:00
Dorian Hernandez 181aea2805 Merge branch 'master' of https://gitlab.com/pamhyr/pamhyr2 2025-01-28 11:04:51 +01:00
Dorian Hernandez 6a762275b6 Mise-a-jour TP_AdisTS 2025-01-28 10:57:26 +01:00
Theophile Terraz a64430691c replace Lea's TP by Jerôme's 2025-01-28 10:54:44 +01:00
Theophile Terraz 3cd6d31731 debug windows paths 2025-01-28 10:04:12 +01:00
Theophile Terraz af30fde81a debug adis path windows 2025-01-27 17:57:44 +01:00
Theophile Terraz 589b8dcd23 compare_results: debug timestamps 2025-01-27 17:34:47 +01:00
Theophile Terraz 4e87135bf4 compare_results: debug timestamps + disable multiple selection for solver table 2025-01-27 11:48:25 +01:00
Theophile Terraz f636236935 debug open results multiple times 2025-01-27 11:04:13 +01:00
Theophile Terraz c3d732b426 merge master 2025-01-27 09:35:08 +01:00
Theophile Terraz 8913a774ea force Mage sulver type in open from file 2025-01-15 14:50:06 +01:00
Theophile Terraz 36c3785cde Merge branch 'master' into compare_results 2025-01-15 14:27:58 +01:00
Theophile Terraz 5ed905df71 Merge branch 'master' into compare_results 2025-01-15 14:25:12 +01:00
Theophile Terraz ea4fa81cc4 debug 2025-01-15 14:13:46 +01:00
Theophile Terraz 8862be991e Merge branch 'master' into compare_results 2025-01-15 14:08:02 +01:00
Theophile Terraz 8aea55909e debug 2025-01-15 14:07:19 +01:00
Theophile Terraz 1289967abb debug 2025-01-15 14:05:11 +01:00
Theophile Terraz 41d1fb9d59 put compare solvers in results window 2025-01-10 16:54:02 +01:00
Theophile Terraz 8d9a196059 merge 2025-01-09 13:47:26 +01:00
Theophile Terraz 558085705f start to work on compare results 2024-11-28 09:20:20 +01:00
55 changed files with 2733 additions and 4143 deletions

No files matched your search

+4 -3
View File
@@ -30,6 +30,7 @@ stages:
variables:
MAGE_8_VERSION: "v8.3.6"
ADISTS_VERSION: "v1.0.2"
dl-mage8-doc:
stage: downloads
@@ -92,7 +93,7 @@ dl-adists-linux:
script:
- mkdir -p 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://gitlab.irstea.fr/jean-baptiste.faure/adists/-/releases/$ADISTS_VERSION/downloads/executables/adists
artifacts:
paths:
- adists-linux/adists
@@ -106,7 +107,7 @@ dl-adists-windows:
script:
- mkdir -p 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://gitlab.irstea.fr/jean-baptiste.faure/adists/-/releases/$ADISTS_VERSION/downloads/executables/adists_win64.exe
artifacts:
paths:
- adists-windows/adists.exe
@@ -363,7 +364,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
# Copy 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:
paths:
- linux/pamhyr
+1 -1
View File
@@ -1375,7 +1375,7 @@ contribution.
#+INCLUDE: "../../AUTHORS" src text
[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/
** Translate
@@ -424,7 +424,7 @@ Create a new version of {{{pamhyr}}} called {{{pamhyr2}}}
** Contribution
#+LaTeX: \begin{center}
\faIcon{gitlab} https://gitlab.irstea.fr/theophile.terraz/pamhyr/
\faIcon{gitlab} https://gitlab.com/pamhyr/pamhyr2/
#+LaTeX: \end{center}
*** For users
@@ -462,7 +462,7 @@ Create a new version of {{{pamhyr}}} called {{{pamhyr2}}}
# #+END_EXPORT
#+LaTeX: \begin{center}
\faIcon{gitlab} https://gitlab.irstea.fr/theophile.terraz/pamhyr/
\faIcon{gitlab} https://gitlab.com/pamhyr/pamhyr2/
#+LaTeX: \end{center}
#+LaTeX: \begin{center}
@@ -179,13 +179,13 @@ Ouvrez la fen
\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}.\\
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}
\includegraphics[width=15cm]{img/CL_edit.jpeg}
\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.
+41 -11
View File
@@ -112,7 +112,7 @@ Auteurs : & Céline Berni & celine.berni@inrae.fr\tabularnewline
% \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.
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.
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}
\includegraphics[width=15cm]{img/export_resultats.png}
\includegraphics[width=12cm]{img/export_resultats2.png}
\includegraphics[width=15cm]{img/export_resultats_commentee.png}
%\includegraphics[width=12cm]{../../../src/View/ui/ressources/export_resultats2.png}
\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}
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) ?
\end{remark}
\pagebreak{}
\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.
@@ -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.
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.
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 ?
\end{remark}
\pagebreak{}
\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.
@@ -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.
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.
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.
Vous pourrez alors créer un réseau tel que celui ci-dessous où DevLat est le noeud marquant la diffluence.
\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.
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.
\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}
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}
\includegraphics[width=15cm]{img/dl.png}
\par\end{center}
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.
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+18 -8
View File
@@ -68,14 +68,24 @@ copy /y ..\doc\dev\images\* pamhyr\doc\images
copy /y ..\doc\images\* pamhyr\doc\images
rem Tuto
mkdir pamhyr\doc\Tuto1\
mkdir pamhyr\doc\Tuto1\data
copy /y ..\doc\users\Tuto1\Hogneau_Engees2022.pdf pamhyr\doc\Tuto1\Hogneau_Engees2022.pdf
copy /y ..\doc\users\Tuto1\step-by-step.pdf pamhyr\doc\Tuto1\Tuto1-en.pdf
copy /y ..\doc\users\Tuto1\pas-a-pas.pdf pamhyr\doc\Tuto1\Tuto1-fr.pdf
copy /y ..\doc\users\Tuto1\*.pamhyr pamhyr\doc\Tuto1\
copy /y ..\doc\users\Tuto1\data\* pamhyr\doc\Tuto1\data\
mkdir pamhyr\doc\TP_Hydraulique_Hogneau\
mkdir pamhyr\doc\TP_Hydraulique_Hogneau\data
copy /y ..\doc\users\TP_Hydraulique_Hogneau\Hogneau_Engees2022.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Hogneau_Engees2022.pdf
copy /y ..\doc\users\TP_Hydraulique_Hogneau\step-by-step.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Tuto1-en.pdf
copy /y ..\doc\users\TP_Hydraulique_Hogneau\pas-a-pas.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Tuto1-fr.pdf
copy /y ..\doc\users\TP_Hydraulique_Hogneau\Tuto-2-fr.pdf pamhyr\doc\TP_Hydraulique_Hogneau\Tuto2-fr.pdf
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
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\
@@ -222,3 +222,33 @@ class BoundaryConditionAdisTS(SQLSubModel):
@property
def data(self):
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 insert(self, index: int, value):
self._data.insert(index, value)
self._status.modified()
+1 -2
View File
@@ -167,8 +167,7 @@ class ProfileXYZ(Profile, SQLSubModel):
filter(
lambda s: s.id == sl,
data["sediment_layers_list"].sediment_layers
)
)
), None)
data["profile"] = new
new._points = PointXYZ._db_load(execute, data.copy())
@@ -384,9 +384,11 @@ class InitialConditions(SQLSubModel):
width = profile.wet_width(profile.z_min() + height)
frictions = self._reach.frictions.frictions
strickler = None
for f in frictions:
if f.contains_rk(profile.rk):
strickler = f.get_friction(profile.rk)[0]
if frictions is not None:
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:
strickler = 25.0
@@ -423,6 +425,8 @@ class InitialConditions(SQLSubModel):
def generate_discharge(self, discharge: float, compute_height: bool):
profiles = self._reach.reach.profiles.copy()
if profiles is None:
return None
profiles.reverse()
previous_elevation = -99999.99
@@ -443,9 +447,11 @@ class InitialConditions(SQLSubModel):
width = profile.width_approximation()
frictions = self._reach.frictions.frictions
strickler = None
for f in frictions:
if f.contains_rk(profile.rk):
strickler = f.get_friction(profile.rk)[0]
if frictions is not None:
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:
strickler = 25.0
+4 -1
View File
@@ -45,7 +45,10 @@ class Pollutants(SQLSubModel):
else:
self.id = id
self._name = str(name)
if name is None or name == "":
self.name = f"pol{self.id}"
else:
self._name = str(name)
self._enabled = True
self._data = []
+4
View File
@@ -56,6 +56,10 @@ class Results(object):
def set(self, key, value):
self._meta_data[key] = value
@property
def is_valid(self):
return ("timestamps" in self._meta_data)
def get(self, key):
return self._meta_data[key]
+4 -6
View File
@@ -17,7 +17,6 @@
import logging
import numpy as np
import os
import glob
from copy import deepcopy
from datetime import datetime
@@ -41,11 +40,10 @@ class Results(object):
# Keep results creation date
"creation_date": datetime.now(),
}
repertory_results = os.path.join(repertory, "resultats")
self._pollutants_list = [
el.split("/")[-1][0:-4]
for el in glob.glob(repertory_results + "/*.bin")
]
filelist = [f for f in os.listdir(self._repertory)
if os.path.isfile(os.path.join(self._repertory, f))
]
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.index("total_sediment"))
)
+4 -1
View File
@@ -57,7 +57,10 @@ class Profile(object):
)
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):
return any(map(lambda ts: "sl" in self._data[ts], self._data))
+25 -20
View File
@@ -17,7 +17,6 @@
# -*- coding: utf-8 -*-
import os
import glob
import logging
import numpy as np
@@ -129,9 +128,9 @@ class AdisTS(CommandLineSolver):
repertory, f"{name}.REP"
), "w+"
) as f:
f.write(f"NET ../{mage_rep}/{name}.NET\n")
f.write(f"REP ../{mage_rep}/{name}.REP\n")
path = os.path.join("..", mage_rep, name)
f.write(f"NET {path}.NET\n")
f.write(f"REP {path}.REP\n")
for file in files:
EXT = file.split('.')[1]
@@ -141,7 +140,7 @@ class AdisTS(CommandLineSolver):
path_mage_net = os.path.join(os.path.abspath(
os.path.join(repertory, os.pardir)
), f"{mage_rep}/net")
), os.path.join(mage_rep, "net"))
path_adists_net = os.path.join(repertory, "net")
if os.path.exists(path_mage_net):
@@ -620,15 +619,15 @@ class AdisTSwc(AdisTS):
@timer
def read_bin(self, study, repertory, results, qlog=None, name="0"):
repertory_results = os.path.join(repertory, "resultats")
files_bin_names = [el.split("/")[-1]
for el in glob.glob(repertory_results+"/*.bin")]
filelist = [f for f in os.listdir(repertory)
if os.path.isfile(os.path.join(repertory, f))
]
files_bin_names = [f for f in filelist if f[-4:] == ".bin"]
files_bin_names.insert(0, files_bin_names.pop(
files_bin_names.index("total_sediment.bin"))
)
ifilename = os.path.join(repertory_results, files_bin_names[0])
ifilename = os.path.join(repertory, files_bin_names[0])
logger.info(f"read_bin: Start reading '{ifilename}' ...")
@@ -725,12 +724,12 @@ class AdisTSwc(AdisTS):
def ip_to_ri(r, i): return i - reach_offset[r]
path_files = map(lambda file: os.path.join(
repertory_results, file), files_bin_names)
repertory, file), files_bin_names)
data_tmp = {}
for file_bin in path_files:
key_pol = file_bin.split("/")[-1][0:-4]
key_pol = os.path.basename(file_bin)[0:-4]
data_tmp[key_pol] = {}
with open(file_bin, 'rb') as f:
# header
@@ -833,8 +832,6 @@ class AdisTSwc(AdisTS):
if name is None:
name = study.name.replace(" ", "_")
print("adist ts results repertory: ", repertory)
results = super(AdisTSwc, self).results(study,
repertory,
qlog,
@@ -852,15 +849,23 @@ class AdisTSwc(AdisTS):
def rm_previous_results(self, study, repertory, qlog):
if "resultats" not in os.listdir(repertory):
if "resultats" in os.listdir(repertory):
repertory_results = os.path.join(repertory, "resultats")
else:
repertory_results = os.path.normpath(repertory)
if not os.path.isdir(repertory_results):
return
repertory_results = os.path.join(repertory, "resultats")
filelist = [f for f in os.listdir(repertory_results)
if os.path.isfile(os.path.join(repertory_results, f))
]
files_bin_names = [f for f in filelist if f[-4:] == ".bin"]
if len(files_bin_names) < 1:
return
files_bin_names = [el.split("/")[-1]
for el in glob.glob(repertory_results+"/*.bin")]
for el in glob.glob(repertory_results+"/*.bin"):
os.remove(el)
for el in files_bin_names:
os.remove(os.path.join(repertory_results, el))
@timer
def export(self, study, repertory, mage_rep, qlog=None, name="0"):
+26 -6
View File
@@ -717,7 +717,7 @@ class Mage(CommandLineSolver):
# RESULTS #
###########
def read_bin(self, study, repertory, results, qlog=None, name="0"):
def read_bin(self, study, fname, results, qlog=None, name="0"):
return
@timer
@@ -728,7 +728,16 @@ class Mage(CommandLineSolver):
repertory=repertory,
name=name,
)
self.read_bin(study, repertory, results, qlog, name=name)
fname = os.path.join(repertory, f"{name}.BIN")
if not os.path.isfile(fname):
logger.info(f"Result file {name}.BIN does not exist")
return None
try:
self.read_bin(study, fname, results, qlog, name=name)
except Exception as e:
logger.error(f"Failed to read results")
logger_exception(e)
return None
return results
@@ -934,8 +943,7 @@ class Mage8(Mage):
###########
@timer
def read_bin(self, study, repertory, results, qlog=None, name="0"):
fname = os.path.join(repertory, f"{name}.BIN")
def read_bin(self, study, fname, results, qlog=None, name="0"):
logger.info(f"read_bin: Start reading '{fname}' ...")
with mage_file_open(fname, "r") as f:
@@ -986,6 +994,7 @@ class Mage8(Mage):
reachs = []
iprofiles = {}
profile_len = []
reach_offset = {}
data = read_int(2*nb_reach)
@@ -1005,6 +1014,7 @@ class Mage8(Mage):
# Profile ID offset
reach_offset[r] = i1
profile_len.append(i2-i1+1)
logger.debug(f"read_bin: iprofiles = {iprofiles}")
@@ -1033,6 +1043,15 @@ class Mage8(Mage):
]
def ip_to_ri(r, i): return i - reach_offset[r]
# check results and geometry consistency
for i, r in enumerate(reachs):
lp = len(r.profiles)
pl = profile_len[i]
if lp != pl:
logger.warning(f"geometry reach {i} has {lp} profiles")
logger.warning(f"results reach {i} has {pl} values")
return
ts = set()
end = False
while not end:
@@ -1042,7 +1061,7 @@ class Mage8(Mage):
f, dtype=np.byte, count=1)).decode()
data = read_float(n)
logger.debug(f"read_bin: timestamp = {timestamp} sec")
# logger.debug(f"read_bin: timestamp = {timestamp} sec")
ts.add(timestamp)
if key in ["Z", "Q"]:
@@ -1066,7 +1085,6 @@ class Mage8(Mage):
endline()
end = newline().size <= 0
logger.debug(reachs[0].profiles[0]._data)
results.set("timestamps", ts)
ts_list = sorted(ts)
logger.info(f"compute tab...")
@@ -1265,6 +1283,8 @@ class Mage8(Mage):
name = study.name.replace(" ", "_")
results = super(Mage8, self).results(study, repertory, qlog, name=name)
if results is None:
return None
if with_gra:
self.read_gra(study, repertory, results, qlog, name=name)
@@ -41,7 +41,7 @@ from PyQt5.QtWidgets import (
)
from View.BoundaryConditionsAdisTS.Edit.UndoCommand import (
AddCommand, DelCommand, SetDataCommand,
AddCommand, DelCommand, SetDataCommand, PasteCommand,
)
_translate = QCoreApplication.translate
@@ -118,3 +118,28 @@ class TableModel(PamhyrTableModel):
)
self.endRemoveRows()
def paste(self, row, header, data):
if len(data) == 0:
return
self.layoutAboutToBeChanged.emit()
self._undo.push(
PasteCommand(
self._data, row,
list(
map(
lambda d: self._data.new_from_data(header, d),
data
)
)
)
)
self.layoutAboutToBeChanged.emit()
self.update()
def update(self):
# self.auto_sort()
self.layoutChanged.emit()
@@ -102,3 +102,22 @@ class DelCommand(QUndoCommand):
def redo(self):
for row in self._rows:
del self._data._data[row]
class PasteCommand(QUndoCommand):
def __init__(self, data, row, bcs):
QUndoCommand.__init__(self)
self._data = data
self._row = row
self._bcs = bcs
self._bcs.reverse()
def undo(self):
self._data.delete_i(
range(self._row, self._row + len(self._bcs))
)
def redo(self):
for bc in self._bcs:
self._data.insert(self._row, bc)
@@ -200,6 +200,22 @@ class EditBoundaryConditionWindow(PamhyrWindow):
self.copyTableIntoClipboard(table)
def _paste(self):
header, data = self.parseClipboardTable()
logger.debug(f"paste: h:{header}, d:{data}")
if len(data) == 0:
return
row = 0
rows = self.index_selected_rows()
if len(rows) != 0:
row = rows[0]
self._table.paste(row, header, data)
self.plot.update()
def _undo(self):
self._table.undo()
self.plot.update()
@@ -182,6 +182,9 @@ class BoundaryConditionAdisTSWindow(PamhyrWindow):
for row in rows:
data = self._bcs.lst[row]
if data.node is None:
continue
if self.sub_window_exists(
EditBoundaryConditionWindow,
data=[self._study, None, data]
+20 -10
View File
@@ -23,6 +23,7 @@ from tools import trace, timer, logger_exception
from View.Tools.PamhyrWindow import PamhyrWindow
from PyQt5 import QtWidgets
from PyQt5.QtGui import (
QKeySequence,
)
@@ -30,7 +31,7 @@ from PyQt5.QtGui import (
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
QRect, QSettings, QItemSelectionModel,
)
from PyQt5.QtWidgets import (
@@ -260,16 +261,24 @@ class InitialConditionsWindow(PamhyrWindow):
self._update()
def import_from_file(self):
workdir = os.path.dirname(self._study.filename)
return self.file_dialog(
select_file="ExistingFile",
callback=lambda d: self._import_from_file(d[0]),
directory=workdir,
default_suffix=".BIN",
file_filter=["Mage (*.BIN)"],
options = QFileDialog.Options()
settings = QSettings(QSettings.IniFormat,
QSettings.UserScope, 'MyOrg', )
options |= QFileDialog.DontUseNativeDialog
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
self._trad["open_file"],
"",
";; ".join(["Mage (*.BIN)"]),
options=options
)
if filename != "":
size = os.stat(filename).st_size
# self._table.import_geometry(0, filename)
print(f"filename: {filename}")
self._import_from_file(filename)
def _import_from_file(self, file_name):
solver = Mage8("dummy")
name = os.path.basename(file_name)\
@@ -292,7 +301,8 @@ class InitialConditionsWindow(PamhyrWindow):
)
dlg.exec_()
results = self._tmp_results
self._import_from_results(results)
if results.is_valid:
self._import_from_results(results)
def _import_from_results(self, results):
logger.debug(f"import from results: {results}")
+177 -30
View File
@@ -77,14 +77,18 @@ from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
from View.AdditionalFiles.Window import AddFileListWindow
from View.REPLines.Window import REPLineListWindow
from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
from View.RunSolver.Window import (
SelectSolverWindow,
SolverLogWindow,
CompareSolversWindow
)
from View.Results.Window import ResultsWindow
from View.RunSolver.WindowAdisTS import (
SelectSolverWindowAdisTS,
SolverLogWindowAdisTS
)
from View.CheckList.Window import CheckListWindow
from View.CheckList.WindowAdisTS import CheckListWindowAdisTS
from View.Results.Window import ResultsWindow
from View.Results.WindowAdisTS import ResultsWindowAdisTS
from View.Results.ReadingResultsDialog import ReadingResultsDialog
from View.Debug.Window import ReplWindow
@@ -93,6 +97,10 @@ from View.Pollutants.Window import PollutantsWindow
from View.D90AdisTS.Window import D90AdisTSWindow
from View.DIFAdisTS.Window import DIFAdisTSWindow
from Solver.Solvers import GenericSolver
from Model.Results.Results import Results
# Optional internal display of documentation for make the application
# package lighter...
try:
@@ -135,7 +143,7 @@ define_model_action = [
"action_menu_edit_reach_sediment_layers", "action_menu_edit_reservoirs",
"action_menu_edit_hydraulic_structures", "action_menu_additional_file",
"action_menu_results_last", "action_open_results_from_file",
"action_menu_boundary_conditions_sediment",
"action_compare_results", "action_menu_boundary_conditions_sediment",
"action_menu_rep_additional_lines", "action_menu_output_rk",
"action_menu_run_adists", "action_menu_pollutants",
"action_menu_d90", "action_menu_dif",
@@ -280,6 +288,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_menu_close": self.close_model,
"action_menu_results_last": self.open_last_results,
"action_open_results_from_file": self.open_results_from_file,
"action_compare_results": self.compare_results,
"action_open_results_adists": self.open_results_adists,
# Help
"action_menu_pamhyr_users_wiki": self.open_doc_user,
@@ -339,10 +348,12 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
def closeEvent(self, event):
if not self._close_question:
if self._study is not None and not self._study.is_saved:
if self.dialog_close(cancel=False):
if self.dialog_close():
# PAMHYR is close correctly (no crash)
self.conf.set_close_correctly()
super(ApplicationWindow, self).closeEvent(event)
else:
event.ignore()
else:
super(ApplicationWindow, self).closeEvent(event)
@@ -522,7 +533,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
self.update()
def close_model(self):
if not self.dialog_close(cancel=True):
if not self.dialog_close():
return
self._study = None
@@ -824,21 +835,19 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
return file
def dialog_close(self, cancel=True):
def dialog_close(self):
dlg = QMessageBox(self)
dlg.setWindowTitle(self._trad["mb_close_title"])
dlg.setText(self._trad["mb_close_msg"])
opt = QMessageBox.Save | QMessageBox.Close
if cancel:
opt |= QMessageBox.Cancel
opt |= QMessageBox.Cancel
dlg.setStandardButtons(opt)
dlg.setIcon(QMessageBox.Warning)
dlg.button(QMessageBox.Save).setText(self._trad["Save"])
dlg.button(QMessageBox.Close).setText(self._trad["Close"])
if cancel:
dlg.button(QMessageBox.Cancel).setText(self._trad["Cancel"])
dlg.button(QMessageBox.Cancel).setText(self._trad["Cancel"])
res = dlg.exec()
@@ -1423,22 +1432,25 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
if results is None:
return
# results does not have values, for example if geometry missmatch
if not results.is_valid:
return
# Windows already opened
if self.sub_window_exists(
ResultsWindow,
data=[
self._study,
None, # No config
solver,
results
]
None, # No config,
results._solver,
results._repertory,
results._name]
):
return
res = ResultsWindow(
study=self._study,
solver=solver,
results=results,
results=[results],
parent=self
)
res.show()
@@ -1487,7 +1499,8 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
self._study,
None, # No config
solver,
results
results._repertory,
results._name,
]
):
return
@@ -1525,9 +1538,6 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
if self._study is None:
return
if self._study.filename == "":
return
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
@@ -1538,14 +1548,15 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
# dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden)
dialog.setNameFilters(['Mage (*.BIN)'])
if self._last_solver is None:
dialog.setDirectory(
os.path.dirname(self._study.filename)
)
else:
dialog.setDirectory(
self._solver_workdir(self._last_solver)
)
if self._study.filename is not None:
if self._last_solver is None:
dialog.setDirectory(
os.path.dirname(self._study.filename)
)
else:
dialog.setDirectory(
self._solver_workdir(self._last_solver)
)
if dialog.exec_():
file_name = dialog.selectedFiles()
@@ -1555,6 +1566,134 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
results=file_name[0]
)
def compare_results(self):
if self._study is None:
return
run = CompareSolversWindow(
study=self._study,
config=self.conf,
parent=self
)
if run.exec():
results = self.diff_results(run.solver1,
run.solver2)
else:
return
# At least one result not available
if results is None:
return
# Windows already opened
if self.sub_window_exists(
ResultsWindow,
data=[self._study, None] +
[r._solver for r in results] +
[r._repertory for r in results] +
[r._name for r in results]
):
return
res = ResultsWindow(
study=self._study,
results=results,
parent=self
)
res.show()
def diff_results(self, solver1, solver2):
if solver1 is None:
# TODO message
return None
if solver2 is None:
# TODO message
return None
solver3 = GenericSolver(solver1.name+" - "+solver2.name)
solver4 = GenericSolver(solver1.name)
solver5 = GenericSolver(solver2.name)
result1 = solver1.results(
self._study,
self._solver_workdir(solver1),
)
if result1 is None:
# TODO message
return None
result2 = solver2.results(
self._study,
self._solver_workdir(solver2),
)
if result2 is None:
# TODO message
return None
if result2.get("nb_reach") != result1.get("nb_reach"):
# TODO message
return None
if result2.get("nb_profile") != result1.get("nb_profile"):
# TODO message
return None
# return [result1, result2]
result3 = Results(self._study, solver3)
result4 = Results(self._study, solver1)
result5 = Results(self._study, solver2)
result3.set("nb_reach", result1.get("nb_reach"))
result4.set("nb_reach", result1.get("nb_reach"))
result5.set("nb_reach", result1.get("nb_reach"))
result3.set("nb_profile", result1.get("nb_profile"))
result4.set("nb_profile", result1.get("nb_profile"))
result5.set("nb_profile", result1.get("nb_profile"))
ts = list(result1.get("timestamps").intersection(
result2.get("timestamps")))
result3.set("timestamps", ts)
result4.set("timestamps", ts)
result5.set("timestamps", ts)
for i in range(int(result1.get("nb_reach"))):
# Add reach to results reach list
r = result3.river.add(i)
r = result4.river.add(i)
r = result5.river.add(i)
for timestamp in result3.get("timestamps"):
for r in range(int(result1.get("nb_reach"))):
reach1 = result1.river.reach(r)
reach2 = result2.river.reach(r)
reach3 = result3.river.reach(r)
reach4 = result4.river.reach(r)
reach5 = result5.river.reach(r)
for p, (profile1, profile2) in enumerate(zip(
reach1.profiles, reach2.profiles)):
for key in ["Z", "Q", "V"]:
d1 = profile1.get_ts_key(timestamp, key)
d2 = profile2.get_ts_key(timestamp, key)
d = d1-d2
reach3.set(p, timestamp, key, d)
reach4.set(p, timestamp, key, d1)
reach5.set(p, timestamp, key, d2)
limits = reach3.profile(p).geometry.get_water_limits(
reach3.profile(p).get_ts_key(timestamp, "Z")
)
reach3.set(
p, timestamp,
"water_limits",
limits
)
limits = profile1.get_ts_key(timestamp, "water_limits")
reach4.set(p, timestamp, "water_limits", limits)
limits = profile2.get_ts_key(timestamp, "water_limits")
reach5.set(p, timestamp, "water_limits", limits)
return [result4, result5, result3]
def open_results_adists(self):
if self._study is None:
return
@@ -1581,13 +1720,21 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
if dialog.exec_():
dir_path = dialog.selectedFiles()[0]
dir_list = os.listdir(dir_path)
if "resultats" in dir_list:
dir_path = os.path.join(dir_path, "resultats")
dir_list = os.listdir(dir_path)
bin_list = list(filter(lambda s: "bin" in s, dir_list))
solver_name = dir_path.split("/")[-2]
if len(bin_list) < 1:
# TODO message
return
path = os.path.normpath(dir_path)
solver_name = path.split(os.sep)[-2]
solver_results = next(filter(lambda x: x.name == solver_name,
self.conf.solvers))
solver_results_adists = solver_results.results(
self._study,
repertory=dir_path[:-10], qlog=None) # self._output)
repertory=dir_path, qlog=None) # self._output)
logger.info(f"Select results: {dir_path}")
if len(bin_list) >= 2 and ("total_sediment.bin" in bin_list):
self.open_solver_results_adists(
+1 -1
View File
@@ -35,5 +35,5 @@ class EditReservoirTranslate(ReservoirTranslate):
self._sub_dict["table_headers"] = {
"z": self._dict["unit_elevation"],
"area": self._dict["unit_area"],
"area": self._dict["unit_area_he"],
}
@@ -0,0 +1,151 @@
# CustomExport.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 -*-
from View.Tools.PamhyrWindow import PamhyrDialog
from PyQt5.QtWidgets import (
QRadioButton, QCheckBox, QVBoxLayout, QLabel,
)
from View.Results.translate import ResultsTranslate
class CustomExportDialog(PamhyrDialog):
_pamhyr_ui = "CustomExportAdisDialog"
_pamhyr_name = "Custom Plot Selection"
def __init__(self, parent=None):
trad = ResultsTranslate()
super(CustomExportDialog, self).__init__(
title=trad[self._pamhyr_name],
options=[],
trad=trad,
parent=parent
)
self._available_values_x = self._trad.get_dict("values_x")
self._available_values_y = self._trad.get_dict("values_y")
self.setup_radio_buttons_x()
self.setup_radio_buttons_res()
self.setup_envelop_box()
self.setup_check_boxes()
self.value = None
def setup_radio_buttons_x(self):
self._radio = []
layout = self.find(QVBoxLayout, "verticalLayout_x")
for value in self._available_values_x:
btn = QRadioButton(
self._available_values_x[value],
parent=self
)
self._radio.append((value, btn))
layout.addWidget(btn)
self._radio[0][1].setChecked(True)
layout.addStretch()
def setup_radio_buttons_res(self):
self._radio2 = []
layout = self.find(QVBoxLayout, "verticalLayout_pol")
label = self.find(QLabel, "label_3")
label.setText(self._trad["solver"])
for solver in self.parent._solvers:
btn = QRadioButton(
solver.name,
parent=self
)
self._radio2.append((solver.name, btn))
layout.addWidget(btn)
self._radio2[0][1].setChecked(True)
if len(self.parent._results) == 1:
self._radio2[0][1].setEnabled(False)
label.setEnabled(False)
else:
self._radio2[0][1].setEnabled(True)
label.setEnabled(True)
layout.addStretch()
def setup_envelop_box(self):
layout = self.find(QVBoxLayout, "verticalLayout_x")
self._envelop = QCheckBox(
self._trad["envelop"],
parent=self
)
layout.addWidget(self._envelop)
self._envelop.setChecked(True)
for r in self._radio:
r[1].clicked.connect(self.envelop_box_status)
def envelop_box_status(self):
if self._radio[0][1].isChecked():
if len(self.parent._results) > 1:
self._envelop.setEnabled(False)
else:
self._envelop.setEnabled(True)
else:
self._envelop.setEnabled(False)
def setup_check_boxes(self):
self._check = []
layout = self.find(QVBoxLayout, "verticalLayout_y")
for value in self._available_values_y:
btn = QCheckBox(
self._available_values_y[value],
parent=self
)
self._check.append((value, btn))
layout.addWidget(btn)
self._check[0][1].setChecked(True)
layout.addStretch()
def accept(self):
x = next(
filter(
lambda r: r[1].isChecked(),
self._radio
)
)[0]
y = list(
map(
lambda b: b[0],
filter(
lambda b: b[1].isChecked(),
self._check
)
)
)
res = 0
for i, b in enumerate(self._radio2):
if b[1].isChecked():
res = i
break
self.value = x, y, self._envelop.isChecked(), res
super().accept()
@@ -1,5 +1,5 @@
# CustomPlotValuesSelectionDialog.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
# CustomExportAdis.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
File diff suppressed because it is too large. Load diff
+18 -6
View File
@@ -29,7 +29,7 @@ _translate = QCoreApplication.translate
class PlotAC(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
results=None, reach_id=0, profile_id=0,
results=None, reach_id=0, profile_id=0, res_id=0,
parent=None):
super(PlotAC, self).__init__(
canvas=canvas,
@@ -39,9 +39,11 @@ class PlotAC(PamhyrPlot):
parent=parent
)
self._current_timestamp = max(results.get("timestamps"))
self._current_reach_id = reach_id
self._current_profile_id = profile_id
self._current_res_id = res_id[0]
self._timestamps = parent._timestamps
self._current_timestamp = max(self._timestamps)
self.label_x = self._trad['x']
self.label_y = self._trad["unit_elevation"]
@@ -62,7 +64,7 @@ class PlotAC(PamhyrPlot):
@results.setter
def results(self, results):
self.data = results
self._current_timestamp = max(results.get("timestamps"))
self._current_timestamp = max(self._timestamps)
@timer
def draw(self, highlight=None):
@@ -71,7 +73,11 @@ class PlotAC(PamhyrPlot):
if self.results is None:
return
reach = self.results.river.reach(self._current_reach_id)
if self.results[self._current_res_id] is None:
return
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
self.draw_profile(reach, profile)
@@ -137,10 +143,15 @@ class PlotAC(PamhyrPlot):
self._current_profile_id = profile_id
self.update()
def set_result(self, res_id):
self._current_res_id = res_id[0]
self.update()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
reach = self.results.river.reach(self._current_reach_id)
reach = self.results[self._current_res_id].river.reach(
self._current_reach_id)
profile = reach.profile(self._current_profile_id)
x = profile.geometry.get_station()
z = profile.geometry.z()
@@ -152,7 +163,8 @@ class PlotAC(PamhyrPlot):
if not self._init:
self.draw()
reach = self.results.river.reach(self._current_reach_id)
reach = self.results[self._current_res_id].river.reach(
self._current_reach_id)
profile = reach.profile(self._current_profile_id)
x = profile.geometry.get_station()
z = profile.geometry.z()
+92 -40
View File
@@ -35,7 +35,7 @@ logger = logging.getLogger()
class PlotH(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
results=None, reach_id=0, profile_id=0,
results=None, reach_id=0, profile_id=0, res_id=[0],
parent=None):
super(PlotH, self).__init__(
canvas=canvas,
@@ -47,9 +47,11 @@ class PlotH(PamhyrPlot):
self._mode = "time"
self._current_timestamp = max(results.get("timestamps"))
self._current_reach_id = reach_id
self._current_profile_id = profile_id
self._current_res_id = res_id
self._timestamps = parent._timestamps
self._current_timestamp = max(self._timestamps)
self.label_x = self._trad["unit_time_s"]
self.label_y = self._trad["unit_discharge"]
@@ -60,8 +62,11 @@ class PlotH(PamhyrPlot):
self._isometric_axis = False
self._auto_relim_update = False
self._autoscale_update = False
# self._auto_relim_update = False
# self._autoscale_update = False
self._line_max = []
self._line = []
@property
def results(self):
@@ -70,47 +75,79 @@ class PlotH(PamhyrPlot):
@results.setter
def results(self, results):
self.data = results
self._current_timestamp = max(results.get("timestamps"))
self._current_timestamp = max(self._timestamps)
@timer
def draw(self, highlight=None):
self.init_axes()
self.canvas.axes.cla()
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
if self.results is None:
return
reach = self.results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
if reach.geometry.number_profiles == 0:
self._init = False
if len(self._current_res_id) < 1:
return
self.draw_max(reach)
self.draw_data(reach, profile)
self.draw_current()
if len(self._current_res_id) == 1:
self.draw_max(self._current_res_id[0])
for res_id in self._current_res_id:
if self.results[res_id] is None:
continue
results = self.results[res_id]
reach = results.river.reach(self._current_reach_id)
if reach.geometry.number_profiles == 0:
self._init = False
return
self.draw_data(res_id)
self.canvas.axes.set_xlabel(
self._trad["unit_time_s"],
color='black', fontsize=10
)
self.canvas.axes.set_ylabel(
self._trad["unit_discharge"],
color='black', fontsize=10
)
self.set_ticks_time_formater()
self.enable_legend()
self.idle()
self.update_current()
self.canvas.draw_idle()
self.update_idle
self.draw_current()
self._init = True
def draw_data(self, reach, profile):
self.ts = list(self.results.get("timestamps"))
self.ts.sort()
def draw_data(self, res_id):
x = self.ts
results = self.results[res_id]
reach = results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
x = self._timestamps
y = profile.get_key("Q")
self._line, = self.canvas.axes.plot(
if res_id == 2:
label = "Δ " + self.label_discharge
else:
label = self.label_discharge
if len(self._current_res_id) > 1:
if res_id != 2:
label += f" ({results._solver.name})"
line, = self.canvas.axes.plot(
x, y,
label=self.label_discharge,
color=self.color_plot,
label=label,
color=self.colors[res_id + 1],
**self.plot_default_kargs
)
self._line.append(line)
def draw_current(self):
self._current, = self.canvas.axes.plot(
@@ -122,12 +159,23 @@ class PlotH(PamhyrPlot):
lw=1.,
)
def draw_max(self, reach):
self.ts = list(self.results.get("timestamps"))
self.ts.sort()
def draw_max(self, res_id):
results = self.results[res_id]
reach = results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
x = self.ts
if reach.geometry.number_profiles == 0:
self._init = False
return
x = self._timestamps
y = []
if res_id == 2:
label = "Δ " + self.label_discharge_max
else:
label = self.label_discharge_max
for ts in x:
ts_y = -9999
for profile in reach.profiles:
@@ -135,13 +183,14 @@ class PlotH(PamhyrPlot):
ts_y = max(ts_y, q)
y.append(ts_y)
self._line_max, = self.canvas.axes.plot(
m, = self.canvas.axes.plot(
x, y,
label=self.label_discharge_max,
label=label,
color=self.color_plot_highlight,
linestyle='dotted',
**self.plot_default_kargs
)
self._line_max.append(m)
def set_reach(self, reach_id):
self._current_reach_id = reach_id
@@ -152,6 +201,10 @@ class PlotH(PamhyrPlot):
self._current_profile_id = profile_id
self.update()
def set_result(self, res_id):
self._current_res_id = res_id
self.draw()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
self.update_current()
@@ -162,24 +215,23 @@ class PlotH(PamhyrPlot):
self.draw()
self.update_data()
self.update_current()
self.update_idle()
def update_data(self):
reach = self.results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
for res, res_id in enumerate(self._current_res_id):
results = self.results[res_id]
reach = results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
x = self.ts
y = profile.get_key("Q")
x = self._timestamps
y = profile.get_key("Q")
self._line.set_data(x, y)
self._current.set_data(
[self._current_timestamp, self._current_timestamp],
self.canvas.axes.get_ylim()
)
self._line[res].set_data(x, y)
def update_current(self):
y = self._current.get_ydata()
self._current.set_data(
[self._current_timestamp, self._current_timestamp],
self.canvas.axes.get_ylim()
y
)
+29 -10
View File
@@ -32,7 +32,7 @@ logger = logging.getLogger()
class PlotRKC(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
results=None, reach_id=0, profile_id=0,
results=None, reach_id=0, profile_id=0, res_id=0,
parent=None):
super(PlotRKC, self).__init__(
canvas=canvas,
@@ -42,10 +42,11 @@ class PlotRKC(PamhyrPlot):
parent=parent
)
self._timestamps = results.get("timestamps")
self._current_timestamp = max(self._timestamps)
self._current_reach_id = reach_id
self._current_profile_id = profile_id
self._current_res_id = res_id[0]
self._timestamps = parent._timestamps
self._current_timestamp = max(self._timestamps)
self.label_x = self._trad["unit_rk"]
self.label_y = self._trad["unit_elevation"]
@@ -56,6 +57,9 @@ class PlotRKC(PamhyrPlot):
self._isometric_axis = False
self._auto_relim_update = True
self._autoscale_update = True
@property
def results(self):
return self.data
@@ -63,7 +67,7 @@ class PlotRKC(PamhyrPlot):
@results.setter
def results(self, results):
self.data = results
self._current_timestamp = max(results.get("timestamps"))
self._current_timestamp = max(self._timestamps)
@timer
def draw(self, highlight=None):
@@ -72,7 +76,11 @@ class PlotRKC(PamhyrPlot):
if self.results is None:
return
reach = self.results.river.reach(self._current_reach_id)
if self.results[self._current_res_id] is None:
return
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
self.draw_bottom(reach)
self.draw_water_elevation(reach)
@@ -107,11 +115,12 @@ class PlotRKC(PamhyrPlot):
self._river_bottom = z
def draw_profiles_hs(self, reach):
results = self.results[self._current_res_id]
lhs = filter(
lambda hs: hs._input_reach.reach is reach.geometry,
filter(
lambda hs: hs._input_reach is not None,
self.results.study.river.hydraulic_structures.lst
results.study.river.hydraulic_structures.lst
)
)
@@ -223,6 +232,7 @@ class PlotRKC(PamhyrPlot):
self.water_fill = self.canvas.axes.fill_between(
rk, self._river_bottom, water_z,
where=[b <= z for b, z in zip(self._river_bottom, water_z)],
color=self.color_plot_river_water_zone,
alpha=0.7,
interpolate=True
@@ -312,6 +322,10 @@ class PlotRKC(PamhyrPlot):
self._current_profile_id = profile_id
self.update_current()
def set_result(self, res_id):
self._current_res_id = res_id[0]
self.update()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
self.update()
@@ -320,7 +334,8 @@ class PlotRKC(PamhyrPlot):
if not self._init:
self.draw()
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
if reach.has_sediment():
self.update_bottom_with_bedload()
@@ -329,7 +344,8 @@ class PlotRKC(PamhyrPlot):
self.update_idle()
def update_water_elevation(self):
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
rk = reach.geometry.get_rk()
z_min = reach.geometry.get_z_min()
@@ -349,12 +365,14 @@ class PlotRKC(PamhyrPlot):
self.water_fill.remove()
self.water_fill = self.canvas.axes.fill_between(
rk, self._river_bottom, water_z,
where=[rb <= wz for rb, wz in zip(self._river_bottom, water_z)],
color=self.color_plot_river_water_zone,
alpha=0.7, interpolate=True
)
def update_current(self):
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
rk = reach.geometry.get_rk()
z_min = reach.geometry.get_z_min()
z_max = reach.geometry.get_z_max()
@@ -367,7 +385,8 @@ class PlotRKC(PamhyrPlot):
self.canvas.figure.canvas.draw_idle()
def update_bottom_with_bedload(self):
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
rk = reach.geometry.get_rk()
z = self.sl_compute_current_z(reach)
+23 -9
View File
@@ -38,7 +38,7 @@ logger = logging.getLogger()
class PlotXY(PamhyrPlot):
def __init__(self, canvas=None, trad=None, toolbar=None,
results=None, reach_id=0, profile_id=0,
results=None, reach_id=0, profile_id=0, res_id=0,
display_current=True, parent=None):
super(PlotXY, self).__init__(
canvas=canvas,
@@ -52,10 +52,11 @@ class PlotXY(PamhyrPlot):
self.line_gl = []
self.overflow = []
self._timestamps = results.get("timestamps")
self._timestamps = parent._timestamps
self._current_timestamp = max(self._timestamps)
self._current_reach_id = reach_id
self._current_profile_id = profile_id
self._current_res_id = res_id[0]
self.label_x = _translate("Results", "X (m)")
self.label_y = _translate("Results", "Y (m)")
@@ -136,7 +137,7 @@ class PlotXY(PamhyrPlot):
@results.setter
def results(self, results):
self.data = results
self._current_timestamp = max(results.get("timestamps"))
self._current_timestamp = max(self._timestamps)
@timer
def draw(self, highlight=None):
@@ -145,8 +146,12 @@ class PlotXY(PamhyrPlot):
if self.results is None:
return
reach = self.results.river.reach(self._current_reach_id)
reaches = self.results.river.reachs
if self.results[self._current_res_id] is None:
return
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
reaches = results.river.reachs
self.draw_profiles(reach, reaches)
self.draw_water_elevation(reach)
@@ -161,6 +166,7 @@ class PlotXY(PamhyrPlot):
if reach.geometry.number_profiles == 0:
self._init = False
return
self.line_xy = []
# TODO uncomment to draw all the reaches
# self.draw_other_profiles(reaches)
for xy in zip(reach.geometry.get_x(),
@@ -272,7 +278,8 @@ class PlotXY(PamhyrPlot):
)
def draw_water_elevation(self, reach):
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
poly_l_x, poly_l_y, poly_r_x, poly_r_y = [], [], [], []
for profile in reach.profiles:
@@ -308,6 +315,10 @@ class PlotXY(PamhyrPlot):
self.update_profile()
self.update_idle()
def set_result(self, res_id):
self._current_res_id = res_id[0]
self.update()
def set_timestamp(self, timestamp):
self._current_timestamp = timestamp
self.update()
@@ -322,7 +333,8 @@ class PlotXY(PamhyrPlot):
self.update_idle()
def update_profile(self):
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
self.plot_selected.set_data(
@@ -331,7 +343,8 @@ class PlotXY(PamhyrPlot):
)
def update_water_elevation(self):
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
poly_l_x, poly_l_y, poly_r_x, poly_r_y = [], [], [], []
for profile in reach.profiles:
@@ -358,7 +371,8 @@ class PlotXY(PamhyrPlot):
self.water_fill[0].set_xy(poly)
def update_water_elevation_overflow(self):
reach = self.results.river.reach(self._current_reach_id)
results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id)
profile = reach.profile(self._current_profile_id)
overflow = []
+20 -5
View File
@@ -46,13 +46,15 @@ _translate = QCoreApplication.translate
class TableModel(PamhyrTableModel):
def _setup_lst(self):
_river = self._data.river
_river = self._data[0].river
if self._opt_data == "reach":
self._lst = _river.reachs
elif self._opt_data == "profile":
self._lst = _river.reach(0).profiles
elif self._opt_data == "raw_data":
self._lst = _river.reach(0).profiles
elif self._opt_data == "solver":
self._lst = self._parent._solvers
def __init__(self, **kwargs):
self._timestamp = 0.0
@@ -76,6 +78,10 @@ class TableModel(PamhyrTableModel):
elif self._headers[column] == "rk":
v = self._lst[row].rk
return f"{v:.4f}"
elif self._opt_data == "solver":
if self._headers[column] == "solver":
v = self._lst[row].name
return str(v)
elif self._opt_data == "raw_data":
p = self._lst[row]
if self._headers[column] == "name":
@@ -84,14 +90,18 @@ class TableModel(PamhyrTableModel):
return f"{p.name}"
elif self._headers[column] == "water_elevation":
v = self._lst[row].get_ts_key(self._timestamp, "Z")
if v is None:
v = 0.0
return f"{v:.4f}"
elif self._headers[column] == "discharge":
v = self._lst[row].get_ts_key(self._timestamp, "Q")
if v is None:
v = 0.0
return f"{v:.4f}"
elif self._headers[column] == "velocity":
q = self._lst[row].get_ts_key(self._timestamp, "Q")
z = self._lst[row].get_ts_key(self._timestamp, "Z")
v = self._lst[row].get_ts_key(self._timestamp, "V")
if v is None:
v = 0.0
return f"{v:.4f}"
elif self._headers[column] == "width":
z = self._lst[row].get_ts_key(self._timestamp, "Z")
@@ -123,7 +133,10 @@ class TableModel(PamhyrTableModel):
v = self._lst[row].get_ts_key(self._timestamp, "V")
a = self._lst[row].geometry.wet_area(z)
b = self._lst[row].geometry.wet_width(z)
froude = v / sqrt(9.81 * (a / b))
if b == 0.0 or a == 0.0:
froude = 0.0
else:
froude = v / sqrt(9.81 * (a / b))
return f"{froude:.4f}"
else:
v = 0.0
@@ -132,12 +145,14 @@ class TableModel(PamhyrTableModel):
return QVariant()
def update(self, reach):
_river = self._data.river
_river = self._data[0].river
if self._opt_data == "reach":
self._lst = _river.reachs
elif self._opt_data == "profile" or self._opt_data == "raw_data":
self._lst = _river.reach(reach).profiles
elif self._opt_data == "solver":
self._lst = self._parent._solvers
self.layoutChanged.emit()
+13 -11
View File
@@ -45,6 +45,7 @@ _translate = QCoreApplication.translate
class TableModel(PamhyrTableModel):
def _setup_lst(self):
_river = self._data.river
self._timestamp = min(list(self._data.get("timestamps")))
if self._opt_data == "reach":
self._lst = _river.reachs
elif self._opt_data == "profile":
@@ -57,7 +58,6 @@ class TableModel(PamhyrTableModel):
self._lst = tmp_list
def __init__(self, type_pol, **kwargs):
self._timestamp = 0.0
self._type_pol = type_pol
super(TableModel, self).__init__(**kwargs)
@@ -99,16 +99,18 @@ class TableModel(PamhyrTableModel):
v = self._lst[row].get_ts_key(
self._timestamp, "pols")[pol_index][0]
return f"{v:.4f}"
if (self._headers[column] == pol + " Mass"
and self._type_pol[pol_index] == 7):
m1 = self._lst[row].get_ts_key(
self._timestamp, "pols")[pol_index][1]
m2 = self._lst[row].get_ts_key(
self._timestamp, "pols")[pol_index][2]
m3 = self._lst[row].get_ts_key(
self._timestamp, "pols")[pol_index][3]
v = m1 + m2 + m3
return f"{v:.4f}"
if self._headers[column] == pol + " Mass":
if self._type_pol[pol_index] == 7:
m1 = self._lst[row].get_ts_key(
self._timestamp, "pols")[pol_index][1]
m2 = self._lst[row].get_ts_key(
self._timestamp, "pols")[pol_index][2]
m3 = self._lst[row].get_ts_key(
self._timestamp, "pols")[pol_index][3]
v = m1 + m2 + m3
return f"{v:.4f}"
else:
return ""
return QVariant()
+387 -93
View File
@@ -59,9 +59,13 @@ from View.Results.CustomPlot.Plot import CustomPlot
from View.Results.CustomPlot.CustomPlotValuesSelectionDialog import (
CustomPlotValuesSelectionDialog,
)
from View.Results.CustomExport.CustomExport import CustomExportDialog
from View.Results.Table import TableModel
from View.Results.translate import ResultsTranslate
from View.Results.translate import (
ResultsTranslate,
CompareResultsTranslate
)
from View.Stricklers.Window import StricklersWindow
_translate = QCoreApplication.translate
@@ -82,16 +86,17 @@ class ResultsWindow(PamhyrWindow):
)
def __init__(self, study=None, config=None,
solver=None, results=None,
parent=None):
self._solver = solver
results=None, parent=None, trad=None):
self._solvers = [r._solver for r in results]
self._results = results
self._current_results = [0]
trad = ResultsTranslate()
if trad is None:
trad = ResultsTranslate()
name = (
trad[self._pamhyr_name] + " - "
+ study.name + " - "
+ self._solver.name
+ " - ".join([s.name for s in self._solvers])
)
super(ResultsWindow, self).__init__(
@@ -102,14 +107,15 @@ class ResultsWindow(PamhyrWindow):
parent=parent
)
self._hash_data.append(self._solver)
self._hash_data.append(self._results)
for r in results:
self._hash_data.append(r._solver)
self._hash_data.append(r._repertory)
self._hash_data.append(r._name)
self._additional_plot = {}
try:
self._timestamps = sorted(list(self._results.get("timestamps")))
self.get_timestamps()
self.setup_slider()
self.setup_table()
self.setup_plots()
@@ -119,22 +125,31 @@ class ResultsWindow(PamhyrWindow):
logger_exception(e)
return
self.update(reach_id=0,
profile_id=0)
self.update_table_selection_solver(0)
def setup_table(self):
self._table = {}
for t in ["reach", "profile", "raw_data"]:
for t in ["reach", "profile", "raw_data", "solver"]:
table = self.find(QTableView, f"tableView_{t}")
self._table[t] = TableModel(
table_view=table,
table_headers=self._trad.get_dict(f"table_headers_{t}"),
data=self._results,
undo=self._undo_stack,
opt_data=t
opt_data=t,
parent=self
)
self._table[t]._timestamp = self._timestamps[
self._slider_time.value()]
if len(self._results) <= 1:
table = self.find(QTableView, f"tableView_solver")
table.hide()
def setup_slider(self):
default_reach = self._results.river.reach(0)
default_reach = self._results[self._current_results[0]].river.reach(0)
self._slider_time = self.find(QSlider, f"horizontalSlider_time")
self._slider_time.setMaximum(len(self._timestamps) - 1)
@@ -181,6 +196,7 @@ class ResultsWindow(PamhyrWindow):
results=self._results,
reach_id=0,
profile_id=0,
res_id=self._current_results,
trad=self._trad,
toolbar=self.toolbar,
display_current=True,
@@ -205,8 +221,10 @@ class ResultsWindow(PamhyrWindow):
results=self._results,
reach_id=0,
profile_id=0,
res_id=self._current_results,
trad=self._trad,
toolbar=self.toolbar_2
toolbar=self.toolbar_2,
parent=self
)
self.plot_rkc.draw()
@@ -227,8 +245,10 @@ class ResultsWindow(PamhyrWindow):
results=self._results,
reach_id=0,
profile_id=0,
res_id=self._current_results,
trad=self._trad,
toolbar=self.toolbar_3
toolbar=self.toolbar_3,
parent=self
)
self.plot_ac.draw()
@@ -250,8 +270,10 @@ class ResultsWindow(PamhyrWindow):
results=self._results,
reach_id=0,
profile_id=0,
res_id=self._current_results,
trad=self._trad,
toolbar=self.toolbar_4
toolbar=self.toolbar_4,
parent=self
)
self.plot_h.draw()
@@ -314,6 +336,9 @@ class ResultsWindow(PamhyrWindow):
# "action_export": self.export_current,
}
if len(self._results) > 1:
self.find(QAction, "action_reload").setEnabled(False)
for action in actions:
self.find(QAction, action).triggered.connect(
actions[action]
@@ -324,9 +349,10 @@ class ResultsWindow(PamhyrWindow):
"reach": self._set_current_reach,
"profile": self._set_current_profile,
"raw_data": self._set_current_profile_raw_data,
"solver": self._set_current_results,
}
for t in ["reach", "profile", "raw_data"]:
for t in ["reach", "profile", "raw_data", "solver"]:
table = self.find(QTableView, f"tableView_{t}")
table.selectionModel()\
@@ -374,7 +400,25 @@ class ResultsWindow(PamhyrWindow):
)
table.scrollTo(index)
def update(self, reach_id=None, profile_id=None, timestamp=None):
def update_table_selection_solver(self, ind):
table = self.find(QTableView, f"tableView_solver")
selectionModel = table.selectionModel()
index = table.model().index(ind, 0)
selectionModel.select(
index,
QItemSelectionModel.Rows |
QItemSelectionModel.ClearAndSelect |
QItemSelectionModel.Select
)
table.scrollTo(index)
def update(self,
reach_id=None,
profile_id=None,
solver_id=None,
timestamp=None):
if reach_id is not None:
self.plot_xy.set_reach(reach_id)
self.plot_ac.set_reach(reach_id)
@@ -398,6 +442,16 @@ class ResultsWindow(PamhyrWindow):
self.update_table_selection_profile(profile_id)
if solver_id is not None:
self._current_results = solver_id
self.plot_xy.set_result(solver_id)
self.plot_ac.set_result(solver_id)
self.plot_rkc.set_result(solver_id)
self.plot_h.set_result(solver_id)
for plot in self._additional_plot:
self._additional_plot[plot].set_result(solver_id)
if timestamp is not None:
self.plot_xy.set_timestamp(timestamp)
self.plot_ac.set_timestamp(timestamp)
@@ -450,13 +504,15 @@ class ResultsWindow(PamhyrWindow):
self.update(profile_id=ind)
def _set_current_profile_raw_data(self):
table = self.find(QTableView, f"tableView_raw_data")
return
def _set_current_results(self):
table = self.find(QTableView, f"tableView_solver")
indexes = table.selectedIndexes()
if len(indexes) == 0:
return
ind = indexes[0].row()
self.update(profile_id=ind)
self.update(solver_id=[i.row() for i in indexes])
def _set_current_timestamp(self):
timestamp = self._timestamps[self._slider_time.value()]
@@ -480,12 +536,13 @@ class ResultsWindow(PamhyrWindow):
def _reload(self):
logger.debug("Reload results...")
self._results = self._results.reload()
if len(self._results) == 1:
self._results[0] = self._results[0].reload()
self._timestamps = sorted(list(self._results.get("timestamps")))
self.get_timestamps()
self._reload_plots()
self._reload_slider()
self._reload_plots()
self._reload_slider()
def _add_custom_plot(self):
dlg = CustomPlotValuesSelectionDialog(parent=self)
@@ -526,6 +583,7 @@ class ResultsWindow(PamhyrWindow):
self._get_current_timestamp(),
data=self._results,
canvas=canvas,
res_id=self._current_results,
toolbar=toolbar,
parent=self,
)
@@ -541,7 +599,26 @@ class ResultsWindow(PamhyrWindow):
tab_widget.setCurrentWidget(widget)
def _copy(self):
logger.info("TODO: copy")
# focus on raw data table
if self.find(QTabWidget, f"tabWidget").currentIndex() == 0:
table = self.find(QTableView, f"tableView_raw_data")
model = self._table["raw_data"]
coltext = []
for index in sorted(table.selectionModel().selectedRows()):
row = index.row()
rowtext = []
for column in range(model.columnCount()):
i = model.createIndex(row, column)
try:
rowtext.append(model.data(i))
except AttributeError:
rowtext.append("")
coltext.append(rowtext)
self.copyTableIntoClipboard(coltext)
else:
logger.info("TODO: copy")
def _paste(self):
logger.info("TODO: paste")
@@ -589,9 +666,9 @@ class ResultsWindow(PamhyrWindow):
def _export(self):
dlg = CustomPlotValuesSelectionDialog(parent=self)
dlg = CustomExportDialog(parent=self)
if dlg.exec():
x, y, envelop = dlg.value
x, y, envelop, solver_id = dlg.value
else:
return
@@ -601,26 +678,26 @@ class ResultsWindow(PamhyrWindow):
)
self.file_dialog(
select_file="AnyFile",
callback=lambda f: self.export_to(f[0], x, y, envelop),
callback=lambda f: self.export_to(f[0], x, y, envelop, solver_id),
default_suffix=".csv",
file_filter=["CSV (*.csv)"],
)
def export_to(self, filename, x, y, envelop):
timestamps = sorted(self._results.get("timestamps"))
reach = self._results.river.reachs[self._get_current_reach()]
first_line = [f"Study: {self._results.study.name}",
def export_to(self, filename, x, y, envelop, solver_id):
results = self._results[solver_id]
reach = results.river.reachs[self._get_current_reach()]
first_line = [f"Study: {results.study.name}",
f"Reach: {reach.name}"]
if x == "rk":
timestamp = self._get_current_timestamp()
first_line.append(f"Time: {timestamp}s")
val_dict = self._export_rk(timestamp, y, envelop)
val_dict = self._export_rk(timestamp, y, envelop, solver_id)
elif x == "time":
profile_id = self._get_current_profile()
profile = reach.profile(profile_id)
pname = profile.name if profile.name != "" else profile.rk
first_line.append(f"Profile: {pname}")
val_dict = self._export_time(profile_id, y)
val_dict = self._export_time(profile_id, y, solver_id)
with open(filename, 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',',
@@ -667,7 +744,8 @@ class ResultsWindow(PamhyrWindow):
)
def export_current_to(self, directory):
reach = self._results.river.reachs[self._get_current_reach()]
results = self._results[self._current_results]
reach = results.river.reachs[self._get_current_reach()]
self.export_all(reach, directory, [self._get_current_timestamp()])
def delete_tab(self, index):
@@ -675,16 +753,32 @@ class ResultsWindow(PamhyrWindow):
self._additional_plot.pop(tab_widget.tabText(index))
tab_widget.removeTab(index)
def _export_rk(self, timestamp, y, envelop):
reach = self._results.river.reachs[self._get_current_reach()]
def _export_rk(self, timestamp, y, envelop, solver_id):
results = self._results[solver_id]
reach = results.river.reachs[self._get_current_reach()]
dict_x = self._trad.get_dict("values_x")
dict_y = self._trad.get_dict("values_y")
if self._current_results == 2:
envelop = False
reach1 = results[0].river.reachs[self._get_current_reach()]
reach2 = results[1].river.reachs[self._get_current_reach()]
if envelop:
dict_y.update(self._trad.get_dict("values_y_envelop"))
my_dict = {}
my_dict[dict_x["rk"]] = reach.geometry.get_rk()
if "bed_elevation" in y:
my_dict[dict_y["bed_elevation"]] = reach.geometry.get_z_min()
if self._current_results != 2:
zmin = reach.geometry.get_z_min()
else:
z_min1 = reach1.geometry.get_z_min()
z_min2 = reach2.geometry.get_z_min()
zmin = list(
map(
lambda x, y: x - y,
z_min2, z_min2
)
)
my_dict[dict_y["bed_elevation"]] = zmin
# if envelop and reach.has_sediment():
if "discharge" in y:
my_dict[dict_y["discharge"]] = list(
@@ -744,13 +838,36 @@ class ResultsWindow(PamhyrWindow):
my_dict[dict_y["max_velocity"]] = [max(v) for v in velocities]
if "depth" in y:
my_dict[dict_y["depth"]] = list(
map(
lambda p: p.geometry.max_water_depth(
p.get_ts_key(timestamp, "Z")),
reach.profiles
if self._current_results != 2:
d = my_dict[dict_y["depth"]] = list(
map(
lambda p: p.geometry.max_water_depth(
p.get_ts_key(timestamp, "Z")),
reach.profiles
)
)
)
else:
d1 = list(
map(
lambda p: p.geometry.max_water_depth(
p.get_ts_key(timestamp, "Z")),
reach1.profiles
)
)
d2 = list(
map(
lambda p: p.geometry.max_water_depth(
p.get_ts_key(timestamp, "Z")),
reach2.profiles
)
)
d = list(
map(
lambda x, y: x - y,
d1, d2
)
)
my_dict[dict_y["depth"]] = d
if envelop:
my_dict[dict_y["min_depth"]] = list(map(
lambda p1, p2: p1 - p2, map(
@@ -768,53 +885,157 @@ class ResultsWindow(PamhyrWindow):
)
if "mean_depth" in y:
my_dict[dict_y["mean_depth"]] = list(
map(
lambda p: p.geometry.mean_water_depth(
p.get_ts_key(timestamp, "Z")),
reach.profiles
if self._current_results != 2:
d = list(
map(
lambda p: p.geometry.mean_water_depth(
p.get_ts_key(timestamp, "Z")),
reach.profiles
)
)
)
else:
d1 = list(
map(
lambda p: p.geometry.mean_water_depth(
p.get_ts_key(timestamp, "Z")),
reach1.profiles
)
)
d2 = list(
map(
lambda p: p.geometry.mean_water_depth(
p.get_ts_key(timestamp, "Z")),
reach2.profiles
)
)
d = list(
map(
lambda x, y: x - y,
d1, d2
)
)
my_dict[dict_y["mean_depth"]] = d
if "froude" in y:
my_dict[dict_y["froude"]] = list(
map(
lambda p:
p.get_ts_key(timestamp, "V") /
sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
p.get_ts_key(timestamp, "Z"))
)),
reach.profiles
if self._current_results != 2:
fr = my_dict[dict_y["froude"]] = list(
map(
lambda p:
p.get_ts_key(timestamp, "V") /
sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
p.get_ts_key(timestamp, "Z"))
)),
reach.profiles
)
)
)
else:
fr1 = list(
map(
lambda p:
p.get_ts_key(timestamp, "V") /
sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
p.get_ts_key(timestamp, "Z"))
)),
reach1.profiles
)
)
fr2 = list(
map(
lambda p:
p.get_ts_key(timestamp, "V") /
sqrt(9.81 * (
p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")) /
p.geometry.wet_width(
p.get_ts_key(timestamp, "Z"))
)),
reach2.profiles
)
)
fr = list(
map(
lambda x, y: x - y,
fr1, fr2
)
)
my_dict[dict_y["froude"]] = fr
if "wet_area" in y:
my_dict[dict_y["wet_area"]] = list(
map(
lambda p: p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")),
reach.profiles
if self._current_results != 2:
wa = list(
map(
lambda p: p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")),
reach.profiles
)
)
)
else:
wa1 = list(
map(
lambda p: p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")),
reach1.profiles
)
)
wa2 = list(
map(
lambda p: p.geometry.wet_area(
p.get_ts_key(timestamp, "Z")),
reach2.profiles
)
)
wa = list(
map(
lambda x, y: x - y,
wa1, wa2
)
)
my_dict[dict_y["wet_area"]] = wa
return my_dict
def _export_time(self, profile, y):
reach = self._results.river.reachs[self._get_current_reach()]
def _export_time(self, profile, y, solver_id):
results = self._results[solver_id]
reach = results.river.reachs[self._get_current_reach()]
profile = reach.profile(profile)
ts = list(self._results.get("timestamps"))
ts.sort()
dict_x = self._trad.get_dict("values_x")
dict_y = self._trad.get_dict("values_y")
my_dict = {}
my_dict[dict_x["time"]] = ts
my_dict[dict_x["time"]] = self._timestamps
z = profile.get_key("Z")
q = profile.get_key("Q")
v = profile.get_key("V")
if self._current_results == 2:
reach1 = self._results[0].river.reach(self._reach)
reach2 = self._results[1].river.reach(self._reach)
profile1 = reach1.profile(self._profile)
profile2 = reach2.profile(self._profile)
q1 = profile1.get_key("Q")
z1 = profile1.get_key("Z")
v1 = profile1.get_key("V")
q2 = profile2.get_key("Q")
z2 = profile2.get_key("Z")
v2 = profile2.get_key("V")
if "bed_elevation" in y:
my_dict[dict_y["bed_elevation"]] = [
profile.geometry.z_min()] * len(ts)
if self._current_results != 2:
z_min = [profile.geometry.z_min()] * len(self._timestamps)
else:
z_min1 = profile1.geometry.z_min()
z_min2 = profile2.geometry.z_min()
z_min = list(
map(
lambda ts: z_min1 - z_min2,
self._timestamps
)
)
my_dict[dict_y["bed_elevation"]] = z_min
if "discharge" in y:
my_dict[dict_y["discharge"]] = q
if "water_elevation" in y:
@@ -822,24 +1043,97 @@ class ResultsWindow(PamhyrWindow):
if "velocity" in y:
my_dict[dict_y["velocity"]] = v
if "depth" in y:
my_dict[dict_y["depth"]] = list(
map(lambda z: profile.geometry.max_water_depth(z), z)
)
if "mean_depth" in y:
my_dict[dict_y["mean_depth"]] = list(
map(lambda z: profile.geometry.mean_water_depth(z), z)
)
if "froude" in y:
my_dict[dict_y["froude"]] = list(
map(lambda z, v:
v / sqrt(9.81 * (
profile.geometry.wet_area(z) /
profile.geometry.wet_width(z))
), z, v)
if self._current_results != 2:
d = list(
map(lambda z: profile.geometry.max_water_depth(z), z)
)
else:
d1 = list(
map(lambda z: profile1.geometry.max_water_depth(z), z1)
)
d2 = list(
map(lambda z: profile2.geometry.max_water_depth(z), z2)
)
d = list(
map(
lambda x, y: x - y,
d1, d2
)
)
my_dict[dict_y["depth"]] = d
if "mean_depth" in y:
if self._current_results != 2:
d = list(
map(lambda z: profile.geometry.mean_water_depth(z), z)
)
else:
d1 = list(
map(lambda z: profile1.geometry.mean_water_depth(z), z1)
)
d2 = list(
map(lambda z: profile2.geometry.mean_water_depth(z), z2)
)
d = list(
map(
lambda x, y: x - y,
d1, d2
)
)
my_dict[dict_y["mean_depth"]] = d
if "froude" in y:
if self._current_results != 2:
fr = my_dict[dict_y["froude"]] = list(
map(lambda z, v:
v / sqrt(9.81 * (
profile.geometry.wet_area(z) /
profile.geometry.wet_width(z))
), z, v)
)
else:
fr1 = list(
map(lambda z, v:
v /
sqrt(9.81 * (
profile1.geometry.wet_area(z) /
profile1.geometry.wet_width(z))
), z1, v1)
)
fr2 = list(
map(lambda z, v:
v /
sqrt(9.81 * (
profile2.geometry.wet_area(z) /
profile2.geometry.wet_width(z))
), z2, v2)
)
fr = list(
map(
lambda x, y: x - y,
fr1, fr2
)
)
my_dict[dict_y["froude"]] = fr
if "wet_area" in y:
my_dict[dict_y["wet_area"]] = list(
map(lambda z: profile.geometry.wet_area(z), z)
)
if self._current_results != 2:
wa = list(
map(lambda z: profile.geometry.wet_area(z), z)
)
else:
wa1 = list(
map(lambda z: profile1.geometry.wet_area(z), z1)
)
wa2 = list(
map(lambda z: profile2.geometry.wet_area(z), z2)
)
wa = list(
map(
lambda x, y: x - y,
wa1, wa2
)
)
my_dict[dict_y["wet_area"]] = wa
return my_dict
def get_timestamps(self):
self._timestamps = sorted(list(self._results[0].get("timestamps")))
+26 -13
View File
@@ -49,7 +49,7 @@ from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
from View.Results.PlotSedAdis import PlotAdis_dx, PlotAdis_dt
from View.Results.CustomPlot.Plot import CustomPlot
from View.Results.CustomExportAdis import (
from View.Results.CustomExport.CustomExportAdis import (
CustomExportAdisDialog,
)
@@ -98,7 +98,8 @@ class ResultsWindowAdisTS(PamhyrWindow):
)
self._hash_data.append(self._solver)
self._hash_data.append(self._results)
self._hash_data.append(self._results._repertory)
self._hash_data.append(self._results._name)
self._additional_plot = {}
self._current_pol_id = [1]
@@ -380,8 +381,8 @@ class ResultsWindowAdisTS(PamhyrWindow):
self._results.pollutants_list[i.row()+1] for i in indexes
]
return (f"Reach: {reach.name} | " +
f"Profile: {pname} | " +
return (f"{self._trad['reach']}: {reach.name} | " +
f"{self._trad['cross_section']}: {pname} | " +
f"Pollutant: {', '.join(self.pollutant_label)} | " +
f"{self._trad['unit_time_s']} : {fts} ({ts} sec)")
@@ -554,14 +555,7 @@ class ResultsWindowAdisTS(PamhyrWindow):
self.update(pol_id=rows)
def _set_current_profile_raw_data(self):
table = self.find(QTableView, f"tableView_raw_data")
indexes = table.selectedIndexes()
if len(indexes) == 0:
return
ind = indexes[0].row()
self.update(profile_id=ind)
self._slider_profile.setValue(ind)
return
def _set_current_timestamp(self):
timestamp = self._timestamps[self._slider_time.value()]
@@ -597,7 +591,26 @@ class ResultsWindowAdisTS(PamhyrWindow):
self._reload_slider()
def _copy(self):
logger.info("TODO: copy")
# focus on raw data table
if self.find(QTabWidget, f"tabWidget").currentIndex() == 0:
table = self.find(QTableView, f"tableView_raw_data")
model = self._table["raw_data"]
coltext = []
for index in sorted(table.selectionModel().selectedRows()):
row = index.row()
rowtext = []
for column in range(model.columnCount()):
i = model.createIndex(row, column)
try:
rowtext.append(str(model.data(i)))
except AttributeError:
rowtext.append("")
coltext.append(rowtext)
self.copyTableIntoClipboard(coltext)
else:
logger.info("TODO: copy")
def _paste(self):
logger.info("TODO: paste")
+42 -2
View File
@@ -42,7 +42,8 @@ class ResultsTranslate(MainTranslate):
self._dict['day'] = _translate("Results", "day")
self._dict['days'] = _translate("Results", "days")
self._dict['envelop'] = _translate("Results", "envelop")
self._dict['envelop'] = _translate("Results", "Envelop")
self._dict['solver'] = _translate("Results", "Solver")
self._dict['x'] = _translate("Results", "X (m)")
@@ -62,10 +63,14 @@ class ResultsTranslate(MainTranslate):
}
self._sub_dict["table_headers_profile"] = {
"name": self._dict["name"],
"name": _translate("Results", "Profile name"),
"rk": self._dict["unit_rk"],
}
self._sub_dict["table_headers_solver"] = {
"solver": self._dict['solver'],
}
self._sub_dict["table_headers_pollutants"] = {
"name": _translate("Results", "Pollutant name"),
}
@@ -134,3 +139,38 @@ class ResultsTranslate(MainTranslate):
"unit_M": self._dict["unit_mass"],
"unit_thickness": self._dict["unit_thickness"],
}
class CompareResultsTranslate(ResultsTranslate):
def __init__(self):
super(CompareResultsTranslate, self).__init__()
self._dict['label_water'] = u"Δ "+_translate(
"Results", "Water elevation"
)
self._dict['unit_elevation'] = u"Δ "+self._dict["unit_elevation"]
self._sub_dict["table_headers_raw_data"] = {
"name": _translate("Results", "Profile"),
"water_elevation": u"Δ "+self._dict["unit_water_elevation"],
"discharge": u"Δ "+self._dict["unit_discharge"],
"velocity": u"Δ "+self._dict["unit_velocity"],
"width": u"Δ "+self._dict["unit_width"],
"depth": u"Δ "+self._dict["unit_depth"],
"mean_depth": u"Δ "+self._dict["unit_mean_depth"],
"wet_area": u"Δ "+self._dict["unit_wet_area"],
"wet_perimeter": u"Δ "+self._dict["unit_wet_perimeter"],
"hydraulic_radius": u"Δ "+self._dict["unit_hydraulic_radius"],
"froude": u"Δ "+self._dict["unit_froude"],
}
self._sub_dict["values_y"] = {
"bed_elevation": u"Δ "+self._dict["unit_bed_elevation"],
"water_elevation": u"Δ "+self._dict["unit_water_elevation"],
"discharge": u"Δ "+self._dict["unit_discharge"],
"velocity": u"Δ "+self._dict["unit_velocity"],
"depth": u"Δ "+self._dict["unit_depth"],
"mean_depth": u"Δ "+self._dict["unit_mean_depth"],
"froude": u"Δ "+self._dict["unit_froude"],
"wet_area": u"Δ "+self._dict["unit_wet_area"],
}
+101
View File
@@ -138,6 +138,107 @@ class SelectSolverWindow(PamhyrDialog):
super(SelectSolverWindow, self).accept()
class CompareSolversWindow(PamhyrDialog):
_pamhyr_ui = "CompareSolvers"
_pamhyr_name = "Compare solvers"
def __init__(self, study=None, config=None,
parent=None):
self._solver1 = None
self._solver2 = None
name = _translate("Solver", "Compare solvers")
super(CompareSolversWindow, self).__init__(
title=name,
study=study,
config=config,
options=[],
parent=parent
)
self.setup_combobox1()
self.setup_combobox2()
self.setup_connections()
self.select_last_solver()
def setup_combobox1(self):
solvers = self._config.solvers
solvers_name = list(
map(
self._format_solver_name,
solvers
)
)
self.combobox_add_items("comboBox1", solvers_name)
def setup_combobox2(self):
solvers = self._config.solvers
solvers_name = list(
map(
self._format_solver_name,
solvers
)
)
self.combobox_add_items("comboBox2", solvers_name)
def setup_connections(self):
self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
self.find(QPushButton, "pushButton_cancel")\
.clicked.connect(self.reject)
def select_last_solver(self):
solvers = self._config.solvers
last = self._config.last_solver_name
solver = list(
filter(
lambda s: s.name == last,
solvers
)
)
if len(solver) != 0:
self.set_combobox_text(
"comboBox1",
self._format_solver_name(solver[0])
)
def _format_solver_name(self, solver):
return f"{solver.name} - ({solver._type})"
@property
def solver1(self):
return self._solver1
@property
def solver2(self):
return self._solver2
def accept(self):
solver_name1 = self.get_combobox_text("comboBox1")
solver_name1 = solver_name1.rsplit(" - ", 1)[0]
self._solver1 = next(
filter(
lambda s: s.name == solver_name1,
self._config.solvers
)
)
solver_name2 = self.get_combobox_text("comboBox2")
solver_name2 = solver_name2.rsplit(" - ", 1)[0]
self._solver2 = next(
filter(
lambda s: s.name == solver_name2,
self._config.solvers
)
)
super(CompareSolversWindow, self).accept()
class SolverLogWindow(PamhyrWindow):
_pamhyr_ui = "SolverLog"
_pamhyr_name = "Solver Log"
+7 -1
View File
@@ -414,9 +414,15 @@ class SolverLogWindowAdisTS(PamhyrWindow):
def results(self):
if self._results is None:
dir_list = os.listdir(self._workdir)
if "resultats" in dir_list:
dir_path = os.path.join(self._workdir, "resultats")
else:
dir_path = self._workdir
def reading_fn():
self._results = self._solver.results(
self._study, self._workdir, qlog=self._output
self._study, dir_path, qlog=self._output
)
dlg = ReadingResultsDialog(reading_fn=reading_fn, parent=self)
+8 -11
View File
@@ -106,17 +106,15 @@ class UnitTranslate(CommonWordTranslate):
self._dict["unit_min_velocity"] = _translate(
"Unit", "Min Velocity (m/s)"
)
self._dict["unit_discharge"] = _translate("Unit", "Discharge (m^3/s)")
self._dict["unit_discharge"] = _translate(
"Unit", "Discharge") + f" (m³/s)"
self._dict["unit_discharge_envelop"] = _translate(
"Unit", "Discharge Envelop (m^3/s)"
)
"Unit", "Discharge Envelop") + " (m³/s)"
self._dict["unit_max_discharge"] = _translate(
"Unit", "Max Discharge (m^3/s)"
)
"Unit", "Max Discharge") + " (m³/s)"
self._dict["unit_min_discharge"] = _translate(
"Unit", "Min Discharge (m^3/s)"
)
self._dict["unit_area"] = _translate("Unit", "Area (hectare)")
"Unit", "Min Discharge") + " (m³/s)"
self._dict["unit_area_he"] = _translate("Unit", "Area (hectare)")
self._dict["unit_time_s"] = _translate("Unit", "Time (sec)")
self._dict["unit_time_p"] = _translate("Unit", "Time (JJJ:HH:MM:SS)")
@@ -136,7 +134,7 @@ class UnitTranslate(CommonWordTranslate):
self._dict["unit_concentration"] = _translate(
"Unit", "Concentration (g/l)"
)
self._dict["unit_wet_area"] = _translate("Unit", "Wet Area (m²)")
self._dict["unit_wet_area"] = _translate("Unit", "Wet Area") + " (m²)"
self._dict["unit_wet_perimeter"] = _translate(
"Unit", "Wet Perimeter (m)"
)
@@ -146,8 +144,7 @@ class UnitTranslate(CommonWordTranslate):
self._dict["unit_froude"] = _translate("Unit", "Froude number")
self._dict["unit_mass"] = _translate("Unit", "Mass (kg)")
self._dict["unit_concentration"] = _translate(
"Unit", "Concentration (kg/m^3)"
)
"Unit", "Concentration") + " (kg/m³)"
class MainTranslate(UnitTranslate):
+61
View File
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>80</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QComboBox" name="comboBox1"/>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_ok">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="comboBox2"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+6
View File
@@ -161,6 +161,7 @@
</property>
<addaction name="action_menu_results_last"/>
<addaction name="action_open_results_from_file"/>
<addaction name="action_compare_results"/>
<addaction name="action_open_results_adists"/>
</widget>
<widget class="QMenu" name="menu_help">
@@ -774,6 +775,11 @@
<string>DIF</string>
</property>
</action>
<action name="action_compare_results">
<property name="text">
<string>Compare results</string>
</property>
</action>
<action name="action_open_results_adists">
<property name="enabled">
<bool>false</bool>
+7
View File
@@ -41,6 +41,13 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QTableView" name="tableView_solver"/>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
+1 -4
View File
@@ -46,9 +46,6 @@
<item>
<widget class="QTableView" name="tableView_pollutants"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_tot_left"/>
</item>
</layout>
</widget>
</widget>
@@ -457,7 +454,7 @@
<resources/>
<connections/>
<buttongroups>
<buttongroup name="buttonGroup"/>
<buttongroup name="buttonGroup_2"/>
<buttongroup name="buttonGroup"/>
</buttongroups>
</ui>
+189 -234
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.