mirror of https://gitlab.com/pamhyr/pamhyr2
Merge branch 'terraz_dev' into adists_release
commit
1266884f93
|
|
@ -41,6 +41,9 @@ __old__
|
||||||
|
|
||||||
*-venv
|
*-venv
|
||||||
|
|
||||||
|
mage8
|
||||||
|
adists
|
||||||
|
|
||||||
### END CUSTOM ###
|
### END CUSTOM ###
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||||
|
|
|
||||||
|
|
@ -28,20 +28,6 @@
|
||||||
#+OPTIONS: toc:t
|
#+OPTIONS: toc:t
|
||||||
#+LANGUAGE: UKenglish
|
#+LANGUAGE: UKenglish
|
||||||
|
|
||||||
#+NAME: attr_wrap
|
|
||||||
#+HEADER: :var width="\\textwidth"
|
|
||||||
#+HEADER: :var caption=""
|
|
||||||
#+HEADER: :var smallcaption=""
|
|
||||||
#+HEADER: :var name=""
|
|
||||||
#+HEADER: :var data=""
|
|
||||||
#+HEADER: :var float="nil"
|
|
||||||
#+BEGIN_SRC sh :results output :exports none
|
|
||||||
echo "#+CAPTION[$smallcaption]: $caption"
|
|
||||||
echo "#+NAME: $name"
|
|
||||||
echo "#+ATTR_LATEX: :width $width :float $float"
|
|
||||||
echo "$data"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
#+BEGIN_abstract
|
#+BEGIN_abstract
|
||||||
This document is for the use of developers. It describes the project
|
This document is for the use of developers. It describes the project
|
||||||
architecture, the tools available to assist development and
|
architecture, the tools available to assist development and
|
||||||
|
|
@ -54,13 +40,13 @@ documentation, translations or code.
|
||||||
|
|
||||||
* Introduction
|
* Introduction
|
||||||
|
|
||||||
Pamhyr2 is free and open source software (FOSS) graphical user
|
{{{pamhyr2}}} is free and open source software (FOSS) graphical user
|
||||||
interface (GUI) for 1D hydro-sedimentary modelling of rivers developed
|
interface (GUI) for 1D hydro-sedimentary modelling of rivers developed
|
||||||
in Python (with version 3.8). It use PyQt at version 5 and matplotlib
|
in Python (with version 3.8). It use PyQt at version 5 and matplotlib
|
||||||
in version 3.4.1 or later for the user insterface (see
|
in version 3.4.1 or later for the user insterface (see
|
||||||
{{{file(/requirements.txt)}}} for details). The architecture of
|
{{{file(/requirements.txt)}}} for details). The architecture of
|
||||||
project code follow the Qt Model/View architecture [fn:qt-arch] (see
|
project code follow the Qt Model/View architecture [fn:qt-arch] (see
|
||||||
details in section [[Architecture]]). Pamhyr2 packages can be build
|
details in section [[Architecture]]). {{{pamhyr2}}} packages can be build
|
||||||
manually (see section [[Building packages]]), but there are automatically
|
manually (see section [[Building packages]]), but there are automatically
|
||||||
build with the gitlab-ci (see the section [[Setup the CI
|
build with the gitlab-ci (see the section [[Setup the CI
|
||||||
environment]]). Documentation files are written with org-mode[fn:org],
|
environment]]). Documentation files are written with org-mode[fn:org],
|
||||||
|
|
@ -75,7 +61,7 @@ https://doc.qt.io/qt-5/model-view-programming.html (last access
|
||||||
|
|
||||||
* Architecture
|
* Architecture
|
||||||
|
|
||||||
Pamhyr2's architecture is based on Qt Model/View, see Figure
|
{{{pamhyr2}}}'s architecture is based on Qt Model/View, see Figure
|
||||||
[[graph-architecture]]. It is made up of several different components: the
|
[[graph-architecture]]. It is made up of several different components: the
|
||||||
model (in blue), the graphical components (in red), the
|
model (in blue), the graphical components (in red), the
|
||||||
actions/delegates (in green), the commands (in purple), the solvers
|
actions/delegates (in green), the commands (in purple), the solvers
|
||||||
|
|
@ -178,7 +164,7 @@ https://doc.qt.io/qt-5/model-view-programming.html
|
||||||
|
|
||||||
** Model
|
** Model
|
||||||
|
|
||||||
The model is a set of Python classes. In Pamhyr2, this classes must
|
The model is a set of Python classes. In {{{pamhyr2}}}, this classes must
|
||||||
respect some constraint. Each model class must inherits
|
respect some constraint. Each model class must inherits
|
||||||
=Model.Tools.SQLSubModel= abstract class, except the =Model.Study=
|
=Model.Tools.SQLSubModel= abstract class, except the =Model.Study=
|
||||||
class who inherits =Model.Tools.SQLModel= (see [[SQL]]).
|
class who inherits =Model.Tools.SQLModel= (see [[SQL]]).
|
||||||
|
|
@ -456,12 +442,12 @@ of Bar (Listing [[sql-bar]] and [[sql-foo]]).
|
||||||
bar._sql_save(execute, data=data)
|
bar._sql_save(execute, data=data)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Let see the results database scheme for Pamhyr2 at version v0.0.7 in
|
Let see the results database scheme for {{{pamhyr2}}} at version v0.0.7 in
|
||||||
Figure [[sql_schema]].
|
Figure [[sql_schema]].
|
||||||
|
|
||||||
#+NAME: sql_schema
|
#+NAME: sql_schema
|
||||||
#+ATTR_LATEX: :width 16cm
|
#+ATTR_LATEX: :width 16cm
|
||||||
#+CAPTION: SQLite database scheme at Pamhyr2 version v0.0.7 (generate with [[https://gitlab.com/Screwtapello/sqlite-schema-diagram]])
|
#+CAPTION: SQLite database scheme at {{{pamhyr2}}} version v0.0.7 (generate with [[https://gitlab.com/Screwtapello/sqlite-schema-diagram]])
|
||||||
[[./images/schema_v0.0.7.png]]
|
[[./images/schema_v0.0.7.png]]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -486,7 +472,7 @@ PamhyrModelList but use a dictionary instead of list.
|
||||||
|
|
||||||
** View
|
** View
|
||||||
|
|
||||||
Pamhyr2 use Qt as graphical user interface library with the
|
{{{pamhyr2}}} use Qt as graphical user interface library with the
|
||||||
application "Qt designer" for windows or widget creation (see [[UI file]])
|
application "Qt designer" for windows or widget creation (see [[UI file]])
|
||||||
and "Qt linguist" for interface translate (see [[Translate]]). In
|
and "Qt linguist" for interface translate (see [[Translate]]). In
|
||||||
addition, we use matplotlib as ploting library (see [[Plot]]).
|
addition, we use matplotlib as ploting library (see [[Plot]]).
|
||||||
|
|
@ -501,11 +487,11 @@ componant translate, and possible other files or sub-directories.
|
||||||
|
|
||||||
*** UI file
|
*** UI file
|
||||||
|
|
||||||
We define as possible all Pamhyr2 windows and custom widgets with "Qt
|
We define as possible all {{{pamhyr2}}} windows and custom widgets
|
||||||
designer". This application generate UI file who describes interface
|
with "Qt designer". This application generate UI file who describes
|
||||||
organisation with table, layout, button, etc. This method is faster
|
interface organisation with table, layout, button, etc. This method is
|
||||||
than hand made windows and widget creation, and saves us some purely
|
faster than hand made windows and widget creation, and saves us some
|
||||||
descriptive code. The UI files are saved into =src/View/ui= for
|
purely descriptive code. The UI files are saved into =src/View/ui= for
|
||||||
window, and =/src/View/ui/Widgets= for custom widget.
|
window, and =/src/View/ui/Widgets= for custom widget.
|
||||||
|
|
||||||
*** Translate
|
*** Translate
|
||||||
|
|
@ -533,10 +519,11 @@ window, and =/src/View/ui/Widgets= for custom widget.
|
||||||
|
|
||||||
*** Window
|
*** Window
|
||||||
|
|
||||||
The abstract class PamhyrWindow and PamhyrDialog are used for most of
|
The abstract class =PamhyrWindow= and =PamhyrDialog= are used for most
|
||||||
Pamhyr2 window. These class allow to create an window for Pamhyr2 GUI
|
of {{{pamhyr2}}} window. These class allow to create an window for
|
||||||
and implemente some useful methods. The super class method difine some
|
{{{pamhyr2}}} GUI and implemente some useful methods. The super class
|
||||||
generic value from optional parameters, for examples:
|
method difine some generic value from optional parameters, for
|
||||||
|
examples:
|
||||||
- =self._study=: The study giving in constructor parameters =study=
|
- =self._study=: The study giving in constructor parameters =study=
|
||||||
(typically a =Model.Study= class object)
|
(typically a =Model.Study= class object)
|
||||||
- =self._config=: The configuration giving in constructor parameters
|
- =self._config=: The configuration giving in constructor parameters
|
||||||
|
|
@ -546,7 +533,7 @@ generic value from optional parameters, for examples:
|
||||||
object)
|
object)
|
||||||
|
|
||||||
#+NAME: window
|
#+NAME: window
|
||||||
#+CAPTION: Example of Pamhyr2 window
|
#+CAPTION: Example of {{{pamhyr2}}} window
|
||||||
#+begin_src python :python python3 :results output :noweb yes
|
#+begin_src python :python python3 :results output :noweb yes
|
||||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
from View.My.Translate import MyTranslate
|
from View.My.Translate import MyTranslate
|
||||||
|
|
@ -593,7 +580,7 @@ window componants or connections.
|
||||||
|
|
||||||
*** Table
|
*** Table
|
||||||
|
|
||||||
An abstract class PamhyrTableModel is available to define a simple
|
An abstract class =PamhyrTableModel= is available to define a simple
|
||||||
QAbstractTableModel shortly. In simple cases, there are only =data=
|
QAbstractTableModel shortly. In simple cases, there are only =data=
|
||||||
and =setData= methode to implement, but the constructor needs more
|
and =setData= methode to implement, but the constructor needs more
|
||||||
information than a classic QAbstractTableModel class.
|
information than a classic QAbstractTableModel class.
|
||||||
|
|
@ -654,7 +641,7 @@ class AddNodeCommand(QUndoCommand):
|
||||||
|
|
||||||
All undo command must be push into a =QUndoStack= (see Listing
|
All undo command must be push into a =QUndoStack= (see Listing
|
||||||
[[undo-cmd-push]]) to perform the action and allow user undo and redo this
|
[[undo-cmd-push]]) to perform the action and allow user undo and redo this
|
||||||
action. In PamhyrWindow (and PamhyrDialog) the undo stack is
|
action. In =PamhyrWindow= (and =PamhyrDialog=) the undo stack is
|
||||||
automatically create if the option ="undo"= is activate at window
|
automatically create if the option ="undo"= is activate at window
|
||||||
creation, this stack is accessible at =self._undo_stack=.
|
creation, this stack is accessible at =self._undo_stack=.
|
||||||
|
|
||||||
|
|
@ -672,7 +659,7 @@ creation, this stack is accessible at =self._undo_stack=.
|
||||||
*** Plot
|
*** Plot
|
||||||
|
|
||||||
To define a new plot you can create a class who inherit to
|
To define a new plot you can create a class who inherit to
|
||||||
PamhyrPlot. The creator need at leaste five argument:
|
=PamhyrPlot=. The creator need at leaste five argument:
|
||||||
- A =canvas= of type =MplCanvas=
|
- A =canvas= of type =MplCanvas=
|
||||||
- A (optional) =trad= of type =PamhyrTranslate=
|
- A (optional) =trad= of type =PamhyrTranslate=
|
||||||
- A =data= used in =draw= and =update= to create and update the plot
|
- A =data= used in =draw= and =update= to create and update the plot
|
||||||
|
|
@ -719,8 +706,8 @@ data has changed.
|
||||||
|
|
||||||
** Solver
|
** Solver
|
||||||
|
|
||||||
The Pamhyr2 architecture allow to define multiple solver. A solver is
|
The {{{pamhyr2}}} architecture allow to define multiple solver. A
|
||||||
define by a:
|
solver is define by a:
|
||||||
- type
|
- type
|
||||||
- name
|
- name
|
||||||
- description,
|
- description,
|
||||||
|
|
@ -736,11 +723,11 @@ different solver type, this solver type implement the code for export
|
||||||
study to solver input format, and read the solver output to study
|
study to solver input format, and read the solver output to study
|
||||||
results. There exists a generic solver with a generic input and output
|
results. There exists a generic solver with a generic input and output
|
||||||
format, the type could be use to use a solver not implemented in
|
format, the type could be use to use a solver not implemented in
|
||||||
Pamhyr2, but this solver must can read/write input and output generic
|
{{{pamhyr2}}}, but this solver must can read/write input and output
|
||||||
format or use external script. There is possible to define different
|
generic format or use external script. There is possible to define
|
||||||
solver with the same type, for example two differents version of the
|
different solver with the same type, for example two differents
|
||||||
same solver. Finaly, with input and output formater is possible to
|
version of the same solver. Finaly, with input and output formater is
|
||||||
execute a code on distant computer, for example, over ssh.
|
possible to execute a code on distant computer, for example, over ssh.
|
||||||
|
|
||||||
#+name: graph-multi-solver
|
#+name: graph-multi-solver
|
||||||
#+header: :results drawer
|
#+header: :results drawer
|
||||||
|
|
@ -857,8 +844,8 @@ solver and get results:
|
||||||
- (2.1) The solver read the input file(s)
|
- (2.1) The solver read the input file(s)
|
||||||
- (2.2) The solver compute results and write it to solver output
|
- (2.2) The solver compute results and write it to solver output
|
||||||
file(s)
|
file(s)
|
||||||
- (3) Pamhyr2 create a =Results= object
|
- (3) {{{pamhyr2}}} create a =Results= object
|
||||||
- (3.1) The Pamhyr2 solver class read solver output file(s) and
|
- (3.1) The {{{pamhyr2}}} solver class read solver output file(s) and
|
||||||
complete Results with readed data
|
complete Results with readed data
|
||||||
|
|
||||||
#+name: graph-pipeline
|
#+name: graph-pipeline
|
||||||
|
|
@ -976,7 +963,7 @@ the temporal order of action is prensented in Figure
|
||||||
}
|
}
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
To implement a Solver in Pamhyr2, there exists a abstract class
|
To implement a Solver in {{{pamhyr2}}}, there exists a abstract class
|
||||||
=Solver.AbstractSolver=. A class who herits this class, must implement
|
=Solver.AbstractSolver=. A class who herits this class, must implement
|
||||||
different methods:
|
different methods:
|
||||||
- =export=: Export the study to solver input file(s)
|
- =export=: Export the study to solver input file(s)
|
||||||
|
|
@ -987,7 +974,7 @@ different methods:
|
||||||
|
|
||||||
** Unit tests
|
** Unit tests
|
||||||
|
|
||||||
A very small part of Pamhyr2 has unit test. This part is limited to the Model.
|
A very small part of {{{pamhyr2}}} has unit test. This part is limited to the Model.
|
||||||
|
|
||||||
#+begin_src shell
|
#+begin_src shell
|
||||||
python3 -m venv test
|
python3 -m venv test
|
||||||
|
|
@ -1000,9 +987,9 @@ A very small part of Pamhyr2 has unit test. This part is limited to the Model.
|
||||||
|
|
||||||
** The debug mode
|
** The debug mode
|
||||||
|
|
||||||
To activate an deactivate the Pamhyr2 debug mode you can open the
|
To activate an deactivate the {{{pamhyr2}}} debug mode you can open
|
||||||
configuration window and type "Ctrl+G" or run Pamhyr2 with command
|
the configuration window and type "Ctrl+G" or run {{{pamhyr2}}} with
|
||||||
line:
|
command line:
|
||||||
#+begin_src shell
|
#+begin_src shell
|
||||||
./Pamhyr2 debug
|
./Pamhyr2 debug
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -1015,7 +1002,7 @@ data base file.
|
||||||
|
|
||||||
#+NAME: debug-repl
|
#+NAME: debug-repl
|
||||||
#+ATTR_LATEX: :width 14cm
|
#+ATTR_LATEX: :width 14cm
|
||||||
#+CAPTION: Pamhyr2 debug Python REPL
|
#+CAPTION: {{{pamhyr2}}} debug Python REPL
|
||||||
[[./images/python-debug-repl.png]]
|
[[./images/python-debug-repl.png]]
|
||||||
|
|
||||||
* Build the project
|
* Build the project
|
||||||
|
|
@ -1028,7 +1015,7 @@ to build packages manually.
|
||||||
If you need an hand made package, you can script available in
|
If you need an hand made package, you can script available in
|
||||||
{{{file(packages)}}} directory.
|
{{{file(packages)}}} directory.
|
||||||
|
|
||||||
*** GNU/Linux
|
*** GNU/Linux {{{linux}}}
|
||||||
|
|
||||||
On GNU/Linux building GNU/Linux packages is easy, you just need python
|
On GNU/Linux building GNU/Linux packages is easy, you just need python
|
||||||
in version 3.8 must be installed with venv and pyinstaller packages
|
in version 3.8 must be installed with venv and pyinstaller packages
|
||||||
|
|
@ -1050,7 +1037,7 @@ cd packages
|
||||||
./linux.sh
|
./linux.sh
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
*** Windows
|
*** Windows {{{windows}}}
|
||||||
|
|
||||||
To make the Windows packages you have two choice: If you use Windows
|
To make the Windows packages you have two choice: If you use Windows
|
||||||
you can use the script {{{file(packages/windows.bat)}}}, other else
|
you can use the script {{{file(packages/windows.bat)}}}, other else
|
||||||
|
|
@ -1065,10 +1052,10 @@ winetricks installed.
|
||||||
|
|
||||||
** Setup the CI environment
|
** Setup the CI environment
|
||||||
|
|
||||||
Pamhyr2 need a Linux ci-runner and a Windows ci-runner for building
|
{{{pamhyr2}}} need a Linux ci-runner and a Windows ci-runner for building
|
||||||
package. The windows ci-runner could run on a Wine environement.
|
package. The windows ci-runner could run on a Wine environement.
|
||||||
|
|
||||||
*** Linux
|
*** Linux {{{linux}}}
|
||||||
|
|
||||||
The Linux ci-runner need some software and dependencies in addtion of
|
The Linux ci-runner need some software and dependencies in addtion of
|
||||||
gitlab-ci.
|
gitlab-ci.
|
||||||
|
|
@ -1078,10 +1065,11 @@ gitlab-ci.
|
||||||
emacs emacs-goodies-el \
|
emacs emacs-goodies-el \
|
||||||
texlive-full \
|
texlive-full \
|
||||||
python3.8 python3.8-venv
|
python3.8 python3.8-venv
|
||||||
|
|
||||||
sudo python3 -m pip install pyinstaller
|
sudo python3 -m pip install pyinstaller
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
*** Windows (Wine)
|
*** Windows (Wine) {{{windows}}}
|
||||||
|
|
||||||
The ci-runner environment for Wine need at least wine version 8, let
|
The ci-runner environment for Wine need at least wine version 8, let
|
||||||
[[https://www.numetopia.fr/comment-installer-wine-sur-ubuntu-ou-linux-mint/][see who to add wine official depot to your linux distribution]].
|
[[https://www.numetopia.fr/comment-installer-wine-sur-ubuntu-ou-linux-mint/][see who to add wine official depot to your linux distribution]].
|
||||||
|
|
@ -1090,18 +1078,77 @@ The ci-runner environment for Wine need at least wine version 8, let
|
||||||
sudo apt install wine-stable winetricks
|
sudo apt install wine-stable winetricks
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
In addition, the environment need windows version of:
|
**** Setup environment
|
||||||
- [[https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe][Python 3.8.10]]
|
|
||||||
- Git
|
Export Wine environment variable to set wine as 64 bits architecture
|
||||||
- PowerShell
|
and set the correct path for wine environment.
|
||||||
- Gitlab-ci
|
|
||||||
|
#+begin_src shell
|
||||||
|
export WINARCH=win64
|
||||||
|
export WINEPREFIX=$PWD/my-wine-runner-prefix
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Setup Wine environment to Windows 10 and install the minimal fonts
|
||||||
|
with =winetricks=.
|
||||||
|
|
||||||
|
#+begin_src shell
|
||||||
|
winetricks corefonts win10
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Install dependencies
|
||||||
|
|
||||||
|
First install 7zip with help of =winetricks=.
|
||||||
|
|
||||||
|
#+begin_src shell
|
||||||
|
winetricks 7zip
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
In addition, install in the environment the Windows version of:
|
||||||
|
- [[https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe][Python 3.8.10]] (ensure the python path is set and Pip is enable)
|
||||||
|
- [[https://git-scm.com/downloads][Git]]
|
||||||
|
- [[https://github.com/PowerShell/PowerShell/releases/download/v7.0.1/PowerShell-7.0.1-win-x64.msi][PowerShell]]
|
||||||
- [[https://freefr.dl.sourceforge.net/project/nsis/NSIS%203/3.08/nsis-3.08-setup.exe][Nsis]]
|
- [[https://freefr.dl.sourceforge.net/project/nsis/NSIS%203/3.08/nsis-3.08-setup.exe][Nsis]]
|
||||||
|
|
||||||
|
To run a Windows executable into wine environement, use =wine64= command:
|
||||||
|
|
||||||
|
#+begin_src shell
|
||||||
|
wine64 <the-exe-file>
|
||||||
|
#+end_src
|
||||||
|
|
||||||
Now, we can install =pyinstaller= on this windows environment:
|
Now, we can install =pyinstaller= on this windows environment:
|
||||||
#+begin_src shell
|
#+begin_src shell
|
||||||
wine python -m pip install pyinstaller
|
wine python -m pip install pyinstaller
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
Now, we can download [[https://docs.gitlab.com/runner/install/windows.html][Gitlab-ci]] runner for Windows an put it in the
|
||||||
|
current path.
|
||||||
|
|
||||||
|
**** Setup runner
|
||||||
|
|
||||||
|
You can configure the runner with command:
|
||||||
|
|
||||||
|
#+begin_src shell
|
||||||
|
wine64 gitlab-runner-windows-amd64.exe register
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Run the runner
|
||||||
|
|
||||||
|
Create a new executable shell script =runner.sh= with following lines:
|
||||||
|
|
||||||
|
#+begin_src shell
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
export WINARCH=win64
|
||||||
|
export WINEPREFIX=$PWD/my-wine-runner-prefix
|
||||||
|
|
||||||
|
wine64 gitlab-runner-windows-amd64.exe run
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Now you can run the runner with command =./runner.sh=.
|
||||||
|
|
||||||
|
{{{bulb}}} You can run this command into a =screen= terminal, detach
|
||||||
|
the terminal and disconnect from runner machine to keep runner alive.
|
||||||
|
|
||||||
* Documentation files
|
* Documentation files
|
||||||
|
|
||||||
This document and the user documentation are org files. This text file
|
This document and the user documentation are org files. This text file
|
||||||
|
|
@ -1284,23 +1331,23 @@ Some org-mode configuration used in documentations files are define in
|
||||||
|
|
||||||
* How to contribute?
|
* How to contribute?
|
||||||
|
|
||||||
Pamhyr2 is free software: you can redistribute it and/or modify it
|
{{{pamhyr2}}} is free software: you can redistribute it and/or modify
|
||||||
under the terms of the GNU General Public License[fn:license], either
|
it under the terms of the GNU General Public License[fn:license],
|
||||||
version 3 of the License, or any later version.
|
either version 3 of the License, or any later version.
|
||||||
|
|
||||||
[fn:license] The GPLv3 web page:
|
[fn:license] The GPLv3 web page:
|
||||||
https://www.gnu.org/licenses/gpl-3.0.en.html
|
https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
|
||||||
** Guidelines
|
** Guidelines
|
||||||
|
|
||||||
To contribute to Pamhyr2, we expect a minimum of respect between
|
To contribute to {{{pamhyr2}}}, we expect a minimum of respect between
|
||||||
contributors. We therefore ask you to respect the following rules
|
contributors. We therefore ask you to respect the following rules
|
||||||
regarding communication and contribution content:
|
regarding communication and contribution content:
|
||||||
+ No gender, racial, religious or social discrimination
|
+ No gender, racial, religious or social discrimination
|
||||||
+ No insults, personal attacks or potentially offensive remarks
|
+ No insults, personal attacks or potentially offensive remarks
|
||||||
+ Pamhyr2 is free software, and intended to remain so, so take care
|
+ {{{pamhyr2}}} is free software, and intended to remain so, so take
|
||||||
with the licensing of libraries and external content you want to add
|
care with the licensing of libraries and external content you want
|
||||||
to the project
|
to add to the project
|
||||||
+ Humour or hidden easter eggs are welcome if they respect the
|
+ Humour or hidden easter eggs are welcome if they respect the
|
||||||
previous rules
|
previous rules
|
||||||
|
|
||||||
|
|
@ -1311,11 +1358,12 @@ an issue on the project's gitlab page[fn:p2-gitlab], or you can create
|
||||||
a merge request on the same page with the changes you have made to the
|
a merge request on the same page with the changes you have made to the
|
||||||
code, translation or documentation.
|
code, translation or documentation.
|
||||||
|
|
||||||
The Pamhyr2 copyright is owned by INRAE[fn:inrae], but we keep a
|
The {{{pamhyr2}}} copyright is owned by INRAE[fn:inrae], but we keep a
|
||||||
record of each contributors. If you made a modification to pamhyr2
|
record of each contributors. If you made a modification to
|
||||||
software, please add your name at the end of {{{file(AUTHORS)}}} file
|
{{{pamhyr2}}} software, please add your name at the end of
|
||||||
and respect the Listing [[auth-format]] format. You can update this file
|
{{{file(AUTHORS)}}} file and respect the Listing [[auth-format]]
|
||||||
information for following contribution.
|
format. You can update this file information for following
|
||||||
|
contribution.
|
||||||
|
|
||||||
#+NAME: auth-format
|
#+NAME: auth-format
|
||||||
#+CAPTION: =AUTHORS= file format
|
#+CAPTION: =AUTHORS= file format
|
||||||
|
|
@ -1326,16 +1374,17 @@ information for following contribution.
|
||||||
#+CAPTION: Current =AUTHORS= file
|
#+CAPTION: Current =AUTHORS= file
|
||||||
#+INCLUDE: "../../AUTHORS" src text
|
#+INCLUDE: "../../AUTHORS" src text
|
||||||
|
|
||||||
[fn:p2-gitlab] The Pamhyr2 Gitlab project page:
|
[fn:p2-gitlab] The {{{pamhyr2}}} Gitlab project page:
|
||||||
https://gitlab.irstea.fr/theophile.terraz/pamhyr
|
https://gitlab.irstea.fr/theophile.terraz/pamhyr
|
||||||
[fn:inrae] The INRAE web site: https://www.inrae.fr/
|
[fn:inrae] The INRAE web site: https://www.inrae.fr/
|
||||||
|
|
||||||
** Translate
|
** Translate
|
||||||
|
|
||||||
You can improve or add translation for the project. To contribute to
|
You can improve or add translation for the project. To contribute to
|
||||||
Pamhyr2 translate, you need to use Qt Linguist[fn:qt-linguist]. Open
|
{{{pamhyr2}}} translate, you need to use Qt
|
||||||
Qt-linguist and edit the translation ({{{file(.ts)}}}) file, finally,
|
Linguist[fn:qt-linguist]. Open Qt-linguist and edit the translation
|
||||||
commit the new version of file and make a merge request.
|
({{{file(.ts)}}}) file, finally, commit the new version of file and
|
||||||
|
make a merge request.
|
||||||
|
|
||||||
If you want add a new language, edit the script
|
If you want add a new language, edit the script
|
||||||
{{{file(src/lang/create_ts.sh)}}} like Listing [[ts-it]]. Run the script
|
{{{file(src/lang/create_ts.sh)}}} like Listing [[ts-it]]. Run the script
|
||||||
|
|
@ -1344,7 +1393,7 @@ and open the new file with Qt-linguist, setup target language (Figure
|
||||||
file and make a merge request.
|
file and make a merge request.
|
||||||
|
|
||||||
#+NAME: ts-it
|
#+NAME: ts-it
|
||||||
#+CAPTION: Example of modified {{{file(src/lang/create_ts.sh)}}} to add italian (it) translate for Pamhyr2
|
#+CAPTION: Example of modified {{{file(src/lang/create_ts.sh)}}} to add italian (it) translate for {{{pamhyr2}}}
|
||||||
#+begin_src shell
|
#+begin_src shell
|
||||||
...
|
...
|
||||||
LANG="fr it"
|
LANG="fr it"
|
||||||
|
|
@ -1362,7 +1411,7 @@ https://doc.qt.io/qt-5/qtlinguist-index.html (last access 2023-09-18)
|
||||||
** Code contribution
|
** Code contribution
|
||||||
|
|
||||||
If you are developper you can improve and/or add features to
|
If you are developper you can improve and/or add features to
|
||||||
Pamhyr2. Please, follow the architecture described in section
|
{{{pamhyr2}}}. Please, follow the architecture described in section
|
||||||
[[Architecture]] as closely as possible. Keep the code simple, clear and
|
[[Architecture]] as closely as possible. Keep the code simple, clear and
|
||||||
efficient as possible. The master branch is reserved for the project
|
efficient as possible. The master branch is reserved for the project
|
||||||
maintainer; you can create a new branch or fork the project before the
|
maintainer; you can create a new branch or fork the project before the
|
||||||
|
|
|
||||||
|
|
@ -163,3 +163,7 @@
|
||||||
\SetWatermarkScale{3}
|
\SetWatermarkScale{3}
|
||||||
\SetWatermarkFontSize{1cm}
|
\SetWatermarkFontSize{1cm}
|
||||||
\SetWatermarkText{Work in progress}
|
\SetWatermarkText{Work in progress}
|
||||||
|
|
||||||
|
%% Icons
|
||||||
|
|
||||||
|
\usepackage{fontawesome5}
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Constant name
|
# Constant name
|
||||||
#+MACRO: oldPamhyr PAMHyR
|
#+MACRO: pamhyr \textsc{PAMHyR}
|
||||||
#+MACRO: Pamhyr Pamhyr2
|
#+MACRO: pamhyr2 \textsc{Pamhyr2}
|
||||||
#+MACRO: Mage Mage
|
#+MACRO: mage \textsc{Mage}
|
||||||
#+MACRO: Rubarbe RubarBE
|
#+MACRO: mage7 \textsc{Mage7}
|
||||||
#+MACRO: Inrae INRAE
|
#+MACRO: mage8 \textsc{Mage8}
|
||||||
|
#+MACRO: rubarbe \textsc{RubarBE}
|
||||||
|
#+MACRO: adists \textsc{AdisTS}
|
||||||
|
#+MACRO: mascaret \textsc{Mascaret}
|
||||||
|
#+MACRO: inrae INRAE
|
||||||
#+MACRO: latex \LaTeX
|
#+MACRO: latex \LaTeX
|
||||||
|
|
||||||
# Information
|
# Information
|
||||||
|
|
@ -35,6 +39,16 @@
|
||||||
#+MACRO: cite [cite:$1]
|
#+MACRO: cite [cite:$1]
|
||||||
#+MACRO: biblio \bibliography{documentation}
|
#+MACRO: biblio \bibliography{documentation}
|
||||||
|
|
||||||
|
# Icons
|
||||||
|
#+MACRO: bulb \faIcon{lightbulb}
|
||||||
|
#+MACRO: OK \faIcon{check}
|
||||||
|
|
||||||
|
#+MACRO: linux \faIcon{linux}
|
||||||
|
#+MACRO: windows \faIcon{windows}
|
||||||
|
|
||||||
|
#+MACRO: python \faIcon{python}
|
||||||
|
#+MACRO: java \faIcon{java}
|
||||||
|
|
||||||
# Wrapper
|
# Wrapper
|
||||||
#+NAME: attr_wrap
|
#+NAME: attr_wrap
|
||||||
#+HEADER: :var width="\\textwidth"
|
#+HEADER: :var width="\\textwidth"
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
$Clapet_001 clapet
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 53 KiB |
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
%% LyX 2.0.2 created this file. For more info, see http://www.lyx.org/.
|
%% LyX 2.0.2 created this file. For more info, see http://www.lyx.org/.
|
||||||
%% Do not edit unless you really know what you are doing.
|
%% Do not edit unless you really know what you are doing.
|
||||||
\documentclass[12pt,french]{article}
|
\documentclass[12pt,french]{article}
|
||||||
|
|
@ -8,6 +9,7 @@
|
||||||
\usepackage{textcomp}
|
\usepackage{textcomp}
|
||||||
\usepackage{graphicx}
|
\usepackage{graphicx}
|
||||||
\usepackage{hyperref}
|
\usepackage{hyperref}
|
||||||
|
\usepackage[frenchb]{babel}
|
||||||
|
|
||||||
\makeatletter
|
\makeatletter
|
||||||
|
|
||||||
|
|
@ -132,17 +134,17 @@ Pendant que vous travaillez sur votre
|
||||||
|
|
||||||
\section{Créer la structure de la rivière}
|
\section{Créer la structure de la rivière}
|
||||||
|
|
||||||
Cliquez sur \texttt{[Réseau] => [Éditer le réseau]} ou sur l'icône \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/network.png} pour créer la structure de votre rivière.
|
Cliquez sur \texttt{[Réseau] => [Modifier le réseau]} ou sur l'icône \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/network.png} pour créer la structure de votre rivière.
|
||||||
Nous voici dans la fenêtre \textit{Réseau}.
|
Nous voici dans la fenêtre \textit{Réseau}.
|
||||||
Dans cette fenêtre, nous allons définir un graphe orienté qui représente les biefs de notre réseau fluvial : les arêtes sont les biefs, les n½uds sont soit des conditions limites amont, soit des conditions limites aval, soit des jonctions entre biefs.
|
Dans cette fenêtre, nous allons définir un graphe orienté qui représente les biefs de notre réseau fluvial : les arêtes sont les biefs, les n\oe{}uds sont soit des conditions limites amont, soit des conditions limites aval, soit des jonctions entre biefs.
|
||||||
Un bief par défaut existe dans la nouvelle étude.
|
Un bief par défaut existe dans la nouvelle étude.
|
||||||
Pour les besoins de ce tutoriel, nous allons le supprimer :
|
Pour les besoins de ce tutoriel, nous allons le supprimer :
|
||||||
cliquez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/del.png} pour entrer dans le mode \textit{Suppression} puis cliquez sur les n½uds.
|
cliquez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/del.png} pour entrer dans le mode \textit{Suppression} puis cliquez sur les n\oe{}uds.
|
||||||
Nous voilà repartis sur une fenêtre vierge.
|
Nous voilà repartis sur une fenêtre vierge.
|
||||||
Appuyez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} pour entrer dans le mode \textit{Ajout}. Créez deux n½uds en cliquant dans la zone grise de la fenêtre, et créez un lien en cliquant à nouveau sur chaque n½ud.
|
Appuyez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} pour entrer dans le mode \textit{Ajout}. Créez deux n\oe{}uds en cliquant dans la zone grise de la fenêtre, et créez un lien en cliquant à nouveau sur chaque n\oe{}ud.
|
||||||
Appuyez à nouveau sur \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} pour quitter le mode \textit{Ajout}.
|
Appuyez à nouveau sur \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} pour quitter le mode \textit{Ajout}.
|
||||||
Vous avez créé votre premier bief, avec un n½ud amont et un n½ud aval.
|
Vous avez créé votre premier bief, avec un n\oe{}ud amont et un n\oe{}ud aval.
|
||||||
Dans la partie inférieure de la fenêtre \textit{Réseau}, vous pouvez renommer les n½uds et les biefs.
|
Dans la partie inférieure de la fenêtre \textit{Réseau}, vous pouvez renommer les n\oe{}uds et les biefs.
|
||||||
Comme le bief que nous avons créé est automatiquement sélectionné, toutes les étapes suivantes s'appliqueront à ce bief.
|
Comme le bief que nous avons créé est automatiquement sélectionné, toutes les étapes suivantes s'appliqueront à ce bief.
|
||||||
La fenêtre doit se présenter comme suit :
|
La fenêtre doit se présenter comme suit :
|
||||||
|
|
||||||
|
|
@ -154,7 +156,7 @@ Fermez la fen
|
||||||
|
|
||||||
\section{Éditer la géométrie de la rivière}
|
\section{Éditer la géométrie de la rivière}
|
||||||
|
|
||||||
Cliquez sur \texttt{[Géométrie] => [Éditer 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électionné.
|
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électionné.
|
||||||
Pour Importer une géométrie depuis un fichier, cliquez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/import.png}.
|
Pour Importer une géométrie depuis un fichier, cliquez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/import.png}.
|
||||||
Sélectionnez le fichier \texttt{Data/Bief\_1.st}.
|
Sélectionnez le fichier \texttt{Data/Bief\_1.st}.
|
||||||
Vous devriez voir :
|
Vous devriez voir :
|
||||||
|
|
@ -237,8 +239,8 @@ Nous pouvons cliquer sur la nouvelle ligne pour s
|
||||||
Ici, nous définirons le débit mesuré lors de la crue de février 2002.
|
Ici, nous définirons le débit mesuré lors de la crue de février 2002.
|
||||||
Sélectionnez la cellule \textit{Nom} pour donner un nom à la condition limite par exemple "crue2002".
|
Sélectionnez la cellule \textit{Nom} pour donner un nom à la condition limite par exemple "crue2002".
|
||||||
Sélectionner la cellule \textit{Type} et utiliser la combo box pour mettre une loi \textit{Q(t)} : débit en fonction du temps (hydrogramme).
|
Sélectionner la cellule \textit{Type} et utiliser la combo box pour mettre une loi \textit{Q(t)} : débit en fonction du temps (hydrogramme).
|
||||||
Sélectionnez la cellule \textit{N½ud} et attribuez cette condition au n½ud amont.
|
Sélectionnez la cellule \textit{n\oe{}ud} et attribuez cette condition au n\oe{}ud amont.
|
||||||
Les noms des n½uds sont rappelés dans le panneau de droite, avec une vue du réseau.
|
Les noms des n\oe{}uds sont rappelés dans le panneau de droite, avec une vue du réseau.
|
||||||
Sélectionnez maintenant la ligne entière et cliquez sur le bouton d'édition \includegraphics[width=0.5cm]{"../../../src/View/ui/ressources/edit.png"}.
|
Sélectionnez maintenant la ligne entière et cliquez sur le bouton d'édition \includegraphics[width=0.5cm]{"../../../src/View/ui/ressources/edit.png"}.
|
||||||
Vous avez ouvert la fenêtre \textit{Éditer les conditions aux limites}.
|
Vous avez ouvert la fenêtre \textit{Éditer les conditions aux limites}.
|
||||||
Dans un éditeur de texte, ouvrez le fichier \texttt{data/Fevrier\_2002.txt}.
|
Dans un éditeur de texte, ouvrez le fichier \texttt{data/Fevrier\_2002.txt}.
|
||||||
|
|
@ -250,7 +252,7 @@ Vous pouvez maintenant voir la courbe de d
|
||||||
\par\end{center}
|
\par\end{center}
|
||||||
|
|
||||||
Fermez cette fenêtre. Revenez sur la fenêtre \textit{Conditions aux limites}.
|
Fermez cette fenêtre. Revenez sur la fenêtre \textit{Conditions aux limites}.
|
||||||
Ajoutez une nouvelle ligne, donnez lui un nom, donnez lui le type \textit{Z(T)} (limnigramme) et associez là au n½ud aval du réseau.
|
Ajoutez une nouvelle ligne, donnez lui un nom, donnez lui le type \textit{Z(T)} (limnigramme) et associez là au n\oe{}ud aval du réseau.
|
||||||
Ouvrez la fenêtre d'édition des conditions aux limites (\includegraphics[width=0.5cm]{"../../../src/View/ui/ressources/edit.png"}).
|
Ouvrez la fenêtre d'édition des conditions aux limites (\includegraphics[width=0.5cm]{"../../../src/View/ui/ressources/edit.png"}).
|
||||||
Ajoutez deux lignes et rentrez les valeurs suivantes :
|
Ajoutez deux lignes et rentrez les valeurs suivantes :
|
||||||
\begin{center}
|
\begin{center}
|
||||||
|
|
@ -271,7 +273,7 @@ Vous pouvez fermer les fen
|
||||||
% Cette condition limite se trouve au niveau d'un seuil.
|
% Cette condition limite se trouve au niveau d'un seuil.
|
||||||
% A cet endroit, l'écoulement passe d'un régime fluvial à un régime torentiel.
|
% A cet endroit, l'écoulement passe d'un régime fluvial à un régime torentiel.
|
||||||
% Nous allons donc calculer une courbe de tarage qui correspond au régime critique de l'écoulement au niveau du seuil.
|
% Nous allons donc calculer une courbe de tarage qui correspond au régime critique de l'écoulement au niveau du seuil.
|
||||||
% Sélectionnez la condition limite et ouvrez la fenêtre \textit{Éditer les conditions aux limites} : (\includegraphics[width=0.5cm]{"../../../src/View/ui/ressources/edit.png"}).
|
% Sélectionnez la condition limite et ouvrez la fenêtre \textit{Éditer les conditions aux limites} : (\includegraphics[width=0.5cm]{"../../../src/View/ui/ressources/edit.png"}).
|
||||||
% Dans la fenêtre \textit{Éditer les conditions aux limites} cliquez sur \texttt{[Générer régime critique]} pour générer cette courbe.
|
% Dans la fenêtre \textit{Éditer les conditions aux limites} cliquez sur \texttt{[Générer régime critique]} pour générer cette courbe.
|
||||||
% Cliquez ensuite sur \texttt{[Rendre croissant]} pour suprimer les points de la courbe qui ne sont pas strictement croissants.
|
% Cliquez ensuite sur \texttt{[Rendre croissant]} pour suprimer les points de la courbe qui ne sont pas strictement croissants.
|
||||||
% Vous pouvez fermer les fenêtres \textit{Éditer les conditions aux limites} et \textit{Conditions aux limites}.
|
% Vous pouvez fermer les fenêtres \textit{Éditer les conditions aux limites} et \textit{Conditions aux limites}.
|
||||||
|
|
@ -400,19 +402,19 @@ Si vous r
|
||||||
|
|
||||||
\section{Paramètres du solveur}
|
\section{Paramètres du solveur}
|
||||||
|
|
||||||
Dans la fenêtre principale, cliquez sur \texttt{[Exécuter] => [Parameters numériques des solveurs]}.
|
Dans la fenêtre principale, cliquez sur \texttt{[Exécuter] => [Paramètres numériques des solveurs]}.
|
||||||
Dans la fenêtre \textit{Paramètres du solveur}, sélectionnez l'onglet \texttt{[Mage v8]}.
|
Dans la fenêtre \textit{Paramètres du solveur}, sélectionnez l'onglet \texttt{[Mage v8]}.
|
||||||
Ces paramètres pilotent le comportement du solveur numérique.
|
Ces paramètres pilotent le comportement du solveur numérique.
|
||||||
la valeur 999:99:00:00 du temps final indique au solveur de s'arrêter lorsqu'il a atteint un régime permanent.
|
la valeur {\NoAutoSpacing 999:99:00:00} du temps final indique au solveur de s'arrêter lorsqu'il a atteint un régime permanent.
|
||||||
Vous pouvez changer la fréquence d'écriture des résultats dans la ligne \textit{Pas de temps d'écriture dans le fichier .BIN}.
|
Vous pouvez changer la fréquence d'écriture des résultats dans la ligne \textit{Pas de temps d'écriture dans le fichier .BIN}.
|
||||||
Une valeur inférieure à 1 seconde indique que la valeur de la ligne \textit{Pas de temps d'écriture dans le fichier .TRA} s sera prise à la place.
|
Une valeur inférieure à 1 seconde indique que la valeur de la ligne \textit{Pas de temps d'écriture dans le fichier .TRA} s sera prise à la place.
|
||||||
% En effet, durant la montée du pic de crue, le solveur a besoin de réduire le pas de temps suffisament pour permettre la convergence des itérations.
|
% En effet, durant la montée du pic de crue, le solveur a besoin de réduire le pas de temps suffisament pour permettre la convergence des itérations.
|
||||||
Pour accélérer les calculs et pour aider le solveur à démarer, nous allons l'autoriser à dégrader la précision, à l'aide des facteurs de réduction de la précision.
|
Pour accélérer les calculs et pour aider le solveur à démarrer, nous allons l'autoriser à dégrader la précision, à l'aide des facteurs de réduction de la précision.
|
||||||
Les précisions internes du solveur sont de 10$^{-9}$.
|
Les précisions internes du solveur sont de 10$^{-9}$.
|
||||||
Cette précision est multipliée par le facteur de réduction de la précision : un facteur de 1000 ramènera donc la précision à 10$^{-5}$.
|
Cette précision est multipliée par le facteur de réduction de la précision : un facteur de 1000 ramènera donc la précision à 10$^{-5}$.
|
||||||
Pour utiliser ce facteur de réduction de la précision, il faut donner un \textit{nombre d'itérations à précision maximum} inférieur au \textit{nombre maximum d'itérations} : le solveur va d'abord tenter de converger avec un certain nombre d'itératons à la précision maximum avant de basculer sur une précision dégradée pour le reste des itérations.
|
Pour utiliser ce facteur de réduction de la précision, il faut donner un \textit{nombre d'itérations à précision maximum} inférieur au \textit{nombre maximum d'itérations} : le solveur va d'abord tenter de converger avec un certain nombre d'itératons à la précision maximum avant de basculer sur une précision dégradée pour le reste des itérations.
|
||||||
Dans notre cas, c'est nécessaire pour lancer le solveur à partir de la condition initiale calculée par Pamhyr2.
|
Dans notre cas, c'est nécessaire pour lancer le solveur à partir de la condition initiale calculée par Pamhyr2.
|
||||||
rentrez 1000 dans les trois lignes \textit{facteurs de réduction de la précision}, rentrez 99 pour le \textit{Nombre d'itérations} et 5 pour le \textit{nombre d'itérations à la précision maximum}.
|
Rentrez 1000 dans les trois lignes \textit{facteurs de réduction de la précision}, rentrez 99 pour le \textit{Nombre maximum d'itérations} et 5 pour le \textit{nombre d'itérations à la précision maximum}.
|
||||||
Gardez les autres paramètres du solveur par défaut.
|
Gardez les autres paramètres du solveur par défaut.
|
||||||
Fermer la fenêtre \textit{Paramètres du solveur}.
|
Fermer la fenêtre \textit{Paramètres du solveur}.
|
||||||
|
|
||||||
|
|
@ -426,12 +428,13 @@ Cette fen
|
||||||
|
|
||||||
\section{Visualiser les résultats}
|
\section{Visualiser les résultats}
|
||||||
|
|
||||||
il est aussi possible d'ouvrir la fenêtre \textit{Résultats} si vous avez fermé la fenêtre \textit{Log du solveur}, en cliquant sur \texttt{[Résultats] => [Visualiser les derniers résultats]} à partir de la fenêtre principale.
|
Il est aussi possible d'ouvrir la fenêtre \textit{Résultats} si vous avez fermé la fenêtre \textit{Log du solveur}, en cliquant sur \texttt{[Résultats] => [Visualiser les derniers résultats]} à partir de la fenêtre principale.
|
||||||
Le panneau supérieur vous permet de sélectionner le bief, le panneau inférieur gauche vous permet de sélectionner une section dans ce bief.
|
Le panneau supérieur vous permet de sélectionner le bief, le panneau inférieur gauche vous permet de sélectionner une section dans ce bief.
|
||||||
Les trois diagrammes sur la droite montrent le bief et la section en travers de la même manière que dans la fenêtre \textit{Géométrie}.
|
Les trois diagrammes sur la droite montrent le bief et la section en travers de la même manière que dans la fenêtre \textit{Géométrie}.
|
||||||
Vous pouvez utiliser le curseur du bas pour visualiser les résultats à différents pas de temps.
|
Vous pouvez utiliser le curseur du bas pour visualiser les résultats à différents pas de temps.
|
||||||
Les croix rouges dans les deux vues du haut correspondent aux points ou l'eau déborde de la géométrie au moins une fois dans la simulation.
|
Les croix rouges dans les deux vues du haut correspondent aux points ou l'eau déborde de la géométrie au moins une fois dans la simulation.
|
||||||
En pratique il n'y a pas de perte de volume par débordement en dehors du modèle, car le solveur ajoute un mur virtuel aux extrémités des sections.
|
En pratique il n'y a pas de perte de volume par débordement en dehors du modèle, car le solveur ajoute un mur virtuel aux extrémités des sections.
|
||||||
|
|
||||||
Pour visualiser le débit, passez à l'onglet \textit{Hydrogramme}.
|
Pour visualiser le débit, passez à l'onglet \textit{Hydrogramme}.
|
||||||
Pour créer des tracés 2D personnalisés, cliquez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} en haut à gauche de la fenêtre.
|
Pour créer des tracés 2D personnalisés, cliquez sur le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/add.png} en haut à gauche de la fenêtre.
|
||||||
Sélectionnez les valeurs que vous voulez sur les axes $X$ et $Y$ et cliquez sur \texttt{[OK]}.
|
Sélectionnez les valeurs que vous voulez sur les axes $X$ et $Y$ et cliquez sur \texttt{[OK]}.
|
||||||
|
|
@ -440,4 +443,3 @@ Le bouton \includegraphics[width=0.5cm]{../../../src/View/ui/ressources/export.p
|
||||||
|
|
||||||
\pagebreak{}
|
\pagebreak{}
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -360,26 +360,11 @@ class InitialConditions(SQLSubModel):
|
||||||
def get_discharge(self):
|
def get_discharge(self):
|
||||||
return self._data_get("discharge")
|
return self._data_get("discharge")
|
||||||
|
|
||||||
def _sort_by_z_and_rk(self, profiles):
|
|
||||||
profiles.sort(
|
|
||||||
reverse=False,
|
|
||||||
key=lambda p: p.rk
|
|
||||||
)
|
|
||||||
|
|
||||||
first_z = profiles[0].z()
|
|
||||||
last_z = profiles[-1].z()
|
|
||||||
|
|
||||||
if first_z > last_z:
|
|
||||||
profiles.sort(
|
|
||||||
reverse=True,
|
|
||||||
key=lambda p: p.rk
|
|
||||||
)
|
|
||||||
|
|
||||||
def generate_growing_constant_depth(self, height: float,
|
def generate_growing_constant_depth(self, height: float,
|
||||||
compute_discharge: bool):
|
compute_discharge: bool):
|
||||||
|
|
||||||
profiles = self._reach.reach.profiles.copy()
|
profiles = self._reach.reach.profiles.copy()
|
||||||
self._sort_by_z_and_rk(profiles)
|
profiles.reverse()
|
||||||
|
|
||||||
previous_elevation = -99999.99
|
previous_elevation = -99999.99
|
||||||
|
|
||||||
|
|
@ -433,12 +418,12 @@ class InitialConditions(SQLSubModel):
|
||||||
previous_elevation = elevation
|
previous_elevation = elevation
|
||||||
self._data.append(new)
|
self._data.append(new)
|
||||||
|
|
||||||
self._generate_resort_data(profiles)
|
self._data.reverse()
|
||||||
|
|
||||||
def generate_discharge(self, discharge: float, compute_height: bool):
|
def generate_discharge(self, discharge: float, compute_height: bool):
|
||||||
|
|
||||||
profiles = self._reach.reach.profiles.copy()
|
profiles = self._reach.reach.profiles.copy()
|
||||||
self._sort_by_z_and_rk(profiles)
|
profiles.reverse()
|
||||||
|
|
||||||
previous_elevation = -99999.99
|
previous_elevation = -99999.99
|
||||||
|
|
||||||
|
|
@ -491,7 +476,7 @@ class InitialConditions(SQLSubModel):
|
||||||
previous_elevation = elevation
|
previous_elevation = elevation
|
||||||
self._data.append(new)
|
self._data.append(new)
|
||||||
|
|
||||||
self._generate_resort_data(profiles)
|
self._data.reverse()
|
||||||
|
|
||||||
def generate_height(self,
|
def generate_height(self,
|
||||||
elevation1: float,
|
elevation1: float,
|
||||||
|
|
@ -525,13 +510,3 @@ class InitialConditions(SQLSubModel):
|
||||||
new["discharge"] = d
|
new["discharge"] = d
|
||||||
new["elevation"] = elevation
|
new["elevation"] = elevation
|
||||||
self._data.append(new)
|
self._data.append(new)
|
||||||
|
|
||||||
def _generate_resort_data(self, profiles):
|
|
||||||
is_reverse = False
|
|
||||||
if profiles[0].rk > profiles[-1].rk:
|
|
||||||
is_reverse = True
|
|
||||||
|
|
||||||
self._data.sort(
|
|
||||||
reverse=not is_reverse,
|
|
||||||
key=lambda d: d['rk']
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,10 @@ class CommandLineSolver(AbstractSolver):
|
||||||
params = study.river.get_params(self.type)
|
params = study.river.get_params(self.type)
|
||||||
args = params.get_by_key("all_command_line_arguments")
|
args = params.get_by_key("all_command_line_arguments")
|
||||||
|
|
||||||
return args.split(" ")
|
if args is None:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
return args.split(" ")
|
||||||
|
|
||||||
def input_param(self):
|
def input_param(self):
|
||||||
"""Return input command line parameter(s)
|
"""Return input command line parameter(s)
|
||||||
|
|
|
||||||
|
|
@ -599,29 +599,50 @@ class Mage(CommandLineSolver):
|
||||||
if qlog is not None:
|
if qlog is not None:
|
||||||
qlog.put("Export VAR file")
|
qlog.put("Export VAR file")
|
||||||
|
|
||||||
with mage_file_open(os.path.join(repertory, f"{name}.VAR"), "w+") as f:
|
nb_cv = 0
|
||||||
files.append(f"{name}.VAR")
|
for hs in hydraulic_structures:
|
||||||
|
if hs.input_reach is None:
|
||||||
|
continue
|
||||||
|
|
||||||
for hs in hydraulic_structures:
|
if not hs.input_reach.is_enable():
|
||||||
if hs.input_reach is None:
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
if not hs.input_reach.is_enable():
|
if not hs.enabled:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for bhs in hs.basic_structures:
|
for bhs in hs.basic_structures:
|
||||||
|
if bhs.enabled:
|
||||||
logger.info(bhs._type)
|
logger.info(bhs._type)
|
||||||
if bhs._type != "CV":
|
if bhs._type == "CV":
|
||||||
|
nb_cv += 1
|
||||||
|
|
||||||
|
if nb_cv != 0:
|
||||||
|
with mage_file_open(os.path.join(
|
||||||
|
repertory, f"{name}.VAR"), "w+") as f:
|
||||||
|
files.append(f"{name}.VAR")
|
||||||
|
|
||||||
|
for hs in hydraulic_structures:
|
||||||
|
if hs.input_reach is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
name = bhs.name
|
if not hs.input_reach.is_enable():
|
||||||
if name == "":
|
continue
|
||||||
name = f"HS_{bhs.id:>3}".replace(" ", "0")
|
|
||||||
|
|
||||||
f.write(
|
if not hs.enabled:
|
||||||
f"${name} clapet"
|
continue
|
||||||
)
|
|
||||||
|
|
||||||
|
for bhs in hs.basic_structures:
|
||||||
|
logger.info(bhs._type)
|
||||||
|
if bhs._type != "CV":
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = bhs.name
|
||||||
|
if name == "":
|
||||||
|
name = f"HS_{bhs.id:>3}".replace(" ", "0")
|
||||||
|
|
||||||
|
f.write(
|
||||||
|
f"${name} clapet"
|
||||||
|
)
|
||||||
return files
|
return files
|
||||||
|
|
||||||
def _export_DEV(self, study, repertory, qlog, name="0"):
|
def _export_DEV(self, study, repertory, qlog, name="0"):
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ class PlotRKZ(PamhyrPlot):
|
||||||
self.line_rk_zmin_zmax_highlight = None
|
self.line_rk_zmin_zmax_highlight = None
|
||||||
|
|
||||||
self.label_x = self._trad["unit_rk"]
|
self.label_x = self._trad["unit_rk"]
|
||||||
self.label_y = self._trad["unit_height"]
|
self.label_y = self._trad["unit_depth"]
|
||||||
|
|
||||||
self.before_plot_selected = None
|
self.before_plot_selected = None
|
||||||
self.plot_selected = None
|
self.plot_selected = None
|
||||||
|
|
|
||||||
|
|
@ -77,29 +77,29 @@ class PlotDRK(PamhyrPlot):
|
||||||
rk = self.data.get_rk()
|
rk = self.data.get_rk()
|
||||||
elevation = self.data.get_elevation()
|
elevation = self.data.get_elevation()
|
||||||
|
|
||||||
|
sorted_rk, sorted_elevation = zip(
|
||||||
|
*sorted(zip(rk, elevation))
|
||||||
|
)
|
||||||
|
|
||||||
self.line_rk_elevation = self.canvas.axes.plot(
|
self.line_rk_elevation = self.canvas.axes.plot(
|
||||||
rk, elevation,
|
sorted_rk, sorted_elevation,
|
||||||
color=self.color_plot_river_water,
|
color=self.color_plot_river_water,
|
||||||
**self.plot_default_kargs
|
**self.plot_default_kargs
|
||||||
)
|
)
|
||||||
|
|
||||||
z_min = self.data.reach.reach.get_z_min()
|
z_min = self.data.reach.reach.get_z_min()
|
||||||
geometry_rk = self.data.reach.reach.get_rk()
|
geometry_rk = self.data.reach.reach.get_rk()
|
||||||
|
sorted_geometry_rk, sorted_z_min = zip(
|
||||||
filtred_elevation = list(
|
*sorted(zip(geometry_rk, z_min), reverse=True)
|
||||||
map(
|
|
||||||
lambda x: elevation[x[0]],
|
|
||||||
filter(
|
|
||||||
lambda x: x[1] in geometry_rk,
|
|
||||||
enumerate(rk)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.collection = self.canvas.axes.fill_between(
|
poly_x = sorted_rk + sorted_geometry_rk
|
||||||
geometry_rk, z_min, filtred_elevation,
|
poly_y = sorted_elevation + sorted_z_min
|
||||||
|
|
||||||
|
self.collection = self.canvas.axes.fill(
|
||||||
|
poly_x, poly_y,
|
||||||
color=self.color_plot_river_water_zone,
|
color=self.color_plot_river_water_zone,
|
||||||
alpha=0.7, interpolate=True
|
alpha=0.7,
|
||||||
)
|
)
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
|
|
|
||||||
|
|
@ -104,15 +104,15 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
row = index.row()
|
row = index.row()
|
||||||
column = index.column()
|
column = index.column()
|
||||||
|
|
||||||
if self._headers[column] is "speed":
|
if self._headers[column] == "velocity":
|
||||||
z = self._lst.get(row)["elevation"]
|
z = self._lst.get(row)["elevation"]
|
||||||
q = self._lst.get(row)["discharge"]
|
q = self._lst.get(row)["discharge"]
|
||||||
profile = self._reach.reach.get_profiles_from_rk(
|
profile = self._reach.reach.get_profiles_from_rk(
|
||||||
self._lst.get(row)["rk"]
|
self._lst.get(row)["rk"]
|
||||||
)
|
)
|
||||||
if len(profile) >= 1:
|
if len(profile) >= 1:
|
||||||
speed = profile[0].speed(q, z)
|
velocity = profile[0].speed(q, z)
|
||||||
return f"{speed:.4f}"
|
return f"{velocity:.4f}"
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
elif self._headers[column] not in ["name", "comment"]:
|
elif self._headers[column] not in ["name", "comment"]:
|
||||||
|
|
|
||||||
|
|
@ -365,40 +365,43 @@ class InitialConditionsWindow(PamhyrWindow):
|
||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
def generate_growing_constant_depth(self):
|
def generate_growing_constant_depth(self):
|
||||||
dlg = DepthDialog(self.depth_value,
|
if self._reach.reach.number_profiles > 0:
|
||||||
self.depth_option,
|
dlg = DepthDialog(self.depth_value,
|
||||||
trad=self._trad,
|
self.depth_option,
|
||||||
parent=self)
|
|
||||||
if dlg.exec():
|
|
||||||
self.depth_value = dlg.value
|
|
||||||
self.depth_option = dlg.option
|
|
||||||
self._table.generate("growing",
|
|
||||||
self.depth_value,
|
|
||||||
self.depth_option)
|
|
||||||
self._update()
|
|
||||||
|
|
||||||
def generate_discharge(self):
|
|
||||||
dlg = DischargeDialog(self.discharge_value,
|
|
||||||
self.discharge_option,
|
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
parent=self)
|
parent=self)
|
||||||
if dlg.exec():
|
if dlg.exec():
|
||||||
self.discharge_value = dlg.value
|
self.depth_value = dlg.value
|
||||||
self.discharge_option = dlg.option
|
self.depth_option = dlg.option
|
||||||
self._table.generate("discharge",
|
self._table.generate("growing",
|
||||||
self.discharge_value,
|
self.depth_value,
|
||||||
self.discharge_option)
|
self.depth_option)
|
||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
|
def generate_discharge(self):
|
||||||
|
if self._reach.reach.number_profiles > 1:
|
||||||
|
dlg = DischargeDialog(self.discharge_value,
|
||||||
|
self.discharge_option,
|
||||||
|
trad=self._trad,
|
||||||
|
parent=self)
|
||||||
|
if dlg.exec():
|
||||||
|
self.discharge_value = dlg.value
|
||||||
|
self.discharge_option = dlg.option
|
||||||
|
self._table.generate("discharge",
|
||||||
|
self.discharge_value,
|
||||||
|
self.discharge_option)
|
||||||
|
self._update()
|
||||||
|
|
||||||
def generate_height(self):
|
def generate_height(self):
|
||||||
dlg = HeightDialog(self.height_values,
|
if self._reach.reach.number_profiles > 0:
|
||||||
self.height_option,
|
dlg = HeightDialog(self.height_values,
|
||||||
trad=self._trad,
|
self.height_option,
|
||||||
parent=self)
|
trad=self._trad,
|
||||||
if dlg.exec():
|
parent=self)
|
||||||
self.height_values = dlg.values
|
if dlg.exec():
|
||||||
self.height_option = dlg.option
|
self.height_values = dlg.values
|
||||||
self._table.generate("height",
|
self.height_option = dlg.option
|
||||||
self.height_values,
|
self._table.generate("height",
|
||||||
self.height_option)
|
self.height_values,
|
||||||
self._update()
|
self.height_option)
|
||||||
|
self._update()
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class ICTranslate(MainTranslate):
|
||||||
"rk": self._dict["unit_rk"],
|
"rk": self._dict["unit_rk"],
|
||||||
"discharge": self._dict["unit_discharge"],
|
"discharge": self._dict["unit_discharge"],
|
||||||
"elevation": self._dict["unit_elevation"],
|
"elevation": self._dict["unit_elevation"],
|
||||||
"height": self._dict["unit_height"],
|
"height": self._dict["unit_depth"],
|
||||||
"speed": self._dict["unit_speed"],
|
"velocity": self._dict["unit_velocity"],
|
||||||
# "comment": _translate("InitialCondition", "Comment"),
|
# "comment": _translate("InitialCondition", "Comment"),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,13 @@ import logging
|
||||||
|
|
||||||
from tools import timer, trace
|
from tools import timer, trace
|
||||||
|
|
||||||
|
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
|
from View.PlotXY import PlotXY
|
||||||
from View.Tools.PamhyrWidget import PamhyrWidget
|
from View.Tools.PamhyrWidget import PamhyrWidget
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import QVBoxLayout
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -38,7 +43,9 @@ class WidgetInfo(PamhyrWidget):
|
||||||
parent=parent
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.parent = parent
|
||||||
self.set_initial_values()
|
self.set_initial_values()
|
||||||
|
self.setup_graph()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def study(self):
|
def study(self):
|
||||||
|
|
@ -64,6 +71,25 @@ class WidgetInfo(PamhyrWidget):
|
||||||
self.set_label_text("label_lc", "-")
|
self.set_label_text("label_lc", "-")
|
||||||
self.set_label_text("label_hs", "-")
|
self.set_label_text("label_hs", "-")
|
||||||
|
|
||||||
|
def setup_graph(self):
|
||||||
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas.setObjectName("canvas")
|
||||||
|
self.plot_layout_xy = self.find(QVBoxLayout, "verticalLayout")
|
||||||
|
self._toolbar_xy = PamhyrPlotToolbar(
|
||||||
|
self.canvas, self,
|
||||||
|
items=["home", "zoom", "save", "iso", "back/forward", "move"]
|
||||||
|
)
|
||||||
|
self.plot_layout_xy.addWidget(self._toolbar_xy)
|
||||||
|
self.plot_layout_xy.addWidget(self.canvas)
|
||||||
|
|
||||||
|
self.plot = PlotXY(
|
||||||
|
canvas=self.canvas,
|
||||||
|
data=None,
|
||||||
|
trad=self.parent._trad,
|
||||||
|
toolbar=self._toolbar_xy,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if self._study is None:
|
if self._study is None:
|
||||||
self.set_initial_values()
|
self.set_initial_values()
|
||||||
|
|
@ -75,6 +101,15 @@ class WidgetInfo(PamhyrWidget):
|
||||||
self.set_network_values()
|
self.set_network_values()
|
||||||
self.set_geometry_values()
|
self.set_geometry_values()
|
||||||
|
|
||||||
|
self.plot = PlotXY(
|
||||||
|
canvas=self.canvas,
|
||||||
|
data=self._study.river.enable_edges(),
|
||||||
|
trad=self.parent._trad,
|
||||||
|
toolbar=self._toolbar_xy,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
self.plot.update()
|
||||||
|
|
||||||
def set_network_values(self):
|
def set_network_values(self):
|
||||||
river = self._study.river
|
river = self._study.river
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
# PlotXY.py -- Pamhyr
|
||||||
|
# Copyright (C) 2023-2024 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from tools import timer, trace
|
||||||
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
|
from matplotlib import collections
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from PyQt5.QtCore import (
|
||||||
|
QCoreApplication, Qt, QItemSelectionModel,
|
||||||
|
QItemSelection, QItemSelectionRange,
|
||||||
|
)
|
||||||
|
from PyQt5.QtWidgets import QApplication, QTableView
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class PlotXY(PamhyrPlot):
|
||||||
|
def __init__(self, canvas=None, trad=None, data=None, toolbar=None,
|
||||||
|
table=None, parent=None):
|
||||||
|
super(PlotXY, self).__init__(
|
||||||
|
canvas=canvas,
|
||||||
|
trad=trad,
|
||||||
|
data=data,
|
||||||
|
toolbar=toolbar,
|
||||||
|
table=table,
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self.label_x = self._trad["x"]
|
||||||
|
self.label_y = self._trad["y"]
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
self._isometric_axis = True
|
||||||
|
|
||||||
|
self._auto_relim_update = True
|
||||||
|
self._autoscale_update = True
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw(self):
|
||||||
|
self.init_axes()
|
||||||
|
|
||||||
|
if self._data is None:
|
||||||
|
self.idle()
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(self._data) < 1:
|
||||||
|
self.idle()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.line_lr = []
|
||||||
|
for data in self._data:
|
||||||
|
if data.reach.number_profiles != 0:
|
||||||
|
self.draw_xy(data.reach)
|
||||||
|
self.draw_lr(data.reach)
|
||||||
|
self.idle()
|
||||||
|
return
|
||||||
|
|
||||||
|
def draw_xy(self, reach):
|
||||||
|
line_xy = []
|
||||||
|
for xy in zip(reach.get_x(), reach.get_y()):
|
||||||
|
line_xy.append(np.column_stack(xy))
|
||||||
|
|
||||||
|
line_xy_collection = collections.LineCollection(
|
||||||
|
line_xy,
|
||||||
|
colors=self.color_plot_river_bottom
|
||||||
|
)
|
||||||
|
self.canvas.axes.add_collection(line_xy_collection)
|
||||||
|
|
||||||
|
def draw_lr(self, reach):
|
||||||
|
lx = []
|
||||||
|
ly = []
|
||||||
|
rx = []
|
||||||
|
ry = []
|
||||||
|
|
||||||
|
for x, y in zip(reach.get_x(),
|
||||||
|
reach.get_y()):
|
||||||
|
lx.append(x[0])
|
||||||
|
ly.append(y[0])
|
||||||
|
|
||||||
|
rx.append(x[-1])
|
||||||
|
ry.append(y[-1])
|
||||||
|
|
||||||
|
line = self.canvas.axes.plot(
|
||||||
|
lx, ly,
|
||||||
|
color=self.color_plot_river_bottom,
|
||||||
|
linestyle="dotted",
|
||||||
|
lw=1.,
|
||||||
|
)
|
||||||
|
self.line_lr.append(line)
|
||||||
|
|
||||||
|
line = self.canvas.axes.plot(
|
||||||
|
rx, ry,
|
||||||
|
color=self.color_plot_river_bottom,
|
||||||
|
linestyle="dotted",
|
||||||
|
lw=1.,
|
||||||
|
)
|
||||||
|
self.line_lr.append(line)
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def update(self):
|
||||||
|
self.draw()
|
||||||
|
self.update_idle()
|
||||||
|
|
@ -49,8 +49,8 @@ class Plot(PamhyrPlot):
|
||||||
self._mode = mode
|
self._mode = mode
|
||||||
self._table_headers = self._trad.get_dict("table_headers")
|
self._table_headers = self._trad.get_dict("table_headers")
|
||||||
|
|
||||||
self.label_x = self._table_headers["z"]
|
self.label_x = self._table_headers["area"]
|
||||||
self.label_y = self._table_headers["area"]
|
self.label_y = self._table_headers["z"]
|
||||||
|
|
||||||
self._isometric_axis = False
|
self._isometric_axis = False
|
||||||
|
|
||||||
|
|
@ -71,8 +71,8 @@ class Plot(PamhyrPlot):
|
||||||
self._init = True
|
self._init = True
|
||||||
|
|
||||||
def draw_data(self):
|
def draw_data(self):
|
||||||
x = list(map(lambda v: v[0], self.data.data))
|
x = list(map(lambda v: v[1], self.data.data))
|
||||||
y = list(map(lambda v: v[1], self.data.data))
|
y = list(map(lambda v: v[0], self.data.data))
|
||||||
self._line, = self.canvas.axes.plot(
|
self._line, = self.canvas.axes.plot(
|
||||||
x, y,
|
x, y,
|
||||||
color=self.color_plot,
|
color=self.color_plot,
|
||||||
|
|
@ -89,7 +89,7 @@ class Plot(PamhyrPlot):
|
||||||
self.update_idle()
|
self.update_idle()
|
||||||
|
|
||||||
def update_data(self):
|
def update_data(self):
|
||||||
x = list(map(lambda v: v[0], self.data.data))
|
x = list(map(lambda v: v[1], self.data.data))
|
||||||
y = list(map(lambda v: v[1], self.data.data))
|
y = list(map(lambda v: v[0], self.data.data))
|
||||||
|
|
||||||
self._line.set_data(x, y)
|
self._line.set_data(x, y)
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ class CustomPlotValuesSelectionDialog(PamhyrDialog):
|
||||||
self._available_values_y = self._trad.get_dict("values_y")
|
self._available_values_y = self._trad.get_dict("values_y")
|
||||||
|
|
||||||
self.setup_radio_buttons()
|
self.setup_radio_buttons()
|
||||||
|
self.setup_envelop_box()
|
||||||
self.setup_check_boxs()
|
self.setup_check_boxs()
|
||||||
|
|
||||||
self.value = None
|
self.value = None
|
||||||
|
|
@ -61,6 +62,24 @@ class CustomPlotValuesSelectionDialog(PamhyrDialog):
|
||||||
self._radio[0][1].setChecked(True)
|
self._radio[0][1].setChecked(True)
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
|
|
||||||
|
def setup_envelop_box(self):
|
||||||
|
self._envelop = []
|
||||||
|
layout = self.find(QVBoxLayout, "verticalLayout_x")
|
||||||
|
self._envelop = QCheckBox(
|
||||||
|
"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():
|
||||||
|
self._envelop.setEnabled(True)
|
||||||
|
else:
|
||||||
|
self._envelop.setEnabled(False)
|
||||||
|
|
||||||
def setup_check_boxs(self):
|
def setup_check_boxs(self):
|
||||||
self._check = []
|
self._check = []
|
||||||
layout = self.find(QVBoxLayout, "verticalLayout_y")
|
layout = self.find(QVBoxLayout, "verticalLayout_y")
|
||||||
|
|
@ -94,6 +113,6 @@ class CustomPlotValuesSelectionDialog(PamhyrDialog):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.value = x, y
|
self.value = x, y, self._envelop.isChecked()
|
||||||
|
|
||||||
super().accept()
|
super().accept()
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import logging
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from numpy import sqrt
|
from numpy import sqrt
|
||||||
|
from numpy import asarray
|
||||||
|
|
||||||
from tools import timer
|
from tools import timer
|
||||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
|
|
@ -30,11 +31,16 @@ from View.Results.CustomPlot.Translate import CustomPlotTranslate
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
unit = {
|
unit = {
|
||||||
"elevation": "0-meter",
|
"bed_elevation": "0-meter",
|
||||||
|
"bed_elevation_envelop": "0-meter",
|
||||||
"water_elevation": "0-meter",
|
"water_elevation": "0-meter",
|
||||||
|
"water_elevation_envelop": "0-meter",
|
||||||
"discharge": "1-m3s",
|
"discharge": "1-m3s",
|
||||||
|
"discharge_envelop": "1-m3s",
|
||||||
"velocity": "2-ms",
|
"velocity": "2-ms",
|
||||||
"max_depth": "3-meter",
|
"velocity_envelop": "2-ms",
|
||||||
|
"depth": "3-meter",
|
||||||
|
"depth_envelop": "3-meter",
|
||||||
"mean_depth": "3-meter",
|
"mean_depth": "3-meter",
|
||||||
"froude": "4-dimensionless",
|
"froude": "4-dimensionless",
|
||||||
"wet_area": "5-m2",
|
"wet_area": "5-m2",
|
||||||
|
|
@ -42,7 +48,7 @@ unit = {
|
||||||
|
|
||||||
|
|
||||||
class CustomPlot(PamhyrPlot):
|
class CustomPlot(PamhyrPlot):
|
||||||
def __init__(self, x, y, reach, profile, timestamp,
|
def __init__(self, x, y, envelop, reach, profile, timestamp,
|
||||||
data=None, canvas=None, trad=None,
|
data=None, canvas=None, trad=None,
|
||||||
toolbar=None, parent=None):
|
toolbar=None, parent=None):
|
||||||
super(CustomPlot, self).__init__(
|
super(CustomPlot, self).__init__(
|
||||||
|
|
@ -55,6 +61,7 @@ class CustomPlot(PamhyrPlot):
|
||||||
|
|
||||||
self._x = x
|
self._x = x
|
||||||
self._y = y
|
self._y = y
|
||||||
|
self._envelop = envelop
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
self._profile = profile
|
self._profile = profile
|
||||||
self._timestamp = timestamp
|
self._timestamp = timestamp
|
||||||
|
|
@ -77,11 +84,97 @@ class CustomPlot(PamhyrPlot):
|
||||||
|
|
||||||
self._axes = {}
|
self._axes = {}
|
||||||
|
|
||||||
|
def draw_bottom_with_bedload(self, reach):
|
||||||
|
self._bedrock = self.sl_compute_bedrock(reach)
|
||||||
|
|
||||||
|
rk = reach.geometry.get_rk()
|
||||||
|
z = self.sl_compute_current_z(reach)
|
||||||
|
|
||||||
|
return z
|
||||||
|
|
||||||
|
def sl_compute_current_z(self, reach):
|
||||||
|
z_br = self._bedrock
|
||||||
|
sl = self.sl_compute_current_rk(reach)
|
||||||
|
|
||||||
|
z = list(
|
||||||
|
map(
|
||||||
|
lambda z, sl: reduce(
|
||||||
|
lambda z, h: z + h[0],
|
||||||
|
sl, z
|
||||||
|
),
|
||||||
|
z_br, # Bedrock elevation
|
||||||
|
sl # Current sediment layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return z
|
||||||
|
|
||||||
|
def sl_compute_bedrock(self, reach):
|
||||||
|
z_min = reach.geometry.get_z_min()
|
||||||
|
sl = self.sl_compute_initial(reach)
|
||||||
|
|
||||||
|
z = list(
|
||||||
|
map(
|
||||||
|
lambda z, sl: reduce(
|
||||||
|
lambda z, h: z - h[0],
|
||||||
|
sl, z
|
||||||
|
),
|
||||||
|
z_min, # Original geometry
|
||||||
|
sl # Original sediment layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return z
|
||||||
|
|
||||||
|
def sl_compute_initial(self, reach):
|
||||||
|
"""
|
||||||
|
Get SL list for profile p at initial time (initial data)
|
||||||
|
"""
|
||||||
|
t0 = min(list(self.data.get("timestamps")))
|
||||||
|
return map(
|
||||||
|
lambda p: p.get_ts_key(t0, "sl")[0],
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
|
||||||
|
def sl_compute_current_rk(self, reach):
|
||||||
|
"""
|
||||||
|
Get SL list for profile p at current time
|
||||||
|
"""
|
||||||
|
return map(
|
||||||
|
lambda p: p.get_ts_key(self._timestamp, "sl")[0],
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_ts_zmin(self, profile):
|
||||||
|
results = self.data
|
||||||
|
nt = len(list(results.get("timestamps")))
|
||||||
|
reach = results.river.reach(self._reach)
|
||||||
|
berdrock = self.sl_compute_bedrock(reach)
|
||||||
|
sl = reach.profile(profile).get_key("sl")
|
||||||
|
|
||||||
|
ts_z_bedrock = [berdrock[profile]]*nt
|
||||||
|
|
||||||
|
ts_z_min = list(
|
||||||
|
map(
|
||||||
|
lambda z, sl: reduce(
|
||||||
|
lambda z, h: z + h,
|
||||||
|
sl, z
|
||||||
|
),
|
||||||
|
ts_z_bedrock, # Bedrock elevations
|
||||||
|
asarray(sl)[:,0,:,0] # Sediment layers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return ts_z_min
|
||||||
|
|
||||||
def _draw_rk(self):
|
def _draw_rk(self):
|
||||||
results = self.data
|
results = self.data
|
||||||
reach = results.river.reach(self._reach)
|
reach = results.river.reach(self._reach)
|
||||||
rk = reach.geometry.get_rk()
|
rk = reach.geometry.get_rk()
|
||||||
z_min = reach.geometry.get_z_min()
|
if reach.has_sediment():
|
||||||
|
z_min = self.draw_bottom_with_bedload(reach)
|
||||||
|
else:
|
||||||
|
z_min = reach.geometry.get_z_min()
|
||||||
|
|
||||||
q = list(
|
q = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.get_ts_key(self._timestamp, "Q"),
|
lambda p: p.get_ts_key(self._timestamp, "Q"),
|
||||||
|
|
@ -105,15 +198,45 @@ class CustomPlot(PamhyrPlot):
|
||||||
self._axes[ax].spines['right'].set_position(('outward', shift))
|
self._axes[ax].spines['right'].set_position(('outward', shift))
|
||||||
shift += 60
|
shift += 60
|
||||||
|
|
||||||
lines = {}
|
self.lines = {}
|
||||||
if "elevation" in self._y:
|
if "bed_elevation" in self._y:
|
||||||
|
|
||||||
ax = self._axes[unit["elevation"]]
|
ax = self._axes[unit["bed_elevation"]]
|
||||||
line = ax.plot(
|
line = ax.plot(
|
||||||
rk, z_min,
|
rk, z_min,
|
||||||
color='grey', lw=1.,
|
color='grey', lw=1.,
|
||||||
)
|
)
|
||||||
lines["elevation"] = line
|
self.lines["bed_elevation"] = line
|
||||||
|
|
||||||
|
if self._envelop and reach.has_sediment():
|
||||||
|
|
||||||
|
ax = self._axes[unit["bed_elevation_envelop"]]
|
||||||
|
|
||||||
|
e = list(
|
||||||
|
map(
|
||||||
|
lambda p: max(self.get_ts_zmin(p)),
|
||||||
|
range(len(reach))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
line1 = ax.plot(
|
||||||
|
rk, e,
|
||||||
|
color='grey', lw=1.,
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
self.lines["bed_elevation_envelop"] = line1
|
||||||
|
|
||||||
|
e = list(
|
||||||
|
map(
|
||||||
|
lambda p: min(self.get_ts_zmin(p)),
|
||||||
|
range(len(reach))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
line2 = ax.plot(
|
||||||
|
rk, e,
|
||||||
|
color='grey', lw=1.,
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
# self.lines["bed_elevation_envelop"] = line2
|
||||||
|
|
||||||
if "water_elevation" in self._y:
|
if "water_elevation" in self._y:
|
||||||
|
|
||||||
|
|
@ -122,14 +245,46 @@ class CustomPlot(PamhyrPlot):
|
||||||
rk, z, lw=1.,
|
rk, z, lw=1.,
|
||||||
color='blue',
|
color='blue',
|
||||||
)
|
)
|
||||||
lines["water_elevation"] = line
|
self.lines["water_elevation"] = line
|
||||||
|
|
||||||
if "elevation" in self._y:
|
if "bed_elevation" in self._y:
|
||||||
ax.fill_between(
|
self.fill = ax.fill_between(
|
||||||
rk, z_min, z,
|
rk, z_min, z,
|
||||||
color='blue', alpha=0.5, interpolate=True
|
color='blue', alpha=0.5, interpolate=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self._envelop:
|
||||||
|
|
||||||
|
ax = self._axes[unit["water_elevation_envelop"]]
|
||||||
|
|
||||||
|
d = list(
|
||||||
|
map(
|
||||||
|
lambda p: max(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
line1 = ax.plot(
|
||||||
|
rk, d, lw=1.,
|
||||||
|
color='blue',
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
self.lines["water_elevation_envelop"] = line1
|
||||||
|
|
||||||
|
d = list(
|
||||||
|
map(
|
||||||
|
lambda p: min(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
line2 = ax.plot(
|
||||||
|
rk, d, lw=1.,
|
||||||
|
color='blue',
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
# self.lines["water_elevation_envelop2"] = line2
|
||||||
|
|
||||||
if "discharge" in self._y:
|
if "discharge" in self._y:
|
||||||
|
|
||||||
ax = self._axes[unit["discharge"]]
|
ax = self._axes[unit["discharge"]]
|
||||||
|
|
@ -137,7 +292,37 @@ class CustomPlot(PamhyrPlot):
|
||||||
rk, q, lw=1.,
|
rk, q, lw=1.,
|
||||||
color='r',
|
color='r',
|
||||||
)
|
)
|
||||||
lines["discharge"] = line
|
self.lines["discharge"] = line
|
||||||
|
|
||||||
|
if self._envelop:
|
||||||
|
|
||||||
|
ax = self._axes[unit["discharge_envelop"]]
|
||||||
|
|
||||||
|
q1 = list(
|
||||||
|
map(
|
||||||
|
lambda p: max(p.get_key("Q")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
line1 = ax.plot(
|
||||||
|
rk, q1, lw=1.,
|
||||||
|
color='r',
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
self.lines["discharge_envelop"] = line1
|
||||||
|
|
||||||
|
q2 = list(
|
||||||
|
map(
|
||||||
|
lambda p: min(p.get_key("Q")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
line2 = ax.plot(
|
||||||
|
rk, q2, lw=1.,
|
||||||
|
color='r',
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
# self.lines["discharge_envelop2"] = line2
|
||||||
|
|
||||||
if "velocity" in self._y:
|
if "velocity" in self._y:
|
||||||
|
|
||||||
|
|
@ -155,11 +340,40 @@ class CustomPlot(PamhyrPlot):
|
||||||
rk, v, lw=1.,
|
rk, v, lw=1.,
|
||||||
color='g',
|
color='g',
|
||||||
)
|
)
|
||||||
lines["velocity"] = line
|
self.lines["velocity"] = line
|
||||||
|
|
||||||
if "max_depth" in self._y:
|
if self._envelop:
|
||||||
|
|
||||||
ax = self._axes[unit["max_depth"]]
|
velocities = list(map(
|
||||||
|
lambda p: list(map(
|
||||||
|
lambda q, z:
|
||||||
|
p.geometry.speed(q, z),
|
||||||
|
p.get_key("Q"), p.get_key("Z")
|
||||||
|
)), reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
ax = self._axes[unit["velocity_envelop"]]
|
||||||
|
vmax = [max(v) for v in velocities]
|
||||||
|
|
||||||
|
line1 = ax.plot(
|
||||||
|
rk, vmax, lw=1.,
|
||||||
|
color='g',
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
self.lines["velocity_envelop"] = line1
|
||||||
|
vmin = [min(v) for v in velocities]
|
||||||
|
|
||||||
|
line2 = ax.plot(
|
||||||
|
rk, vmin, lw=1.,
|
||||||
|
color='g',
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
# self.lines["velocity_envelop2"] = line2
|
||||||
|
|
||||||
|
if "depth" in self._y:
|
||||||
|
|
||||||
|
ax = self._axes[unit["depth"]]
|
||||||
d = list(
|
d = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.geometry.max_water_depth(
|
lambda p: p.geometry.max_water_depth(
|
||||||
|
|
@ -171,7 +385,37 @@ class CustomPlot(PamhyrPlot):
|
||||||
rk, d,
|
rk, d,
|
||||||
color='brown', lw=1.,
|
color='brown', lw=1.,
|
||||||
)
|
)
|
||||||
lines["max_depth"] = line
|
self.lines["depth"] = line
|
||||||
|
|
||||||
|
if self._envelop:
|
||||||
|
|
||||||
|
ax = self._axes[unit["depth_envelop"]]
|
||||||
|
|
||||||
|
d = list(map(
|
||||||
|
lambda p1, p2: p1 - p2, map(
|
||||||
|
lambda p: max(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
), z_min)
|
||||||
|
)
|
||||||
|
line1 = ax.plot(
|
||||||
|
rk, d,
|
||||||
|
color='brown', lw=1.,
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
self.lines["depth_envelop"] = line1
|
||||||
|
|
||||||
|
d = list(map(
|
||||||
|
lambda p1, p2: p1 - p2, map(
|
||||||
|
lambda p: min(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
), z_min)
|
||||||
|
)
|
||||||
|
line2 = ax.plot(
|
||||||
|
rk, d,
|
||||||
|
color='brown', lw=1.,
|
||||||
|
linestyle='dotted',
|
||||||
|
)
|
||||||
|
# self.lines["depth_envelop2"] = line2
|
||||||
|
|
||||||
if "mean_depth" in self._y:
|
if "mean_depth" in self._y:
|
||||||
|
|
||||||
|
|
@ -188,7 +432,7 @@ class CustomPlot(PamhyrPlot):
|
||||||
rk, d,
|
rk, d,
|
||||||
color='orange', lw=1.,
|
color='orange', lw=1.,
|
||||||
)
|
)
|
||||||
lines["mean_depth"] = line
|
self.lines["mean_depth"] = line
|
||||||
|
|
||||||
if "froude" in self._y:
|
if "froude" in self._y:
|
||||||
|
|
||||||
|
|
@ -212,7 +456,7 @@ class CustomPlot(PamhyrPlot):
|
||||||
line = ax.plot(
|
line = ax.plot(
|
||||||
rk, fr, color='black', linestyle='--', lw=1.,
|
rk, fr, color='black', linestyle='--', lw=1.,
|
||||||
)
|
)
|
||||||
lines["froude"] = line
|
self.lines["froude"] = line
|
||||||
|
|
||||||
if "wet_area" in self._y:
|
if "wet_area" in self._y:
|
||||||
|
|
||||||
|
|
@ -229,17 +473,115 @@ class CustomPlot(PamhyrPlot):
|
||||||
rk, d,
|
rk, d,
|
||||||
color='blue', linestyle='--', lw=1.,
|
color='blue', linestyle='--', lw=1.,
|
||||||
)
|
)
|
||||||
lines["wet_area"] = line
|
self.lines["wet_area"] = line
|
||||||
|
|
||||||
# Legend
|
# Legend
|
||||||
lns = reduce(
|
lns = reduce(
|
||||||
lambda acc, line: acc + line,
|
lambda acc, line: acc + line,
|
||||||
map(lambda line: lines[line], lines),
|
map(lambda line: self.lines[line], self.lines),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
labs = list(map(lambda line: self._trad[line], lines))
|
labs = list(map(lambda line: self._trad[line], self.lines))
|
||||||
self.canvas.axes.legend(lns, labs, loc="best")
|
self.canvas.axes.legend(lns, labs, loc="best")
|
||||||
|
|
||||||
|
def _redraw_rk(self):
|
||||||
|
results = self.data
|
||||||
|
reach = results.river.reach(self._reach)
|
||||||
|
rk = reach.geometry.get_rk()
|
||||||
|
z_min = reach.geometry.get_z_min()
|
||||||
|
if reach.has_sediment():
|
||||||
|
z_min = self.draw_bottom_with_bedload(reach)
|
||||||
|
else:
|
||||||
|
z_min = reach.geometry.get_z_min()
|
||||||
|
|
||||||
|
q = list(
|
||||||
|
map(
|
||||||
|
lambda p: p.get_ts_key(self._timestamp, "Q"),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
z = list(
|
||||||
|
map(
|
||||||
|
lambda p: p.get_ts_key(self._timestamp, "Z"),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if "bed_elevation" in self._y:
|
||||||
|
self.lines["bed_elevation"][0].set_ydata(z_min)
|
||||||
|
|
||||||
|
if "water_elevation" in self._y:
|
||||||
|
self.lines["water_elevation"][0].set_ydata(z)
|
||||||
|
|
||||||
|
if "bed_elevation" in self._y:
|
||||||
|
ax = self._axes[unit["water_elevation"]]
|
||||||
|
self.fill.remove()
|
||||||
|
self.fill = ax.fill_between(
|
||||||
|
rk, z_min, z,
|
||||||
|
color='blue', alpha=0.5, interpolate=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if "discharge" in self._y:
|
||||||
|
self.lines["discharge"][0].set_ydata(q)
|
||||||
|
|
||||||
|
if "velocity" in self._y:
|
||||||
|
v = list(
|
||||||
|
map(
|
||||||
|
lambda p: p.geometry.speed(
|
||||||
|
p.get_ts_key(self._timestamp, "Q"),
|
||||||
|
p.get_ts_key(self._timestamp, "Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.lines["discharge"][0].set_ydata(v)
|
||||||
|
|
||||||
|
if "depth" in self._y:
|
||||||
|
d = list(
|
||||||
|
map(
|
||||||
|
lambda p: p.geometry.max_water_depth(
|
||||||
|
p.get_ts_key(self._timestamp, "Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.lines["depth"][0].set_ydata(d)
|
||||||
|
|
||||||
|
if "mean_depth" in self._y:
|
||||||
|
d = list(
|
||||||
|
map(
|
||||||
|
lambda p: p.geometry.mean_water_depth(
|
||||||
|
p.get_ts_key(self._timestamp, "Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.lines["mean_depth"][0].set_ydata(d)
|
||||||
|
|
||||||
|
if "froude" in self._y:
|
||||||
|
fr = list(
|
||||||
|
map(
|
||||||
|
lambda p:
|
||||||
|
p.geometry.speed(
|
||||||
|
p.get_ts_key(self._timestamp, "Q"),
|
||||||
|
p.get_ts_key(self._timestamp, "Z")) /
|
||||||
|
sqrt(9.81 * (
|
||||||
|
p.geometry.wet_area(
|
||||||
|
p.get_ts_key(self._timestamp, "Z")) /
|
||||||
|
p.geometry.wet_width(
|
||||||
|
p.get_ts_key(self._timestamp, "Z"))
|
||||||
|
)),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.lines["froude"][0].set_ydata(fr)
|
||||||
|
|
||||||
|
if "wet_area" in self._y:
|
||||||
|
d = list(
|
||||||
|
map(
|
||||||
|
lambda p: p.geometry.wet_area(
|
||||||
|
p.get_ts_key(self._timestamp, "Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.lines["wet_area"][0].set_ydata(d)
|
||||||
|
|
||||||
def _customize_x_axes_time(self, ts, mode="time"):
|
def _customize_x_axes_time(self, ts, mode="time"):
|
||||||
# Custom time display
|
# Custom time display
|
||||||
nb = len(ts)
|
nb = len(ts)
|
||||||
|
|
@ -301,24 +643,27 @@ class CustomPlot(PamhyrPlot):
|
||||||
q = profile.get_key("Q")
|
q = profile.get_key("Q")
|
||||||
z = profile.get_key("Z")
|
z = profile.get_key("Z")
|
||||||
z_min = profile.geometry.z_min()
|
z_min = profile.geometry.z_min()
|
||||||
ts_z_min = list(
|
if reach.has_sediment():
|
||||||
map(
|
ts_z_min = self.get_ts_zmin(self._profile)
|
||||||
lambda ts: z_min,
|
else:
|
||||||
ts
|
ts_z_min = list(
|
||||||
|
map(
|
||||||
|
lambda ts: z_min,
|
||||||
|
ts
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
lines = {}
|
self.lines = {}
|
||||||
if "elevation" in self._y:
|
if "bed_elevation" in self._y:
|
||||||
# Z min is constant in time
|
# Z min is constant in time
|
||||||
|
|
||||||
ax = self._axes[unit["elevation"]]
|
ax = self._axes[unit["bed_elevation"]]
|
||||||
|
|
||||||
line = ax.plot(
|
line = ax.plot(
|
||||||
ts, ts_z_min,
|
ts, ts_z_min,
|
||||||
color='grey', lw=1.
|
color='grey', lw=1.
|
||||||
)
|
)
|
||||||
lines["elevation"] = line
|
self.lines["bed_elevation"] = line
|
||||||
|
|
||||||
if "water_elevation" in self._y:
|
if "water_elevation" in self._y:
|
||||||
|
|
||||||
|
|
@ -327,11 +672,11 @@ class CustomPlot(PamhyrPlot):
|
||||||
ts, z, lw=1.,
|
ts, z, lw=1.,
|
||||||
color='b',
|
color='b',
|
||||||
)
|
)
|
||||||
lines["water_elevation"] = line
|
self.lines["water_elevation"] = line
|
||||||
|
|
||||||
if "elevation" in self._y:
|
if "bed_elevation" in self._y:
|
||||||
|
|
||||||
ax.fill_between(
|
self.fill = ax.fill_between(
|
||||||
ts, ts_z_min, z,
|
ts, ts_z_min, z,
|
||||||
color='blue', alpha=0.5, interpolate=True
|
color='blue', alpha=0.5, interpolate=True
|
||||||
)
|
)
|
||||||
|
|
@ -343,7 +688,7 @@ class CustomPlot(PamhyrPlot):
|
||||||
ts, q, lw=1.,
|
ts, q, lw=1.,
|
||||||
color='r',
|
color='r',
|
||||||
)
|
)
|
||||||
lines["discharge"] = line
|
self.lines["discharge"] = line
|
||||||
|
|
||||||
if "velocity" in self._y:
|
if "velocity" in self._y:
|
||||||
|
|
||||||
|
|
@ -359,11 +704,11 @@ class CustomPlot(PamhyrPlot):
|
||||||
ts, v, lw=1.,
|
ts, v, lw=1.,
|
||||||
color='g',
|
color='g',
|
||||||
)
|
)
|
||||||
lines["velocity"] = line
|
self.lines["velocity"] = line
|
||||||
|
|
||||||
if "max_depth" in self._y:
|
if "depth" in self._y:
|
||||||
|
|
||||||
ax = self._axes[unit["max_depth"]]
|
ax = self._axes[unit["depth"]]
|
||||||
d = list(
|
d = list(
|
||||||
map(lambda z: profile.geometry.max_water_depth(z), z)
|
map(lambda z: profile.geometry.max_water_depth(z), z)
|
||||||
)
|
)
|
||||||
|
|
@ -372,7 +717,7 @@ class CustomPlot(PamhyrPlot):
|
||||||
ts, d,
|
ts, d,
|
||||||
color='brown', lw=1.,
|
color='brown', lw=1.,
|
||||||
)
|
)
|
||||||
lines["max_depth"] = line
|
self.lines["depth"] = line
|
||||||
|
|
||||||
if "mean_depth" in self._y:
|
if "mean_depth" in self._y:
|
||||||
|
|
||||||
|
|
@ -385,7 +730,7 @@ class CustomPlot(PamhyrPlot):
|
||||||
ts, d,
|
ts, d,
|
||||||
color='orange', lw=1.,
|
color='orange', lw=1.,
|
||||||
)
|
)
|
||||||
lines["mean_depth"] = line
|
self.lines["mean_depth"] = line
|
||||||
|
|
||||||
if "froude" in self._y:
|
if "froude" in self._y:
|
||||||
|
|
||||||
|
|
@ -402,7 +747,7 @@ class CustomPlot(PamhyrPlot):
|
||||||
line = ax.plot(
|
line = ax.plot(
|
||||||
ts, d, color='black', linestyle='--', lw=1.,
|
ts, d, color='black', linestyle='--', lw=1.,
|
||||||
)
|
)
|
||||||
lines["froude"] = line
|
self.lines["froude"] = line
|
||||||
|
|
||||||
if "wet_area" in self._y:
|
if "wet_area" in self._y:
|
||||||
|
|
||||||
|
|
@ -414,21 +759,108 @@ class CustomPlot(PamhyrPlot):
|
||||||
line = ax.plot(
|
line = ax.plot(
|
||||||
ts, d, color='blue', linestyle='--', lw=1.,
|
ts, d, color='blue', linestyle='--', lw=1.,
|
||||||
)
|
)
|
||||||
lines["wet_area"] = line
|
self.lines["wet_area"] = line
|
||||||
|
|
||||||
self._customize_x_axes_time(ts)
|
self._customize_x_axes_time(ts)
|
||||||
|
|
||||||
# Legend
|
# Legend
|
||||||
lns = reduce(
|
lns = reduce(
|
||||||
lambda acc, line: acc + line,
|
lambda acc, line: acc + line,
|
||||||
map(lambda line: lines[line], lines),
|
map(lambda line: self.lines[line], self.lines),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
labs = list(map(lambda line: self._trad[line], lines))
|
labs = list(map(lambda line: self._trad[line], self.lines))
|
||||||
self.canvas.axes.legend(lns, labs, loc="best")
|
self.canvas.axes.legend(lns, labs, loc="best")
|
||||||
|
|
||||||
@timer
|
def _redraw_time(self):
|
||||||
|
|
||||||
|
results = self.data
|
||||||
|
reach = results.river.reach(self._reach)
|
||||||
|
profile = reach.profile(self._profile)
|
||||||
|
ts = list(results.get("timestamps"))
|
||||||
|
ts.sort()
|
||||||
|
|
||||||
|
q = profile.get_key("Q")
|
||||||
|
z = profile.get_key("Z")
|
||||||
|
if reach.has_sediment():
|
||||||
|
ts_z_min = self.get_ts_zmin(self._profile)
|
||||||
|
else:
|
||||||
|
z_min = profile.geometry.z_min()
|
||||||
|
ts_z_min = list(
|
||||||
|
map(
|
||||||
|
lambda ts: z_min,
|
||||||
|
ts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if "bed_elevation" in self._y:
|
||||||
|
self.lines["bed_elevation"][0].set_ydata(ts_z_min)
|
||||||
|
|
||||||
|
if "water_elevation" in self._y:
|
||||||
|
self.lines["water_elevation"][0].set_ydata(z)
|
||||||
|
|
||||||
|
if "bed_elevation" in self._y:
|
||||||
|
ax = self._axes[unit["bed_elevation"]]
|
||||||
|
self.fill.remove()
|
||||||
|
self.fill = ax.fill_between(
|
||||||
|
ts, ts_z_min, z,
|
||||||
|
color='blue', alpha=0.5, interpolate=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if "discharge" in self._y:
|
||||||
|
self.lines["discharge"][0].set_ydata(q)
|
||||||
|
|
||||||
|
if "velocity" in self._y:
|
||||||
|
v = list(
|
||||||
|
map(
|
||||||
|
lambda q, z: profile.geometry.speed(q, z),
|
||||||
|
q, z
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.lines["velocity"][0].set_ydata(v)
|
||||||
|
|
||||||
|
if "depth" in self._y:
|
||||||
|
d = list(
|
||||||
|
map(lambda z: profile.geometry.max_water_depth(z), z)
|
||||||
|
)
|
||||||
|
self.lines["depth"][0].set_ydata(d)
|
||||||
|
|
||||||
|
if "mean_depth" in self._y:
|
||||||
|
d = list(
|
||||||
|
map(lambda z: profile.geometry.mean_water_depth(z), z)
|
||||||
|
)
|
||||||
|
self.lines["mean_depth"][0].set_ydata(d)
|
||||||
|
|
||||||
|
if "froude" in self._y:
|
||||||
|
d = list(
|
||||||
|
map(lambda z, q:
|
||||||
|
profile.geometry.speed(q, z) /
|
||||||
|
sqrt(9.81 * (
|
||||||
|
profile.geometry.wet_area(z) /
|
||||||
|
profile.geometry.wet_width(z))
|
||||||
|
), z, q)
|
||||||
|
)
|
||||||
|
self.lines["froude"][0].set_ydata(d)
|
||||||
|
|
||||||
|
if "wet_area" in self._y:
|
||||||
|
d = list(
|
||||||
|
map(lambda z: profile.geometry.wet_area(z), z)
|
||||||
|
)
|
||||||
|
self.lines["wet_area"][0].set_ydata(d)
|
||||||
|
|
||||||
|
self.canvas.axes.relim(visible_only=True)
|
||||||
|
self.canvas.axes.autoscale_view()
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
|
self.draw_static()
|
||||||
|
|
||||||
|
def draw_update(self):
|
||||||
|
if self._x == "rk":
|
||||||
|
self._redraw_rk()
|
||||||
|
elif self._x == "time":
|
||||||
|
self._redraw_time()
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def draw_static(self):
|
||||||
self.canvas.axes.cla()
|
self.canvas.axes.cla()
|
||||||
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
|
self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
|
||||||
|
|
||||||
|
|
@ -478,16 +910,16 @@ class CustomPlot(PamhyrPlot):
|
||||||
lw=1.,
|
lw=1.,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.canvas.figure.canvas.draw_idle()
|
|
||||||
if self.toolbar is not None:
|
if self.toolbar is not None:
|
||||||
self.toolbar.update()
|
self.toolbar.update()
|
||||||
|
self.canvas.draw_idle()
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def update(self):
|
def update(self):
|
||||||
if not self._init:
|
self.draw_update()
|
||||||
self.draw()
|
self.draw_current()
|
||||||
self.draw_current()
|
# self.draw_static()
|
||||||
return
|
return
|
||||||
|
|
||||||
def set_reach(self, reach_id):
|
def set_reach(self, reach_id):
|
||||||
self._reach = reach_id
|
self._reach = reach_id
|
||||||
|
|
@ -519,4 +951,5 @@ class CustomPlot(PamhyrPlot):
|
||||||
elif self._x == "time":
|
elif self._x == "time":
|
||||||
x = self._timestamp
|
x = self._timestamp
|
||||||
self._current.set_data([x, x], self.canvas.axes.get_ylim())
|
self._current.set_data([x, x], self.canvas.axes.get_ylim())
|
||||||
self.canvas.figure.canvas.draw_idle()
|
self.canvas.draw_idle()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,21 @@ class CustomPlotTranslate(ResultsTranslate):
|
||||||
self._dict['time'] = self._dict["unit_time_s"]
|
self._dict['time'] = self._dict["unit_time_s"]
|
||||||
self._dict['rk'] = self._dict["unit_rk"]
|
self._dict['rk'] = self._dict["unit_rk"]
|
||||||
self._dict['water_elevation'] = self._dict["unit_water_elevation"]
|
self._dict['water_elevation'] = self._dict["unit_water_elevation"]
|
||||||
|
self._dict['water_elevation_envelop'] = self._dict[
|
||||||
|
"unit_water_elevation_envelop"
|
||||||
|
]
|
||||||
self._dict['discharge'] = self._dict["unit_discharge"]
|
self._dict['discharge'] = self._dict["unit_discharge"]
|
||||||
self._dict['elevation'] = _translate(
|
self._dict['discharge_envelop'] = self._dict["unit_discharge_envelop"]
|
||||||
"CustomPlot", "Bed elevation (m)"
|
self._dict['bed_elevation'] = self._dict["unit_bed_elevation"]
|
||||||
)
|
self._dict['bed_elevation_envelop'] = self._dict[
|
||||||
self._dict['velocity'] = self._dict["unit_speed"]
|
"unit_bed_elevation_envelop"
|
||||||
|
]
|
||||||
|
self._dict['velocity'] = self._dict["unit_velocity"]
|
||||||
self._dict['width'] = self._dict["unit_width"]
|
self._dict['width'] = self._dict["unit_width"]
|
||||||
self._dict['max_depth'] = self._dict["unit_max_height"]
|
self._dict['velocity_envelop'] = self._dict["unit_velocity_envelop"]
|
||||||
self._dict['mean_depth'] = self._dict["unit_mean_height"]
|
self._dict['depth'] = self._dict["unit_depth"]
|
||||||
|
self._dict['depth_envelop'] = self._dict["unit_depth_envelop"]
|
||||||
|
self._dict['mean_depth'] = self._dict["unit_mean_depth"]
|
||||||
self._dict['wet_area'] = self._dict["unit_wet_area"]
|
self._dict['wet_area'] = self._dict["unit_wet_area"]
|
||||||
self._dict['wet_perimeter'] = self._dict["unit_wet_perimeter"]
|
self._dict['wet_perimeter'] = self._dict["unit_wet_perimeter"]
|
||||||
self._dict['hydraulic_radius'] = self._dict["unit_hydraulic_radius"]
|
self._dict['hydraulic_radius'] = self._dict["unit_hydraulic_radius"]
|
||||||
|
|
@ -55,7 +62,7 @@ class CustomPlotTranslate(ResultsTranslate):
|
||||||
"CustomPlot", "Elevation (m)"
|
"CustomPlot", "Elevation (m)"
|
||||||
)
|
)
|
||||||
self._dict['1-m3s'] = self._dict["unit_discharge"]
|
self._dict['1-m3s'] = self._dict["unit_discharge"]
|
||||||
self._dict['2-ms'] = self._dict["unit_speed"]
|
self._dict['2-ms'] = self._dict["unit_velocity"]
|
||||||
self._dict['3-meter'] = self._dict["unit_height"]
|
self._dict['3-meter'] = self._dict["unit_depth"]
|
||||||
self._dict['4-dimensionless'] = self._dict["unit_froude"]
|
self._dict['4-dimensionless'] = self._dict["unit_froude"]
|
||||||
self._dict['5-m2'] = self._dict["wet_area"]
|
self._dict['5-m2'] = self._dict["wet_area"]
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,9 @@ class PlotXY(PamhyrPlot):
|
||||||
return
|
return
|
||||||
|
|
||||||
reach = self.results.river.reach(self._current_reach_id)
|
reach = self.results.river.reach(self._current_reach_id)
|
||||||
|
reaches = self.results.river.reachs
|
||||||
|
|
||||||
self.draw_profiles(reach)
|
self.draw_profiles(reach, reaches)
|
||||||
self.draw_water_elevation(reach)
|
self.draw_water_elevation(reach)
|
||||||
self.draw_water_elevation_max(reach)
|
self.draw_water_elevation_max(reach)
|
||||||
self.draw_guide_lines(reach)
|
self.draw_guide_lines(reach)
|
||||||
|
|
@ -156,12 +157,12 @@ class PlotXY(PamhyrPlot):
|
||||||
self.idle()
|
self.idle()
|
||||||
self._init = True
|
self._init = True
|
||||||
|
|
||||||
def draw_profiles(self, reach):
|
def draw_profiles(self, reach, reaches):
|
||||||
if reach.geometry.number_profiles == 0:
|
if reach.geometry.number_profiles == 0:
|
||||||
self._init = False
|
self._init = False
|
||||||
return
|
return
|
||||||
|
# TODO uncomment to draw all the reaches
|
||||||
self.line_xy = []
|
# self.draw_other_profiles(reaches)
|
||||||
for xy in zip(reach.geometry.get_x(),
|
for xy in zip(reach.geometry.get_x(),
|
||||||
reach.geometry.get_y()):
|
reach.geometry.get_y()):
|
||||||
self.line_xy.append(np.column_stack(xy))
|
self.line_xy.append(np.column_stack(xy))
|
||||||
|
|
@ -176,6 +177,19 @@ class PlotXY(PamhyrPlot):
|
||||||
)
|
)
|
||||||
self.canvas.axes.add_collection(self.line_xy_collection)
|
self.canvas.axes.add_collection(self.line_xy_collection)
|
||||||
|
|
||||||
|
def draw_other_profiles(self, reaches):
|
||||||
|
|
||||||
|
for reach in reaches:
|
||||||
|
for xy in zip(reach.geometry.get_x(),
|
||||||
|
reach.geometry.get_y()):
|
||||||
|
self.line_xy.append(np.column_stack(xy))
|
||||||
|
|
||||||
|
self.line_xy_collection = collections.LineCollection(
|
||||||
|
self.line_xy,
|
||||||
|
colors=self.color_plot_river_bottom,
|
||||||
|
)
|
||||||
|
self.canvas.axes.add_collection(self.line_xy_collection)
|
||||||
|
|
||||||
def draw_guide_lines(self, reach):
|
def draw_guide_lines(self, reach):
|
||||||
x_complete = reach.geometry.get_guidelines_x()
|
x_complete = reach.geometry.get_guidelines_x()
|
||||||
y_complete = reach.geometry.get_guidelines_y()
|
y_complete = reach.geometry.get_guidelines_y()
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ class TableModel(PamhyrTableModel):
|
||||||
z = self._lst[row].get_ts_key(self._timestamp, "Z")
|
z = self._lst[row].get_ts_key(self._timestamp, "Z")
|
||||||
v = self._lst[row].geometry.wet_width(z)
|
v = self._lst[row].geometry.wet_width(z)
|
||||||
return f"{v:.4f}"
|
return f"{v:.4f}"
|
||||||
elif self._headers[column] == "max_depth":
|
elif self._headers[column] == "depth":
|
||||||
z = self._lst[row].get_ts_key(self._timestamp, "Z")
|
z = self._lst[row].get_ts_key(self._timestamp, "Z")
|
||||||
v = self._lst[row].geometry.max_water_depth(z)
|
v = self._lst[row].geometry.max_water_depth(z)
|
||||||
return f"{v:.4f}"
|
return f"{v:.4f}"
|
||||||
|
|
|
||||||
|
|
@ -490,11 +490,13 @@ class ResultsWindow(PamhyrWindow):
|
||||||
def _add_custom_plot(self):
|
def _add_custom_plot(self):
|
||||||
dlg = CustomPlotValuesSelectionDialog(parent=self)
|
dlg = CustomPlotValuesSelectionDialog(parent=self)
|
||||||
if dlg.exec():
|
if dlg.exec():
|
||||||
x, y = dlg.value
|
x, y, envelop = dlg.value
|
||||||
self.create_new_tab_custom_plot(x, y)
|
self.create_new_tab_custom_plot(x, y, envelop)
|
||||||
|
|
||||||
def create_new_tab_custom_plot(self, x: str, y: list):
|
def create_new_tab_custom_plot(self, x: str, y: list, envelop: bool):
|
||||||
name = f"{x}: {','.join(y)}"
|
name = f"{x}: {','.join(y)}"
|
||||||
|
if envelop and x == "rk":
|
||||||
|
name += "_envelop"
|
||||||
wname = f"tab_custom_{x}_{y}"
|
wname = f"tab_custom_{x}_{y}"
|
||||||
|
|
||||||
tab_widget = self.find(QTabWidget, f"tabWidget")
|
tab_widget = self.find(QTabWidget, f"tabWidget")
|
||||||
|
|
@ -518,7 +520,7 @@ class ResultsWindow(PamhyrWindow):
|
||||||
)
|
)
|
||||||
|
|
||||||
plot = CustomPlot(
|
plot = CustomPlot(
|
||||||
x, y,
|
x, y, envelop,
|
||||||
self._get_current_reach(),
|
self._get_current_reach(),
|
||||||
self._get_current_profile(),
|
self._get_current_profile(),
|
||||||
self._get_current_timestamp(),
|
self._get_current_timestamp(),
|
||||||
|
|
@ -589,7 +591,7 @@ class ResultsWindow(PamhyrWindow):
|
||||||
|
|
||||||
dlg = CustomPlotValuesSelectionDialog(parent=self)
|
dlg = CustomPlotValuesSelectionDialog(parent=self)
|
||||||
if dlg.exec():
|
if dlg.exec():
|
||||||
x, y = dlg.value
|
x, y, envelop = dlg.value
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -599,32 +601,39 @@ class ResultsWindow(PamhyrWindow):
|
||||||
)
|
)
|
||||||
self.file_dialog(
|
self.file_dialog(
|
||||||
select_file="AnyFile",
|
select_file="AnyFile",
|
||||||
callback=lambda f: self.export_to(f[0], x, y),
|
callback=lambda f: self.export_to(f[0], x, y, envelop),
|
||||||
default_suffix=".csv",
|
default_suffix=".csv",
|
||||||
file_filter=["CSV (*.csv)"],
|
file_filter=["CSV (*.csv)"],
|
||||||
)
|
)
|
||||||
|
|
||||||
def export_to(self, filename, x, y):
|
def export_to(self, filename, x, y, envelop):
|
||||||
timestamps = sorted(self._results.get("timestamps"))
|
timestamps = sorted(self._results.get("timestamps"))
|
||||||
|
reach = self._results.river.reachs[self._get_current_reach()]
|
||||||
|
first_line = [f"Study: {self._results.study.name}",
|
||||||
|
f"Reach: {reach.name}"]
|
||||||
if x == "rk":
|
if x == "rk":
|
||||||
timestamp = self._get_current_timestamp()
|
timestamp = self._get_current_timestamp()
|
||||||
val_dict = self._export_rk(timestamp, y, filename)
|
first_line.append(f"Time: {timestamp}s")
|
||||||
|
val_dict = self._export_rk(timestamp, y, envelop, filename)
|
||||||
elif x == "time":
|
elif x == "time":
|
||||||
profile = self._get_current_profile()
|
profile_id = self._get_current_profile()
|
||||||
val_dict = self._export_time(profile, y, filename)
|
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, filename)
|
||||||
|
|
||||||
with open(filename, 'w', newline='') as csvfile:
|
with open(filename, 'w', newline='') as csvfile:
|
||||||
writer = csv.writer(csvfile, delimiter=',',
|
writer = csv.writer(csvfile, delimiter=',',
|
||||||
quotechar='|', quoting=csv.QUOTE_MINIMAL)
|
quotechar='|', quoting=csv.QUOTE_MINIMAL)
|
||||||
dict_x = self._trad.get_dict("values_x")
|
dict_x = self._trad.get_dict("values_x")
|
||||||
dict_y = self._trad.get_dict("values_y")
|
header = []
|
||||||
header = [dict_x[x]]
|
writer.writerow(first_line)
|
||||||
for text in y:
|
for text in val_dict.keys():
|
||||||
header.append(dict_y[text])
|
header.append(text)
|
||||||
writer.writerow(header)
|
writer.writerow(header)
|
||||||
for row in range(len(val_dict[x])):
|
for row in range(len(val_dict[dict_x[x]])):
|
||||||
line = [val_dict[x][row]]
|
line = []
|
||||||
for var in y:
|
for var in val_dict.keys():
|
||||||
line.append(val_dict[var][row])
|
line.append(val_dict[var][row])
|
||||||
writer.writerow(line)
|
writer.writerow(line)
|
||||||
|
|
||||||
|
|
@ -666,28 +675,60 @@ class ResultsWindow(PamhyrWindow):
|
||||||
self._additional_plot.pop(tab_widget.tabText(index))
|
self._additional_plot.pop(tab_widget.tabText(index))
|
||||||
tab_widget.removeTab(index)
|
tab_widget.removeTab(index)
|
||||||
|
|
||||||
def _export_rk(self, timestamp, y, filename):
|
def _export_rk(self, timestamp, y, envelop, filename):
|
||||||
reach = self._results.river.reachs[self._get_current_reach()]
|
reach = self._results.river.reachs[self._get_current_reach()]
|
||||||
|
dict_x = self._trad.get_dict("values_x")
|
||||||
|
dict_y = self._trad.get_dict("values_y")
|
||||||
|
if envelop:
|
||||||
|
dict_y.update(self._trad.get_dict("values_y_envelop"))
|
||||||
my_dict = {}
|
my_dict = {}
|
||||||
my_dict["rk"] = reach.geometry.get_rk()
|
my_dict[dict_x["rk"]] = reach.geometry.get_rk()
|
||||||
if "elevation" in y:
|
if "bed_elevation" in y:
|
||||||
my_dict["elevation"] = reach.geometry.get_z_min()
|
my_dict[dict_y["bed_elevation"]] = reach.geometry.get_z_min()
|
||||||
|
#if envelop and reach.has_sediment():
|
||||||
if "discharge" in y:
|
if "discharge" in y:
|
||||||
my_dict["discharge"] = list(
|
my_dict[dict_y["discharge"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.get_ts_key(timestamp, "Q"),
|
lambda p: p.get_ts_key(timestamp, "Q"),
|
||||||
reach.profiles
|
reach.profiles
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if envelop:
|
||||||
|
my_dict[dict_y["min_discharge"]] = list(
|
||||||
|
map(
|
||||||
|
lambda p: min(p.get_key("Q")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
my_dict[dict_y["max_discharge"]] = list(
|
||||||
|
map(
|
||||||
|
lambda p: max(p.get_key("Q")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
if "water_elevation" in y:
|
if "water_elevation" in y:
|
||||||
my_dict["water_elevation"] = list(
|
my_dict[dict_y["water_elevation"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.get_ts_key(timestamp, "Z"),
|
lambda p: p.get_ts_key(timestamp, "Z"),
|
||||||
reach.profiles
|
reach.profiles
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if envelop:
|
||||||
|
my_dict[dict_y["min_water_elevation"]] = list(
|
||||||
|
map(
|
||||||
|
lambda p: min(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
my_dict[dict_y["max_water_elevation"]] = list(
|
||||||
|
map(
|
||||||
|
lambda p: max(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if "velocity" in y:
|
if "velocity" in y:
|
||||||
my_dict["velocity"] = list(
|
my_dict[dict_y["velocity"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.geometry.speed(
|
lambda p: p.geometry.speed(
|
||||||
p.get_ts_key(timestamp, "Q"),
|
p.get_ts_key(timestamp, "Q"),
|
||||||
|
|
@ -695,16 +736,44 @@ class ResultsWindow(PamhyrWindow):
|
||||||
reach.profiles
|
reach.profiles
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if "max_depth" in y:
|
if envelop:
|
||||||
my_dict["max_depth"] = list(
|
velocities = list(map(
|
||||||
|
lambda p: list(map(
|
||||||
|
lambda q, z:
|
||||||
|
p.geometry.speed(q, z),
|
||||||
|
p.get_key("Q"), p.get_key("Z")
|
||||||
|
)), reach.profiles
|
||||||
|
)
|
||||||
|
)
|
||||||
|
my_dict[dict_y["min_velocity"]] = [min(v) for v in velocities]
|
||||||
|
my_dict[dict_y["max_velocity"]] = [max(v) for v in velocities]
|
||||||
|
|
||||||
|
if "depth" in y:
|
||||||
|
my_dict[dict_y["depth"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.geometry.max_water_depth(
|
lambda p: p.geometry.max_water_depth(
|
||||||
p.get_ts_key(timestamp, "Z")),
|
p.get_ts_key(timestamp, "Z")),
|
||||||
reach.profiles
|
reach.profiles
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if envelop:
|
||||||
|
my_dict[dict_y["min_depth"]] = list(map(
|
||||||
|
lambda p1, p2: p1 - p2, map(
|
||||||
|
lambda p: min(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
), reach.geometry.get_z_min()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
my_dict[dict_y["max_depth"]] = list(map(
|
||||||
|
lambda p1, p2: p1 - p2, map(
|
||||||
|
lambda p: max(p.get_key("Z")),
|
||||||
|
reach.profiles
|
||||||
|
), reach.geometry.get_z_min()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if "mean_depth" in y:
|
if "mean_depth" in y:
|
||||||
my_dict["mean_depth"] = list(
|
my_dict[dict_y["mean_depth"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.geometry.mean_water_depth(
|
lambda p: p.geometry.mean_water_depth(
|
||||||
p.get_ts_key(timestamp, "Z")),
|
p.get_ts_key(timestamp, "Z")),
|
||||||
|
|
@ -712,7 +781,7 @@ class ResultsWindow(PamhyrWindow):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if "froude" in y:
|
if "froude" in y:
|
||||||
my_dict["froude"] = list(
|
my_dict[dict_y["froude"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda p:
|
lambda p:
|
||||||
p.geometry.speed(
|
p.geometry.speed(
|
||||||
|
|
@ -728,7 +797,7 @@ class ResultsWindow(PamhyrWindow):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if "wet_area" in y:
|
if "wet_area" in y:
|
||||||
my_dict["wet_area"] = list(
|
my_dict[dict_y["wet_area"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda p: p.geometry.wet_area(
|
lambda p: p.geometry.wet_area(
|
||||||
p.get_ts_key(timestamp, "Z")),
|
p.get_ts_key(timestamp, "Z")),
|
||||||
|
|
@ -743,33 +812,36 @@ class ResultsWindow(PamhyrWindow):
|
||||||
profile = reach.profile(profile)
|
profile = reach.profile(profile)
|
||||||
ts = list(self._results.get("timestamps"))
|
ts = list(self._results.get("timestamps"))
|
||||||
ts.sort()
|
ts.sort()
|
||||||
|
dict_x = self._trad.get_dict("values_x")
|
||||||
|
dict_y = self._trad.get_dict("values_y")
|
||||||
my_dict = {}
|
my_dict = {}
|
||||||
my_dict["time"] = ts
|
my_dict[dict_x["time"]] = ts
|
||||||
z = profile.get_key("Z")
|
z = profile.get_key("Z")
|
||||||
q = profile.get_key("Q")
|
q = profile.get_key("Q")
|
||||||
if "elevation" in y:
|
if "bed_elevation" in y:
|
||||||
my_dict["elevation"] = [profile.geometry.z_min()] * len(ts)
|
my_dict[dict_y["bed_elevation"]] = [
|
||||||
|
profile.geometry.z_min()] * len(ts)
|
||||||
if "discharge" in y:
|
if "discharge" in y:
|
||||||
my_dict["discharge"] = q
|
my_dict[dict_y["discharge"]] = q
|
||||||
if "water_elevation" in y:
|
if "water_elevation" in y:
|
||||||
my_dict["water_elevation"] = z
|
my_dict[dict_y["water_elevation"]] = z
|
||||||
if "velocity" in y:
|
if "velocity" in y:
|
||||||
my_dict["velocity"] = list(
|
my_dict[dict_y["velocity"]] = list(
|
||||||
map(
|
map(
|
||||||
lambda q, z: profile.geometry.speed(q, z),
|
lambda q, z: profile.geometry.speed(q, z),
|
||||||
q, z
|
q, z
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if "max_depth" in y:
|
if "depth" in y:
|
||||||
my_dict["max_depth"] = list(
|
my_dict[dict_y["depth"]] = list(
|
||||||
map(lambda z: profile.geometry.max_water_depth(z), z)
|
map(lambda z: profile.geometry.max_water_depth(z), z)
|
||||||
)
|
)
|
||||||
if "mean_depth" in y:
|
if "mean_depth" in y:
|
||||||
my_dict["mean_depth"] = list(
|
my_dict[dict_y["mean_depth"]] = list(
|
||||||
map(lambda z: profile.geometry.mean_water_depth(z), z)
|
map(lambda z: profile.geometry.mean_water_depth(z), z)
|
||||||
)
|
)
|
||||||
if "froude" in y:
|
if "froude" in y:
|
||||||
my_dict["froude"] = list(
|
my_dict[dict_y["froude"]] = list(
|
||||||
map(lambda z, q:
|
map(lambda z, q:
|
||||||
profile.geometry.speed(q, z) /
|
profile.geometry.speed(q, z) /
|
||||||
sqrt(9.81 * (
|
sqrt(9.81 * (
|
||||||
|
|
@ -778,7 +850,7 @@ class ResultsWindow(PamhyrWindow):
|
||||||
), z, q)
|
), z, q)
|
||||||
)
|
)
|
||||||
if "wet_area" in y:
|
if "wet_area" in y:
|
||||||
my_dict["wet_area"] = list(
|
my_dict[dict_y["wet_area"]] = list(
|
||||||
map(lambda z: profile.geometry.wet_area(z), z)
|
map(lambda z: profile.geometry.wet_area(z), z)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ class ResultsTranslate(MainTranslate):
|
||||||
"name": _translate("Results", "Profile"),
|
"name": _translate("Results", "Profile"),
|
||||||
"water_elevation": self._dict["unit_water_elevation"],
|
"water_elevation": self._dict["unit_water_elevation"],
|
||||||
"discharge": self._dict["unit_discharge"],
|
"discharge": self._dict["unit_discharge"],
|
||||||
"velocity": self._dict["unit_speed"],
|
"velocity": self._dict["unit_velocity"],
|
||||||
"width": self._dict["unit_width"],
|
"width": self._dict["unit_width"],
|
||||||
"max_depth": self._dict["unit_max_height"],
|
"depth": self._dict["unit_depth"],
|
||||||
"mean_depth": self._dict["unit_mean_height"],
|
"mean_depth": self._dict["unit_mean_depth"],
|
||||||
"wet_area": self._dict["unit_wet_area"],
|
"wet_area": self._dict["unit_wet_area"],
|
||||||
"wet_perimeter": self._dict["unit_wet_perimeter"],
|
"wet_perimeter": self._dict["unit_wet_perimeter"],
|
||||||
"hydraulic_radius": self._dict["unit_hydraulic_radius"],
|
"hydraulic_radius": self._dict["unit_hydraulic_radius"],
|
||||||
|
|
@ -88,12 +88,12 @@ class ResultsTranslate(MainTranslate):
|
||||||
}
|
}
|
||||||
|
|
||||||
self._sub_dict["values_y"] = {
|
self._sub_dict["values_y"] = {
|
||||||
"elevation": self._dict["unit_elevation"],
|
"bed_elevation": self._dict["unit_bed_elevation"],
|
||||||
"water_elevation": self._dict["unit_water_elevation"],
|
"water_elevation": self._dict["unit_water_elevation"],
|
||||||
"discharge": self._dict["unit_discharge"],
|
"discharge": self._dict["unit_discharge"],
|
||||||
"velocity": self._dict["unit_speed"],
|
"velocity": self._dict["unit_velocity"],
|
||||||
"max_depth": self._dict["unit_max_height"],
|
"depth": self._dict["unit_depth"],
|
||||||
"mean_depth": self._dict["unit_mean_height"],
|
"mean_depth": self._dict["unit_mean_depth"],
|
||||||
"froude": self._dict["unit_froude"],
|
"froude": self._dict["unit_froude"],
|
||||||
"wet_area": self._dict["unit_wet_area"],
|
"wet_area": self._dict["unit_wet_area"],
|
||||||
}
|
}
|
||||||
|
|
@ -110,6 +110,18 @@ class ResultsTranslate(MainTranslate):
|
||||||
"name": _translate("Results", "Profile"),
|
"name": _translate("Results", "Profile"),
|
||||||
"water_elevation": self._dict["unit_water_elevation"],
|
"water_elevation": self._dict["unit_water_elevation"],
|
||||||
"discharge": self._dict["unit_discharge"],
|
"discharge": self._dict["unit_discharge"],
|
||||||
"speed": self._dict["unit_speed"],
|
"discharge": self._dict["unit_discharge"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._sub_dict["values_y_envelop"] = {
|
||||||
|
"min_bed_elevation": self._dict["unit_min_bed_elevation"],
|
||||||
|
"max_bed_elevation": self._dict["unit_max_bed_elevation"],
|
||||||
|
"min_water_elevation": self._dict["unit_min_water_elevation"],
|
||||||
|
"max_water_elevation": self._dict["unit_max_water_elevation"],
|
||||||
|
"min_discharge": self._dict["unit_min_discharge"],
|
||||||
|
"max_discharge": self._dict["unit_max_discharge"],
|
||||||
|
"min_velocity": self._dict["unit_min_velocity"],
|
||||||
|
"max_velocity": self._dict["unit_max_velocity"],
|
||||||
|
"min_depth": self._dict["unit_min_depth"],
|
||||||
|
"max_depth": self._dict["unit_max_depth"],
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class Plot(PamhyrPlot):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.label_x = self._trad["rk"]
|
self.label_x = self._trad["rk"]
|
||||||
self.label_y = self._trad["height"]
|
self.label_y = self._trad["elevation"]
|
||||||
|
|
||||||
self.line_rk_zmin = None
|
self.line_rk_zmin = None
|
||||||
self.line_rk_sl = []
|
self.line_rk_sl = []
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class Plot(PamhyrPlot):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.label_x = self._trad["x"]
|
self.label_x = self._trad["x"]
|
||||||
self.label_y = self._trad["height"]
|
self.label_y = self._trad["elevation"]
|
||||||
|
|
||||||
self.line_rk_zmin = None
|
self.line_rk_zmin = None
|
||||||
self.line_rk_sl = []
|
self.line_rk_sl = []
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class SedimentProfileTranslate(SedimentReachTranslate):
|
||||||
self._dict["x"] = _translate(
|
self._dict["x"] = _translate(
|
||||||
"SedimentLayers", "X (m)"
|
"SedimentLayers", "X (m)"
|
||||||
)
|
)
|
||||||
self._dict["height"] = self._dict["unit_height"]
|
self._dict["elevation"] = self._dict["unit_elevation"]
|
||||||
|
|
||||||
self._dict["Profile sediment layers"] = _translate(
|
self._dict["Profile sediment layers"] = _translate(
|
||||||
"SedimentLayers", "Profile sediment layers"
|
"SedimentLayers", "Profile sediment layers"
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class SedimentReachTranslate(SedimentTranslate):
|
||||||
)
|
)
|
||||||
|
|
||||||
self._dict["rk"] = self._dict["unit_rk"]
|
self._dict["rk"] = self._dict["unit_rk"]
|
||||||
self._dict["height"] = self._dict["unit_height"]
|
self._dict["elevation"] = self._dict["unit_elevation"]
|
||||||
|
|
||||||
self._sub_dict["table_headers"] = {
|
self._sub_dict["table_headers"] = {
|
||||||
"name": self._dict["name"],
|
"name": self._dict["name"],
|
||||||
|
|
|
||||||
|
|
@ -57,18 +57,65 @@ class UnitTranslate(CommonWordTranslate):
|
||||||
|
|
||||||
self._dict["unit_rk"] = _translate("Unit", "River Kilometer (m)")
|
self._dict["unit_rk"] = _translate("Unit", "River Kilometer (m)")
|
||||||
self._dict["unit_width"] = _translate("Unit", "Width (m)")
|
self._dict["unit_width"] = _translate("Unit", "Width (m)")
|
||||||
self._dict["unit_height"] = _translate("Unit", "Depth (m)")
|
self._dict["unit_width_envelop"] = _translate(
|
||||||
self._dict["unit_max_height"] = _translate("Unit", "Max Depth (m)")
|
"Unit", "Width Envelop (m)"
|
||||||
self._dict["unit_mean_height"] = _translate("Unit", "Mean Depth (m)")
|
)
|
||||||
|
self._dict["unit_max_width"] = _translate("Unit", "Max Width (m)")
|
||||||
|
self._dict["unit_min_width"] = _translate("Unit", "Min Width (m)")
|
||||||
|
self._dict["unit_depth"] = _translate("Unit", "Depth (m)")
|
||||||
|
self._dict["unit_max_depth"] = _translate("Unit", "Max Depth (m)")
|
||||||
|
self._dict["unit_min_depth"] = _translate("Unit", "Min Depth (m)")
|
||||||
|
self._dict["unit_depth_envelop"] = _translate(
|
||||||
|
"Unit", "Depth Envelop (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_mean_depth"] = _translate("Unit", "Mean Depth (m)")
|
||||||
self._dict["unit_diameter"] = _translate("Unit", "Diameter (m)")
|
self._dict["unit_diameter"] = _translate("Unit", "Diameter (m)")
|
||||||
self._dict["unit_thickness"] = _translate("Unit", "Thickness (m)")
|
self._dict["unit_thickness"] = _translate("Unit", "Thickness (m)")
|
||||||
self._dict["unit_elevation"] = _translate("Unit", "Elevation (m)")
|
self._dict["unit_elevation"] = _translate("Unit", "Elevation (m)")
|
||||||
self._dict["unit_water_elevation"] = _translate(
|
self._dict["unit_bed_elevation"] = _translate(
|
||||||
"Unit", "Water elevation (m)"
|
"Unit", "Bed Elevation (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_bed_elevation_envelop"] = _translate(
|
||||||
|
"Unit", "Bed Elevation Envelop (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_max_bed_elevation"] = _translate(
|
||||||
|
"Unit", "Max Bed Elevation (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_min_bed_elevation"] = _translate(
|
||||||
|
"Unit", "Min Bed Elevation (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_water_elevation"] = _translate(
|
||||||
|
"Unit", "Water Elevation (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_water_elevation_envelop"] = _translate(
|
||||||
|
"Unit", "Water Elevation Envelop (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_max_water_elevation"] = _translate(
|
||||||
|
"Unit", "Max Water Elevation (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_min_water_elevation"] = _translate(
|
||||||
|
"Unit", "Min Water Elevation (m)"
|
||||||
|
)
|
||||||
|
self._dict["unit_velocity"] = _translate("Unit", "Velocity (m/s)")
|
||||||
|
self._dict["unit_velocity_envelop"] = _translate(
|
||||||
|
"Unit", "Velocity Envelop (m/s)"
|
||||||
|
)
|
||||||
|
self._dict["unit_max_velocity"] = _translate(
|
||||||
|
"Unit", "Max Velocity (m/s)"
|
||||||
|
)
|
||||||
|
self._dict["unit_min_velocity"] = _translate(
|
||||||
|
"Unit", "Min Velocity (m/s)"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._dict["unit_speed"] = _translate("Unit", "Velocity (m/s)")
|
|
||||||
self._dict["unit_discharge"] = _translate("Unit", "Discharge (m^3/s)")
|
self._dict["unit_discharge"] = _translate("Unit", "Discharge (m^3/s)")
|
||||||
|
self._dict["unit_discharge_envelop"] = _translate(
|
||||||
|
"Unit", "Discharge Envelop (m^3/s)"
|
||||||
|
)
|
||||||
|
self._dict["unit_max_discharge"] = _translate(
|
||||||
|
"Unit", "Max Discharge (m^3/s)"
|
||||||
|
)
|
||||||
|
self._dict["unit_min_discharge"] = _translate(
|
||||||
|
"Unit", "Min Discharge (m^3/s)"
|
||||||
|
)
|
||||||
self._dict["unit_area"] = _translate("Unit", "Area (hectare)")
|
self._dict["unit_area"] = _translate("Unit", "Area (hectare)")
|
||||||
|
|
||||||
self._dict["unit_time_s"] = _translate("Unit", "Time (sec)")
|
self._dict["unit_time_s"] = _translate("Unit", "Time (sec)")
|
||||||
|
|
@ -146,3 +193,5 @@ class MainTranslate(UnitTranslate):
|
||||||
"MainWindow",
|
"MainWindow",
|
||||||
"Do you want to save current study before closing it?"
|
"Do you want to save current study before closing it?"
|
||||||
)
|
)
|
||||||
|
self._dict["x"] = _translate("MainWindow", "X (m)")
|
||||||
|
self._dict["y"] = _translate("MainWindow", "Y (m)")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!DOCTYPE TS><TS version="2.0" language="fr_FR" sourcelanguage="en_150">
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1" language="fr_FR" sourcelanguage="en_150">
|
||||||
<context>
|
<context>
|
||||||
<name>About</name>
|
<name>About</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -1167,7 +1168,7 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/ui/about.ui" line="94"/>
|
<location filename="../View/ui/about.ui" line="94"/>
|
||||||
<source>Copyright © 2022-2024 INRAE</source>
|
<source>Copyright © 2022-2024 INRAE</source>
|
||||||
<translation type="obsolete">Copyright © 2022-2024 INRAE</translation>
|
<translation type="obsolete">Copyright © 2022-2024 INRAE</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
|
@ -1175,11 +1176,6 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
<source>Version: @version @codename</source>
|
<source>Version: @version @codename</source>
|
||||||
<translation>Version : @version @codename</translation>
|
<translation>Version : @version @codename</translation>
|
||||||
</message>
|
</message>
|
||||||
<message encoding="UTF-8">
|
|
||||||
<location filename="../View/ui/about.ui" line="94"/>
|
|
||||||
<source>Copyright © 2022-2024 INRAE</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Frictions</name>
|
<name>Frictions</name>
|
||||||
|
|
@ -1456,17 +1452,17 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
<context>
|
<context>
|
||||||
<name>MainWindow</name>
|
<name>MainWindow</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="98"/>
|
<location filename="../View/Translate.py" line="97"/>
|
||||||
<source>Open debug window</source>
|
<source>Open debug window</source>
|
||||||
<translation>Ouvrir la fenêtre de débogage</translation>
|
<translation>Ouvrir la fenêtre de débogage</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="101"/>
|
<location filename="../View/Translate.py" line="100"/>
|
||||||
<source>Open SQLite debuging tool ('sqlitebrowser')</source>
|
<source>Open SQLite debuging tool ('sqlitebrowser')</source>
|
||||||
<translation>Ouvrir l'outil de débogage SQLite ('sqlitebrowser')</translation>
|
<translation>Ouvrir l'outil de débogage SQLite ('sqlitebrowser')</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="104"/>
|
<location filename="../View/Translate.py" line="103"/>
|
||||||
<source>Enable this window</source>
|
<source>Enable this window</source>
|
||||||
<translation>Activer cette fenêtre</translation>
|
<translation>Activer cette fenêtre</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2311,12 +2307,12 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
<translation>Maillage</translation>
|
<translation>Maillage</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="91"/>
|
<location filename="../View/Translate.py" line="90"/>
|
||||||
<source>Summary</source>
|
<source>Summary</source>
|
||||||
<translation>Résumé</translation>
|
<translation>Résumé</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="94"/>
|
<location filename="../View/Translate.py" line="93"/>
|
||||||
<source>Checks</source>
|
<source>Checks</source>
|
||||||
<translation>Vérifications</translation>
|
<translation>Vérifications</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2536,7 +2532,7 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
<translation>Données</translation>
|
<translation>Données</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="112"/>
|
<location filename="../View/Translate.py" line="111"/>
|
||||||
<source>Please select a reach</source>
|
<source>Please select a reach</source>
|
||||||
<translation>Veuillez sélectionner un bief</translation>
|
<translation>Veuillez sélectionner un bief</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2546,35 +2542,45 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
<translation type="obsolete">L'édition de la géométrie nécessite un bief sélectionné dans le réseau fluvial pour pouvoir travailler dessus</translation>
|
<translation type="obsolete">L'édition de la géométrie nécessite un bief sélectionné dans le réseau fluvial pour pouvoir travailler dessus</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="121"/>
|
<location filename="../View/Translate.py" line="120"/>
|
||||||
<source>Last open study</source>
|
<source>Last open study</source>
|
||||||
<translation>Dernière étude ouverte</translation>
|
<translation>Dernière étude ouverte</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="124"/>
|
<location filename="../View/Translate.py" line="123"/>
|
||||||
<source>Do you want to open again the last open study?</source>
|
<source>Do you want to open again the last open study?</source>
|
||||||
<translation>Voulez-vous rouvrir la dernière étude ?</translation>
|
<translation>Voulez-vous rouvrir la dernière étude ?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="115"/>
|
<location filename="../View/Translate.py" line="114"/>
|
||||||
<source>This edition window need a reach selected into the river network to work on it</source>
|
<source>This edition window need a reach selected into the river network to work on it</source>
|
||||||
<translation>Cette fenêtre d'édition a besoin d'un bief sélectionné dans le réseau pour travailler dessus</translation>
|
<translation>Cette fenêtre d'édition a besoin d'un bief sélectionné dans le réseau pour travailler dessus</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="129"/>
|
<location filename="../View/Translate.py" line="128"/>
|
||||||
<source>Close without saving study</source>
|
<source>Close without saving study</source>
|
||||||
<translation>Fermer sans sauvegarder l'étude</translation>
|
<translation>Fermer sans sauvegarder l'étude</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="132"/>
|
<location filename="../View/Translate.py" line="131"/>
|
||||||
<source>Do you want to save current study before closing it?</source>
|
<source>Do you want to save current study before closing it?</source>
|
||||||
<translation>Souhaitez-vous sauvegarder l'étude en cours avant de la fermer ?</translation>
|
<translation>Souhaitez-vous sauvegarder l'étude en cours avant de la fermer ?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="109"/>
|
<location filename="../View/Translate.py" line="108"/>
|
||||||
<source>Warning</source>
|
<source>Warning</source>
|
||||||
<translation>Avertissement</translation>
|
<translation>Avertissement</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/Translate.py" line="135"/>
|
||||||
|
<source>X (m)</source>
|
||||||
|
<translation>X (m)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/Translate.py" line="136"/>
|
||||||
|
<source>Y (m)</source>
|
||||||
|
<translation>Y (m)</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MainWindow_reach</name>
|
<name>MainWindow_reach</name>
|
||||||
|
|
@ -3255,17 +3261,17 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
<translation>Vitesse (m/s)</translation>
|
<translation>Vitesse (m/s)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="78"/>
|
<location filename="../View/Translate.py" line="77"/>
|
||||||
<source>Wet Perimeter (m)</source>
|
<source>Wet Perimeter (m)</source>
|
||||||
<translation>Périmètre mouillé (m)</translation>
|
<translation>Périmètre mouillé (m)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="81"/>
|
<location filename="../View/Translate.py" line="80"/>
|
||||||
<source>Hydraulic Radius (m)</source>
|
<source>Hydraulic Radius (m)</source>
|
||||||
<translation>Rayon hydraulique (m)</translation>
|
<translation>Rayon hydraulique (m)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="84"/>
|
<location filename="../View/Translate.py" line="83"/>
|
||||||
<source>Froude number</source>
|
<source>Froude number</source>
|
||||||
<translation>Nombre de Froude</translation>
|
<translation>Nombre de Froude</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3277,6 +3283,11 @@ Cette fonctionnalité nécessite un bief muni d'une géométrie.</translati
|
||||||
<message>
|
<message>
|
||||||
<location filename="../View/Translate.py" line="77"/>
|
<location filename="../View/Translate.py" line="77"/>
|
||||||
<source>Wet Area (m^2)</source>
|
<source>Wet Area (m^2)</source>
|
||||||
|
<translation type="obsolete">Aire mouillée (m²)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../View/Translate.py" line="76"/>
|
||||||
|
<source>Wet Area (m²)</source>
|
||||||
<translation>Aire mouillée (m²)</translation>
|
<translation>Aire mouillée (m²)</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue