mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58f72cfa6b | ||
|
|
69134303d2 | ||
|
|
5d0109769d | ||
|
|
6852b08cfc | ||
|
|
2896c604a5 | ||
|
|
b21b6be9ca | ||
|
|
5f043468ee | ||
|
|
e25a3ae98c | ||
|
|
38560cdcf5 | ||
|
|
7cd4d070ac | ||
|
|
e6b36f3fe5 | ||
|
|
36597d9b3d | ||
|
|
c4e965a631 | ||
|
|
15da23183b | ||
|
|
77baba0893 | ||
|
|
a19ab7aa79 | ||
|
|
29d4c7c146 | ||
|
|
69f40748e5 | ||
|
|
37a9122aa8 | ||
|
|
a1cdb1ad56 | ||
|
|
fef93209cd | ||
|
|
932e4a0f98 | ||
|
|
149b150eda | ||
|
|
3adce567df | ||
|
|
e842fef434 | ||
|
|
1c89b7fb1b | ||
|
|
fdebac3b6a | ||
|
|
85d6feec01 | ||
|
|
0fffc85f6c |
No files matched your search
@@ -39,6 +39,9 @@ __old__
|
||||
|
||||
*-venv
|
||||
|
||||
mage8
|
||||
adists
|
||||
|
||||
### END CUSTOM ###
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
|
||||
+126
-77
@@ -28,20 +28,6 @@
|
||||
#+OPTIONS: toc:t
|
||||
#+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
|
||||
This document is for the use of developers. It describes the project
|
||||
architecture, the tools available to assist development and
|
||||
@@ -54,13 +40,13 @@ documentation, translations or code.
|
||||
|
||||
* 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
|
||||
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
|
||||
{{{file(/requirements.txt)}}} for details). The architecture of
|
||||
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
|
||||
build with the gitlab-ci (see the section [[Setup the CI
|
||||
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
|
||||
|
||||
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
|
||||
model (in blue), the graphical components (in red), the
|
||||
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
|
||||
|
||||
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
|
||||
=Model.Tools.SQLSubModel= abstract class, except the =Model.Study=
|
||||
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)
|
||||
#+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]].
|
||||
|
||||
#+NAME: sql_schema
|
||||
#+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]]
|
||||
|
||||
|
||||
@@ -486,7 +472,7 @@ PamhyrModelList but use a dictionary instead of list.
|
||||
|
||||
** 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]])
|
||||
and "Qt linguist" for interface translate (see [[Translate]]). In
|
||||
addition, we use matplotlib as ploting library (see [[Plot]]).
|
||||
@@ -501,11 +487,11 @@ componant translate, and possible other files or sub-directories.
|
||||
|
||||
*** UI file
|
||||
|
||||
We define as possible all Pamhyr2 windows and custom widgets with "Qt
|
||||
designer". This application generate UI file who describes interface
|
||||
organisation with table, layout, button, etc. This method is faster
|
||||
than hand made windows and widget creation, and saves us some purely
|
||||
descriptive code. The UI files are saved into =src/View/ui= for
|
||||
We define as possible all {{{pamhyr2}}} windows and custom widgets
|
||||
with "Qt designer". This application generate UI file who describes
|
||||
interface organisation with table, layout, button, etc. This method is
|
||||
faster than hand made windows and widget creation, and saves us some
|
||||
purely descriptive code. The UI files are saved into =src/View/ui= for
|
||||
window, and =/src/View/ui/Widgets= for custom widget.
|
||||
|
||||
*** Translate
|
||||
@@ -533,10 +519,11 @@ window, and =/src/View/ui/Widgets= for custom widget.
|
||||
|
||||
*** Window
|
||||
|
||||
The abstract class PamhyrWindow and PamhyrDialog are used for most of
|
||||
Pamhyr2 window. These class allow to create an window for Pamhyr2 GUI
|
||||
and implemente some useful methods. The super class method difine some
|
||||
generic value from optional parameters, for examples:
|
||||
The abstract class =PamhyrWindow= and =PamhyrDialog= are used for most
|
||||
of {{{pamhyr2}}} window. These class allow to create an window for
|
||||
{{{pamhyr2}}} GUI and implemente some useful methods. The super class
|
||||
method difine some generic value from optional parameters, for
|
||||
examples:
|
||||
- =self._study=: The study giving in constructor parameters =study=
|
||||
(typically a =Model.Study= class object)
|
||||
- =self._config=: The configuration giving in constructor parameters
|
||||
@@ -546,7 +533,7 @@ generic value from optional parameters, for examples:
|
||||
object)
|
||||
|
||||
#+NAME: window
|
||||
#+CAPTION: Example of Pamhyr2 window
|
||||
#+CAPTION: Example of {{{pamhyr2}}} window
|
||||
#+begin_src python :python python3 :results output :noweb yes
|
||||
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||
from View.My.Translate import MyTranslate
|
||||
@@ -593,7 +580,7 @@ window componants or connections.
|
||||
|
||||
*** 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=
|
||||
and =setData= methode to implement, but the constructor needs more
|
||||
information than a classic QAbstractTableModel class.
|
||||
@@ -654,7 +641,7 @@ class AddNodeCommand(QUndoCommand):
|
||||
|
||||
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
|
||||
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
|
||||
creation, this stack is accessible at =self._undo_stack=.
|
||||
|
||||
@@ -672,7 +659,7 @@ creation, this stack is accessible at =self._undo_stack=.
|
||||
*** Plot
|
||||
|
||||
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 (optional) =trad= of type =PamhyrTranslate=
|
||||
- A =data= used in =draw= and =update= to create and update the plot
|
||||
@@ -719,8 +706,8 @@ data has changed.
|
||||
|
||||
** Solver
|
||||
|
||||
The Pamhyr2 architecture allow to define multiple solver. A solver is
|
||||
define by a:
|
||||
The {{{pamhyr2}}} architecture allow to define multiple solver. A
|
||||
solver is define by a:
|
||||
- type
|
||||
- name
|
||||
- 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
|
||||
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
|
||||
Pamhyr2, but this solver must can read/write input and output generic
|
||||
format or use external script. There is possible to define different
|
||||
solver with the same type, for example two differents version of the
|
||||
same solver. Finaly, with input and output formater is possible to
|
||||
execute a code on distant computer, for example, over ssh.
|
||||
{{{pamhyr2}}}, but this solver must can read/write input and output
|
||||
generic format or use external script. There is possible to define
|
||||
different solver with the same type, for example two differents
|
||||
version of the same solver. Finaly, with input and output formater is
|
||||
possible to execute a code on distant computer, for example, over ssh.
|
||||
|
||||
#+name: graph-multi-solver
|
||||
#+header: :results drawer
|
||||
@@ -857,8 +844,8 @@ solver and get results:
|
||||
- (2.1) The solver read the input file(s)
|
||||
- (2.2) The solver compute results and write it to solver output
|
||||
file(s)
|
||||
- (3) Pamhyr2 create a =Results= object
|
||||
- (3.1) The Pamhyr2 solver class read solver output file(s) and
|
||||
- (3) {{{pamhyr2}}} create a =Results= object
|
||||
- (3.1) The {{{pamhyr2}}} solver class read solver output file(s) and
|
||||
complete Results with readed data
|
||||
|
||||
#+name: graph-pipeline
|
||||
@@ -976,7 +963,7 @@ the temporal order of action is prensented in Figure
|
||||
}
|
||||
#+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
|
||||
different methods:
|
||||
- =export=: Export the study to solver input file(s)
|
||||
@@ -987,7 +974,7 @@ different methods:
|
||||
|
||||
** 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
|
||||
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
|
||||
|
||||
To activate an deactivate the Pamhyr2 debug mode you can open the
|
||||
configuration window and type "Ctrl+G" or run Pamhyr2 with command
|
||||
line:
|
||||
To activate an deactivate the {{{pamhyr2}}} debug mode you can open
|
||||
the configuration window and type "Ctrl+G" or run {{{pamhyr2}}} with
|
||||
command line:
|
||||
#+begin_src shell
|
||||
./Pamhyr2 debug
|
||||
#+end_src
|
||||
@@ -1015,7 +1002,7 @@ data base file.
|
||||
|
||||
#+NAME: debug-repl
|
||||
#+ATTR_LATEX: :width 14cm
|
||||
#+CAPTION: Pamhyr2 debug Python REPL
|
||||
#+CAPTION: {{{pamhyr2}}} debug Python REPL
|
||||
[[./images/python-debug-repl.png]]
|
||||
|
||||
* Build the project
|
||||
@@ -1028,7 +1015,7 @@ to build packages manually.
|
||||
If you need an hand made package, you can script available in
|
||||
{{{file(packages)}}} directory.
|
||||
|
||||
*** GNU/Linux
|
||||
*** GNU/Linux {{{linux}}}
|
||||
|
||||
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
|
||||
@@ -1050,7 +1037,7 @@ cd packages
|
||||
./linux.sh
|
||||
#+end_src
|
||||
|
||||
*** Windows
|
||||
*** Windows {{{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
|
||||
@@ -1065,10 +1052,10 @@ winetricks installed.
|
||||
|
||||
** 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.
|
||||
|
||||
*** Linux
|
||||
*** Linux {{{linux}}}
|
||||
|
||||
The Linux ci-runner need some software and dependencies in addtion of
|
||||
gitlab-ci.
|
||||
@@ -1078,10 +1065,11 @@ gitlab-ci.
|
||||
emacs emacs-goodies-el \
|
||||
texlive-full \
|
||||
python3.8 python3.8-venv
|
||||
|
||||
sudo python3 -m pip install pyinstaller
|
||||
#+end_src
|
||||
|
||||
*** Windows (Wine)
|
||||
*** Windows (Wine) {{{windows}}}
|
||||
|
||||
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]].
|
||||
@@ -1090,18 +1078,77 @@ The ci-runner environment for Wine need at least wine version 8, let
|
||||
sudo apt install wine-stable winetricks
|
||||
#+end_src
|
||||
|
||||
In addition, the environment need windows version of:
|
||||
- [[https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe][Python 3.8.10]]
|
||||
- Git
|
||||
- PowerShell
|
||||
- Gitlab-ci
|
||||
**** Setup environment
|
||||
|
||||
Export Wine environment variable to set wine as 64 bits architecture
|
||||
and set the correct path for wine environment.
|
||||
|
||||
#+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]]
|
||||
|
||||
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:
|
||||
#+begin_src shell
|
||||
wine python -m pip install pyinstaller
|
||||
#+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
|
||||
|
||||
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?
|
||||
|
||||
Pamhyr2 is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License[fn:license], either
|
||||
version 3 of the License, or any later version.
|
||||
{{{pamhyr2}}} is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License[fn:license],
|
||||
either version 3 of the License, or any later version.
|
||||
|
||||
[fn:license] The GPLv3 web page:
|
||||
https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
|
||||
** 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
|
||||
regarding communication and contribution content:
|
||||
+ No gender, racial, religious or social discrimination
|
||||
+ No insults, personal attacks or potentially offensive remarks
|
||||
+ Pamhyr2 is free software, and intended to remain so, so take care
|
||||
with the licensing of libraries and external content you want to add
|
||||
to the project
|
||||
+ {{{pamhyr2}}} is free software, and intended to remain so, so take
|
||||
care with the licensing of libraries and external content you want
|
||||
to add to the project
|
||||
+ Humour or hidden easter eggs are welcome if they respect the
|
||||
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
|
||||
code, translation or documentation.
|
||||
|
||||
The Pamhyr2 copyright is owned by INRAE[fn:inrae], but we keep a
|
||||
record of each contributors. If you made a modification to pamhyr2
|
||||
software, please add your name at the end of {{{file(AUTHORS)}}} file
|
||||
and respect the Listing [[auth-format]] format. You can update this file
|
||||
information for following contribution.
|
||||
The {{{pamhyr2}}} copyright is owned by INRAE[fn:inrae], but we keep a
|
||||
record of each contributors. If you made a modification to
|
||||
{{{pamhyr2}}} software, please add your name at the end of
|
||||
{{{file(AUTHORS)}}} file and respect the Listing [[auth-format]]
|
||||
format. You can update this file information for following
|
||||
contribution.
|
||||
|
||||
#+NAME: auth-format
|
||||
#+CAPTION: =AUTHORS= file format
|
||||
@@ -1326,16 +1374,17 @@ information for following contribution.
|
||||
#+CAPTION: Current =AUTHORS= file
|
||||
#+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
|
||||
[fn:inrae] The INRAE web site: https://www.inrae.fr/
|
||||
|
||||
** Translate
|
||||
|
||||
You can improve or add translation for the project. To contribute to
|
||||
Pamhyr2 translate, you need to use Qt Linguist[fn:qt-linguist]. Open
|
||||
Qt-linguist and edit the translation ({{{file(.ts)}}}) file, finally,
|
||||
commit the new version of file and make a merge request.
|
||||
{{{pamhyr2}}} translate, you need to use Qt
|
||||
Linguist[fn:qt-linguist]. Open Qt-linguist and edit the translation
|
||||
({{{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
|
||||
{{{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.
|
||||
|
||||
#+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
|
||||
...
|
||||
LANG="fr it"
|
||||
@@ -1362,7 +1411,7 @@ https://doc.qt.io/qt-5/qtlinguist-index.html (last access 2023-09-18)
|
||||
** Code contribution
|
||||
|
||||
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
|
||||
efficient as possible. The master branch is reserved for the project
|
||||
maintainer; you can create a new branch or fork the project before the
|
||||
|
||||
@@ -0,0 +1,487 @@
|
||||
# presentation.org -- Pamhyr
|
||||
# Copyright (C) 2023 INRAE
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#+STARTUP: indent hideblocks content beamer
|
||||
|
||||
#+TITLE: SimHydro 2023
|
||||
#+SUBTITLE: \textbf{Pamhyr2}: a graphical user interface for 1D hydro-sedimentary modelling of rivers
|
||||
|
||||
# #+AUTHOR: Pierre-Antoine Rouby
|
||||
#+LATEX_HEADER: \author[Pierre-Antoine Rouby]{\textbf{Pierre-Antoine Rouby$^{*}$}, Benoît Camenen, Lionel Pénard, Léa Kieffer, Théophile Terraz\\\texttt{<pierre-antoine.rouby@inrae.fr>}^{*}}
|
||||
#+EMAIL: pierre-antoine.rouby@inrae.fr
|
||||
#+INSTITUTE: INRAE Lyon-Villerbanne, teams River Hydraulics
|
||||
#+LATEX_HEADER: \institute{INRAE Lyon-Villerbanne, River Hydraulics team}
|
||||
#+DATE: 9th November
|
||||
|
||||
#+KEYWORDS: g ui, hydraulics, sedimentary, hydro-sedimentary, 1D modelling, freesoftware, foss
|
||||
|
||||
#+OPTIONS: H:2 toc:t num:t author:nil
|
||||
#+LATEX_CLASS: beamer
|
||||
#+LATEX_CLASS_OPTIONS: [slideopt,A4,showboxes,svgnames,aspectratio=169]
|
||||
# #+LATEX_CLASS_OPTIONS: [presentation]
|
||||
#+BEAMER_THEME: default
|
||||
#+COLUMNS: %45ITEM %10BEAMER_ENV(Env) %10BEAMER_ACT(Act) %4BEAMER_COL(Col)
|
||||
|
||||
#+LANGUAGE: fr
|
||||
#+LATEX_HEADER: \usepackage[frenchb]{babel}
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :results silent :exports none
|
||||
(setq org-latex-pdf-process (list
|
||||
"latexmk -pdflatex='lualatex -shell-escape -interaction nonstopmode' -pdf -f %f"))
|
||||
|
||||
(add-to-list 'org-latex-packages-alist '("" "minted"))
|
||||
(setq org-latex-listings 'minted)
|
||||
(setq org-src-fontify-natively t)
|
||||
|
||||
(org-add-link-type
|
||||
"cite" 'ebib
|
||||
(lambda (path desc format)
|
||||
(cond
|
||||
((eq format 'html)
|
||||
(format "(<cite>%s</cite>)" path))
|
||||
((eq format 'text)
|
||||
(format "[%s]" path))
|
||||
((eq format 'latex)
|
||||
(if (or (not desc) (equal 0 (search "cite:" desc)))
|
||||
(format "\\cite{%s}" path)
|
||||
(format "\\cite[%s][%s]{%s}"
|
||||
(cadr (split-string desc ";"))
|
||||
(car (split-string desc ";")) path))))))
|
||||
#+END_SRC
|
||||
|
||||
#+LATEX_HEADER: \setbeamertemplate{footline}[frame number]
|
||||
#+LATEX_HEADER: \setbeamertemplate{headline}{}
|
||||
#+LATEX_HEADER: \usepackage{multirow}
|
||||
#+LATEX_HEADER: \usepackage{fontawesome5}
|
||||
#+LATEX_HEADER: \usepackage{tcolorbox}
|
||||
#+LATEX_HEADER: \usepackage{tikz}
|
||||
|
||||
#+LATEX_HEADER: \logo{\includegraphics[width=.1\textwidth]{../../../../../src/View/ui/ressources/Logo-INRAE.png}}
|
||||
|
||||
#+LATEX_HEADER: \newcommand{\R}[1]{\rotatebox[origin=c]{90}{#1}}
|
||||
|
||||
# Beamer colors
|
||||
#+LATEX_HEADER: \setbeamersize{text margin left=0.5cm,text margin right=0.5cm}
|
||||
#+LATEX_HEADER: \setbeamerfont{alerted text}{series=\bfseries}
|
||||
#+LATEX_HEADER: \setbeamerfont{example text}{series=\bfseries}
|
||||
|
||||
#+LATEX_HEADER: \definecolor{inrae_1}{RGB}{102,193,191}
|
||||
#+LATEX_HEADER: \definecolor{inrae_2}{RGB}{0,150,152}
|
||||
#+LATEX_HEADER: \definecolor{inrae_3}{RGB}{39,86,98}
|
||||
|
||||
#+LATEX_HEADER: \setbeamercolor{alerted text}{fg=inrae_1}
|
||||
#+LATEX_HEADER: \setbeamercolor{structure}{fg=inrae_2}
|
||||
#+LATEX_HEADER: \setbeamercolor{normal text}{fg=inrae_3}
|
||||
#+LATEX_HEADER: \setbeamercolor*{author}{fg=inrae_3}
|
||||
|
||||
#+LATEX_HEADER: \usepackage[absolute,showboxes,overlay]{textpos}
|
||||
|
||||
#+LATEX_HEADER: \TPshowboxesfalse
|
||||
#+LATEX_HEADER: \textblockorigin{5mm}{0mm}
|
||||
|
||||
# Biblio
|
||||
#+LATEX_HEADER: \usepackage{natbib}
|
||||
# #+LATEX_HEADER: \bibliographystyle{apalike}
|
||||
#+LATEX_HEADER: \setbeamertemplate{bibliography item}{}
|
||||
#+LATEX_HEADER: \renewcommand\bibfont{\scriptsize}
|
||||
#+LATEX_HEADER: \setbeamertemplate{frametitle continuation}[from second]
|
||||
#+LATEX_HEADER: \setbeamercolor*{bibliography entry title}{fg=inrae_3}
|
||||
#+LATEX_HEADER: \setbeamercolor*{bibliography entry author}{fg=inrae_3}
|
||||
#+LATEX_HEADER: \setbeamercolor*{bibliography entry location}{fg=inrae_3}
|
||||
|
||||
#+LATEX_HEADER: \usepackage{bbding}
|
||||
#+LATEX_HEADER: \usepackage{pdfpages}
|
||||
|
||||
# Renew title page
|
||||
#+LATEX_HEADER: \defbeamertemplate*{title page}{customized}[1][]
|
||||
#+LATEX_HEADER: {
|
||||
# #+LATEX_HEADER: {
|
||||
# #+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}
|
||||
# #+LATEX_HEADER: \tikz[overlay,remember picture]
|
||||
# #+LATEX_HEADER: \node[xshift=-1cm,yshift=-1cm,text width=10cm] at (current page.north east) {
|
||||
# #+LATEX_HEADER: 7$^{th}$ International Conference\\
|
||||
# #+LATEX_HEADER: 8TH-10TH November\\
|
||||
# #+LATEX_HEADER: EDF Lab - CHATOU, FRANCE
|
||||
# #+LATEX_HEADER: }
|
||||
# #+LATEX_HEADER: }
|
||||
#+LATEX_HEADER: {
|
||||
#+LATEX_HEADER: \usebeamerfont{title}\inserttitle\par
|
||||
#+LATEX_HEADER: \usebeamerfont{title}\usebeamercolor[fg]{title}
|
||||
#+LATEX_HEADER: \large New modeling paradigms for water issues?\par
|
||||
#+LATEX_HEADER: }
|
||||
#+LATEX_HEADER: \bigskip
|
||||
#+LATEX_HEADER: \begin{center}
|
||||
#+LATEX_HEADER: \usebeamerfont{subtitle}\usebeamercolor[fg]{subtitle}
|
||||
#+LATEX_HEADER: {
|
||||
#+LATEX_HEADER: \LARGE\insertsubtitle\par
|
||||
#+LATEX_HEADER: }
|
||||
#+LATEX_HEADER: \bigskip
|
||||
#+LATEX_HEADER: \usebeamerfont{author}\usebeamercolor[fg]{author}\insertauthor\par
|
||||
#+LATEX_HEADER: \bigskip
|
||||
#+LATEX_HEADER: \usebeamerfont{institute}\usebeamercolor[fg]{institute}\insertinstitute\par
|
||||
#+LATEX_HEADER: \bigskip
|
||||
#+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}\insertdate\par
|
||||
#+LATEX_HEADER: \usebeamercolor[fg]{titlegraphic}\inserttitlegraphic
|
||||
#+LATEX_HEADER: \end{center}
|
||||
#+LATEX_HEADER: }
|
||||
|
||||
# #+LATEX_HEADER: \newcommand{\tred}[1]{\textcolor{rouge_inrae}{#1}}
|
||||
|
||||
#+TODO: TODO WIP TOREVIEW | DONE
|
||||
|
||||
#+MACRO: pamhyr \textsc{PAMHyR}
|
||||
#+MACRO: pamhyr2 \textsc{Pamhyr2}
|
||||
|
||||
#+MACRO: pause \pause
|
||||
#+MACRO: framebreak \framebreak
|
||||
#+MACRO: no
|
||||
# #+MACRO: OK \checkmark
|
||||
#+MACRO: OK \faIcon{check}
|
||||
#+MACRO: bf \textbf{$1}
|
||||
|
||||
# #+latex: \frame{\tocpage}
|
||||
|
||||
* 1D hydro-sedimentary simulation at INRAE
|
||||
** COMMENT 1D river flow simulation
|
||||
*** INRAE (Lyon-Villerbanne)
|
||||
|
||||
- Mage [fn:: Mage: https://gitlab.irstea.fr/jean-baptiste.faure/mage]
|
||||
- RubarBE [fn:: RubarBE:
|
||||
https://gitlab.irstea.fr/theophile.terraz/rubarbe]
|
||||
|
||||
*** Other project
|
||||
|
||||
- Mascaret [fn:: OpenTeleMac: http://www.opentelemac.org]
|
||||
- HEC-RAS [fn:: HEC-RAS:
|
||||
https://www.hec.usace.army.mil/software/hec-ras]
|
||||
- Mike 11 [fn:: Mike11:
|
||||
https://www.mikepoweredbydhi.com/products/mike-11]
|
||||
|
||||
** {{{pamhyr}}}
|
||||
#+BEGIN_EXPORT latex
|
||||
\tikz[overlay,remember picture]
|
||||
\node[xshift=-4cm,yshift=4cm] at (current page.south east) {
|
||||
\includegraphics[width=7cm]{../images/PAMHyR.png}
|
||||
};
|
||||
#+END_EXPORT
|
||||
|
||||
{{{pamhyr}}} developed at INRAE in Java since the end of 90s
|
||||
|
||||
*** Features
|
||||
- Graphical user interface
|
||||
- Define and edit complexe 1D river models
|
||||
- Run a solver
|
||||
- Visualize simulation results
|
||||
|
||||
*** Compatibility
|
||||
- 2 solvers *Mage and RubarBE*
|
||||
# - Multi-reaches (Only for Mage)
|
||||
- Multi-platform (Linux / Windows)
|
||||
|
||||
** {{{pamhyr}}}
|
||||
#+BEGIN_EXPORT latex
|
||||
\tikz[overlay,remember picture]
|
||||
\node[xshift=-4cm,yshift=4cm] at (current page.south east) {
|
||||
\includegraphics[width=7cm]{../images/PAMHyR.png}
|
||||
};
|
||||
#+END_EXPORT
|
||||
|
||||
*** Conception issues
|
||||
- Monolingual French
|
||||
- Interface too different for each solver
|
||||
- Impossible to undo an action
|
||||
|
||||
*** Huge technical debts
|
||||
- Out dated technologies (UML $\to$ Java)
|
||||
- Unmaintained library
|
||||
- Unstable development process
|
||||
|
||||
Hard to maintain or add features to the interface
|
||||
|
||||
(No modification since 2016)
|
||||
|
||||
* Presentation of {{{pamhyr2}}}
|
||||
** {{{Pamhyr2}}} - Needs - General constraints
|
||||
|
||||
Create a new version of {{{pamhyr}}} called {{{pamhyr2}}}
|
||||
|
||||
{{{pause}}}
|
||||
|
||||
*** Constraints for users experience
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.5
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
+ *User friendly*
|
||||
+ *Multi platform* (at least Linux and Windows)
|
||||
+ *Multi language* (at least English and French)
|
||||
+ *Multi solver* (as much as possible, at least Mage and
|
||||
RubarBE)
|
||||
+ *Single save file* per study
|
||||
|
||||
{{{pause}}}
|
||||
|
||||
*** Constraints for developers experience
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.5
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
- *Common used* code library and tools
|
||||
# - *Modular* and *flexible* code
|
||||
- *Clear* architecture
|
||||
- *Free and open sources software* (FOSS)
|
||||
|
||||
** {{{Pamhyr2}}} - Needs - Features
|
||||
# #+BEGIN_EXPORT latex
|
||||
# \tikz[overlay,remember picture]
|
||||
# \node[xshift=-5cm,yshift=-2cm] at (current page.north east) {
|
||||
# \includegraphics[width=6cm]{../images/geometry_saar.png}
|
||||
# };
|
||||
# #+END_EXPORT
|
||||
|
||||
**** {{{no}}}
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.30
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
- Define and edit data
|
||||
+ River network
|
||||
+ Geometry
|
||||
+ Boundary conditions
|
||||
+ Friction
|
||||
+ Initial conditions
|
||||
+ *Sedimentary layers*
|
||||
- User meshed geometry
|
||||
- Run a solver
|
||||
- Display results
|
||||
+ Default visualisation
|
||||
+ *Customized visualisation*
|
||||
|
||||
**** {{{no}}}
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.70
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
[[../images/geometry_saar.png]]
|
||||
|
||||
** {{{pamhyr2}}} - Technical choices
|
||||
#+BEGIN_EXPORT latex
|
||||
\tikz[overlay,remember picture]
|
||||
\node[xshift=-9.3cm,yshift=-4cm] at (current page.north east) {
|
||||
\includegraphics[width=6.3cm]{../images/BC.png}
|
||||
};
|
||||
#+END_EXPORT
|
||||
|
||||
*** Technologies
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.60
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
- *Python*
|
||||
- *PyQt*
|
||||
- Qt Designer
|
||||
- Qt Linguist
|
||||
- *Matplotlib*
|
||||
- SQLite (as =*.pamhyr=)
|
||||
- *GPLv3* license (strong copyleft)
|
||||
|
||||
*** Architecture
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.35
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
- Qt Model/View
|
||||
- Multiple solvers configuration
|
||||
- *Unified interface*, as much as possible
|
||||
|
||||
** {{{pamhyr2}}} - State of the project
|
||||
#+BEGIN_EXPORT latex
|
||||
\tikz[overlay,remember picture]
|
||||
\node[xshift=-4.5cm,yshift=-2.5cm] at (current page.north east) {
|
||||
\includegraphics[width=8cm]{../images/apply_sedi.png}
|
||||
};
|
||||
#+END_EXPORT
|
||||
|
||||
*** {{{no}}}
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.40
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
|
||||
\vspace{-1.5cm}
|
||||
|
||||
\begin{center}
|
||||
\emph{Last version:} \texttt{v0.0.3}
|
||||
\end{center}
|
||||
|
||||
{{{pause}}}
|
||||
|
||||
#+latex: \begin{center}
|
||||
#+latex: \resizebox{0.9\columnwidth}{!}{
|
||||
# #+caption: Tools by methods
|
||||
#+name: tab:current-state
|
||||
#+attr_latex: :align |l|c|
|
||||
|---------------------------------+-----------------|
|
||||
| {{{bf(Features)}}} | {{{bf(State)}}} |
|
||||
|---------------------------------+-----------------|
|
||||
| Create save and load study | {{{OK}}} |
|
||||
| *Undo/Redo actions* | {{{OK}}} |
|
||||
| Edit river network | {{{OK}}} |
|
||||
| Edit geometry | {{{OK}}} |
|
||||
| Edit boundary conditions | {{{OK}}} |
|
||||
| Edit lateral contributions | {{{OK}}} |
|
||||
| Edit frictions (Stricklers) | {{{OK}}} |
|
||||
| Edit initial conditions | {{{OK}}} |
|
||||
| *Edit sedimentary layers* | {{{OK}}} |
|
||||
| Edit hydraulics structures | |
|
||||
| Edit suspended sediment | |
|
||||
| Edit polluant | |
|
||||
| Use meshing tool | WIP |
|
||||
| Run a solver | {{{OK}}} |
|
||||
| Read and display results | {{{OK}}} |
|
||||
| Customize results visualisation | WIP |
|
||||
| Generic solver input/output | |
|
||||
|---------------------------------+-----------------|
|
||||
#+latex: }
|
||||
#+latex: \end{center}
|
||||
|
||||
{{{pause}}}
|
||||
|
||||
*** {{{no}}}
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.60
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
|
||||
\vspace{2.5cm}
|
||||
|
||||
#+latex: \begin{center}
|
||||
#+latex: \resizebox{0.8\columnwidth}{!}{
|
||||
# #+caption: Tools by methods
|
||||
#+name: tab:current-state-solver
|
||||
#+attr_latex: :align |l|c|c|c|
|
||||
|----------------------------+----------------+-------------------+--------------------|
|
||||
| {{{bf(Usage)}}} | {{{bf(Mage)}}} | {{{bf(RubarBE)}}} | {{{bf(Mascaret)}}} |
|
||||
|----------------------------+----------------+-------------------+--------------------|
|
||||
| *Hydraulics* (mono reach) | {{{OK}}} | | {{{OK}}} |
|
||||
| *Hydraulics* (multi reach) | {{{OK}}} | | |
|
||||
| *Bed load evolution* | {{{OK}}} | | |
|
||||
|----------------------------+----------------+-------------------+--------------------|
|
||||
#+latex: }
|
||||
#+latex: \end{center}
|
||||
|
||||
# #+LaTeX: \vspace{0.3cm}
|
||||
|
||||
#+latex: \begin{center}
|
||||
#+latex: \resizebox{0.6\columnwidth}{!}{
|
||||
# #+caption: Tools by methods
|
||||
#+name: tab:current-state-package
|
||||
#+attr_latex: :align |l|c|c|
|
||||
|--------------------+---------------------+-------------------|
|
||||
| {{{bf(Packages)}}} | {{{bf(GNU/Linux)}}} | {{{bf(Windows)}}} |
|
||||
|--------------------+---------------------+-------------------|
|
||||
| Archive (tar/zip) | {{{OK}}} | {{{OK}}} |
|
||||
| Installer | | {{{OK}}} |
|
||||
|--------------------+---------------------+-------------------|
|
||||
#+latex: }
|
||||
#+latex: \end{center}
|
||||
|
||||
* Future work and perspective
|
||||
** Future work
|
||||
#+BEGIN_EXPORT latex
|
||||
\tikz[overlay,remember picture]
|
||||
\node[xshift=-4.8cm,yshift=-3.8cm] at (current page.north east) {
|
||||
\includegraphics[width=8.7cm]{../images/results_hydro.png}
|
||||
};
|
||||
#+END_EXPORT
|
||||
|
||||
*** Next step
|
||||
- *Meshing tools integration*
|
||||
- *Custom results visualisation*
|
||||
+ Python + matplotlib script
|
||||
- RubarBE integration
|
||||
- Hydraulics structures
|
||||
- Unified graphics theme
|
||||
|
||||
*** Open questions
|
||||
- Generic solver input/output (HDF5? CGNS? SQLite?)
|
||||
- GNU/Linux packages (Pip? Conda? Guix? Deb?)
|
||||
|
||||
** Contribution
|
||||
#+LaTeX: \begin{center}
|
||||
\faIcon{gitlab} https://gitlab.irstea.fr/theophile.terraz/pamhyr/
|
||||
#+LaTeX: \end{center}
|
||||
|
||||
*** For users
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.45
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
- Try {{{pamhyr2}}}
|
||||
- Report bug
|
||||
- Propose improvement
|
||||
- Improve translation
|
||||
- Improve user documentation
|
||||
- Improve tests cases examples
|
||||
- /Find better project name/
|
||||
|
||||
*** For developers
|
||||
:PROPERTIES:
|
||||
:BEAMER_COL: 0.45
|
||||
:BEAMER_ENV: block
|
||||
:END:
|
||||
- Add new solver / features
|
||||
- Improve sources code
|
||||
- Improve developers documentation
|
||||
- Improve unit tests
|
||||
|
||||
# * Conclusion
|
||||
** Thanks for listening
|
||||
# #+BEGIN_EXPORT latex
|
||||
# \tikz[overlay,remember picture]
|
||||
# \node[xshift=-6cm,yshift=-1.5cm,text width=10cm] at (current page.north east) {
|
||||
# {\small\emph{\alert{Journées de la modélisation 1D hydro-sédimentaire} (in french) -}
|
||||
# \emph{30 \& 31 janvier 2024, INRAE Villeurbanne - }
|
||||
# \emph{Information and inscription: }\texttt{<benoit.camenen@inrae.fr>}}
|
||||
# };
|
||||
# #+END_EXPORT
|
||||
|
||||
#+LaTeX: \begin{center}
|
||||
\faIcon{gitlab} https://gitlab.irstea.fr/theophile.terraz/pamhyr/
|
||||
#+LaTeX: \end{center}
|
||||
|
||||
#+LaTeX: \begin{center}
|
||||
/*Journées de la modélisation 1D hydro-sédimentaire*/ (in French)
|
||||
#+LaTeX: \\
|
||||
/30 & 31 janvier 2024/, INRAE Villeurbanne
|
||||
#+LaTeX: \\
|
||||
Information and registration: =<benoit.camenen@inrae.fr>=
|
||||
#+LaTeX: \end{center}
|
||||
|
||||
- {{{pamhyr2}}} developers:
|
||||
+ =<pierre-antoine.rouby@inrae.fr>=,
|
||||
+ =<theophile.terraz@inrae.fr>=
|
||||
- Mage/RubarBE developer:
|
||||
+ =<theophile.terraz@inrae.fr>=
|
||||
|
||||
# #+LaTeX: \vspace{0.5cm}
|
||||
# #+LaTeX: \begin{center}
|
||||
# #+LaTeX: {\Large
|
||||
# *Thanks for listening*
|
||||
# #+LaTeX: }
|
||||
# #+LaTeX: \end{center}
|
||||
@@ -163,3 +163,7 @@
|
||||
\SetWatermarkScale{3}
|
||||
\SetWatermarkFontSize{1cm}
|
||||
\SetWatermarkText{Work in progress}
|
||||
|
||||
%% Icons
|
||||
|
||||
\usepackage{fontawesome5}
|
||||
+19
-5
@@ -17,11 +17,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Constant name
|
||||
#+MACRO: oldPamhyr PAMHyR
|
||||
#+MACRO: Pamhyr Pamhyr2
|
||||
#+MACRO: Mage Mage
|
||||
#+MACRO: Rubarbe RubarBE
|
||||
#+MACRO: Inrae INRAE
|
||||
#+MACRO: pamhyr \textsc{PAMHyR}
|
||||
#+MACRO: pamhyr2 \textsc{Pamhyr2}
|
||||
#+MACRO: mage \textsc{Mage}
|
||||
#+MACRO: mage7 \textsc{Mage7}
|
||||
#+MACRO: mage8 \textsc{Mage8}
|
||||
#+MACRO: rubarbe \textsc{RubarBE}
|
||||
#+MACRO: adists \textsc{AdisTS}
|
||||
#+MACRO: mascaret \textsc{Mascaret}
|
||||
#+MACRO: inrae INRAE
|
||||
#+MACRO: latex \LaTeX
|
||||
|
||||
# Information
|
||||
@@ -35,6 +39,16 @@
|
||||
#+MACRO: cite [cite:$1]
|
||||
#+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
|
||||
#+NAME: attr_wrap
|
||||
#+HEADER: :var width="\\textwidth"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#! /bin/sh
|
||||
|
||||
pdflatex -no-shell-escape step-by-step.tex
|
||||
pdflatex -no-shell-escape step-by-step.tex
|
||||
pdflatex -no-shell-escape pas-a-pas.tex
|
||||
pdflatex -no-shell-escape pas-a-pas.tex
|
||||
@@ -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/.
|
||||
%% Do not edit unless you really know what you are doing.
|
||||
\documentclass[12pt,french]{article}
|
||||
@@ -8,6 +9,7 @@
|
||||
\usepackage{textcomp}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{hyperref}
|
||||
\usepackage[frenchb]{babel}
|
||||
|
||||
\makeatletter
|
||||
|
||||
@@ -132,17 +134,17 @@ Pendant que vous travaillez sur votre
|
||||
|
||||
\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}.
|
||||
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.
|
||||
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.
|
||||
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}.
|
||||
Vous avez créé votre premier bief, avec un n½ud amont et un n½ud aval.
|
||||
Dans la partie inférieure de la fenêtre \textit{Réseau}, vous pouvez renommer les n½uds et les biefs.
|
||||
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\oe{}uds et les biefs.
|
||||
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 :
|
||||
|
||||
@@ -154,7 +156,7 @@ Fermez la fen
|
||||
|
||||
\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}.
|
||||
Sélectionnez le fichier \texttt{Data/Bief\_1.st}.
|
||||
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.
|
||||
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électionnez la cellule \textit{N½ud} et attribuez cette condition au n½ud amont.
|
||||
Les noms des n½uds sont rappelés dans le panneau de droite, avec une vue du réseau.
|
||||
Sélectionnez la cellule \textit{n\oe{}ud} et attribuez cette condition au n\oe{}ud amont.
|
||||
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"}.
|
||||
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}.
|
||||
@@ -250,7 +252,7 @@ Vous pouvez maintenant voir la courbe de d
|
||||
\par\end{center}
|
||||
|
||||
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"}).
|
||||
Ajoutez deux lignes et rentrez les valeurs suivantes :
|
||||
\begin{center}
|
||||
@@ -271,7 +273,7 @@ Vous pouvez fermer les fen
|
||||
% 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.
|
||||
% 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.
|
||||
% 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}.
|
||||
@@ -400,19 +402,19 @@ Si vous r
|
||||
|
||||
\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]}.
|
||||
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}.
|
||||
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.
|
||||
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}$.
|
||||
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.
|
||||
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.
|
||||
Fermer la fenêtre \textit{Paramètres du solveur}.
|
||||
|
||||
@@ -426,12 +428,13 @@ Cette fen
|
||||
|
||||
\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.
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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{}
|
||||
\end{document}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -177,8 +177,7 @@ class Friction(SQLSubModel):
|
||||
|
||||
def has_coefficient(self):
|
||||
return (
|
||||
self._begin_strickler is not None and
|
||||
self._end_strickler is not None
|
||||
self._begin_strickler is not None
|
||||
)
|
||||
|
||||
def is_full_defined(self):
|
||||
@@ -237,7 +236,8 @@ class Friction(SQLSubModel):
|
||||
|
||||
@property
|
||||
def end_strickler(self):
|
||||
return self._end_strickler
|
||||
# return self._end_strickler
|
||||
return self._begin_strickler
|
||||
|
||||
@end_strickler.setter
|
||||
def end_strickler(self, strickler):
|
||||
@@ -247,13 +247,17 @@ class Friction(SQLSubModel):
|
||||
def get_friction(self, rk):
|
||||
if not self.contains_rk(rk):
|
||||
return None
|
||||
minor = interp(rk,
|
||||
[self.begin_rk, self.end_rk],
|
||||
[self.begin_strickler.minor,
|
||||
self.end_strickler.minor])
|
||||
medium = interp(rk,
|
||||
[self.begin_rk, self.end_rk],
|
||||
[self.begin_strickler.medium,
|
||||
self.end_strickler.medium])
|
||||
|
||||
minor = self.begin_strickler.minor
|
||||
medium = self.begin_strickler.medium
|
||||
|
||||
# minor = interp(rk,
|
||||
# [self.begin_rk, self.end_rk],
|
||||
# [self.begin_strickler.minor,
|
||||
# self.end_strickler.minor])
|
||||
# medium = interp(rk,
|
||||
# [self.begin_rk, self.end_rk],
|
||||
# [self.begin_strickler.medium,
|
||||
# self.end_strickler.medium])
|
||||
|
||||
return minor, medium
|
||||
@@ -368,6 +368,9 @@ class Reach(SQLSubModel):
|
||||
|
||||
def inter_profiles_rk(self):
|
||||
profiles = sorted(self.profiles, key=lambda p: p.rk)
|
||||
if len(profiles) == 0:
|
||||
return []
|
||||
|
||||
first = profiles[0]
|
||||
last = profiles[-1]
|
||||
|
||||
@@ -750,6 +753,9 @@ class Reach(SQLSubModel):
|
||||
cnt += 1
|
||||
|
||||
def get_incline(self):
|
||||
if len(self.profiles) == 0:
|
||||
return 0.0
|
||||
|
||||
first = self.profile(0)
|
||||
last = self.profile(len(self) - 1)
|
||||
|
||||
@@ -767,6 +773,9 @@ class Reach(SQLSubModel):
|
||||
|
||||
def get_incline_mean(self):
|
||||
profiles = self.profiles
|
||||
if len(profiles) == 0:
|
||||
return 0.0
|
||||
|
||||
previous = profiles[0]
|
||||
|
||||
incline_acc = 0
|
||||
@@ -790,6 +799,9 @@ class Reach(SQLSubModel):
|
||||
|
||||
def get_incline_median(self):
|
||||
profiles = self.profiles
|
||||
if len(profiles) == 0:
|
||||
return 0.0
|
||||
|
||||
previous = profiles[0]
|
||||
|
||||
incline_acc = []
|
||||
@@ -814,6 +826,9 @@ class Reach(SQLSubModel):
|
||||
|
||||
def get_incline_median_mean(self):
|
||||
profiles = self.profiles
|
||||
if len(profiles) == 0:
|
||||
return 0.0
|
||||
|
||||
previous = profiles[0]
|
||||
|
||||
incline_acc = []
|
||||
@@ -825,6 +840,9 @@ class Reach(SQLSubModel):
|
||||
z_last = profile.z_min()
|
||||
rk_last = profile.rk
|
||||
|
||||
if (rk_last - rk_first) == 0:
|
||||
continue
|
||||
|
||||
incline_acc += [
|
||||
(z_last - z_first)
|
||||
/
|
||||
|
||||
@@ -360,26 +360,11 @@ class InitialConditions(SQLSubModel):
|
||||
def get_discharge(self):
|
||||
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,
|
||||
compute_discharge: bool):
|
||||
|
||||
profiles = self._reach.reach.profiles.copy()
|
||||
self._sort_by_z_and_rk(profiles)
|
||||
profiles.reverse()
|
||||
|
||||
previous_elevation = -99999.99
|
||||
|
||||
@@ -433,12 +418,12 @@ class InitialConditions(SQLSubModel):
|
||||
previous_elevation = elevation
|
||||
self._data.append(new)
|
||||
|
||||
self._generate_resort_data(profiles)
|
||||
self._data.reverse()
|
||||
|
||||
def generate_discharge(self, discharge: float, compute_height: bool):
|
||||
|
||||
profiles = self._reach.reach.profiles.copy()
|
||||
self._sort_by_z_and_rk(profiles)
|
||||
profiles.reverse()
|
||||
|
||||
previous_elevation = -99999.99
|
||||
|
||||
@@ -491,7 +476,7 @@ class InitialConditions(SQLSubModel):
|
||||
previous_elevation = elevation
|
||||
self._data.append(new)
|
||||
|
||||
self._generate_resort_data(profiles)
|
||||
self._data.reverse()
|
||||
|
||||
def generate_height(self,
|
||||
elevation1: float,
|
||||
@@ -525,13 +510,3 @@ class InitialConditions(SQLSubModel):
|
||||
new["discharge"] = d
|
||||
new["elevation"] = elevation
|
||||
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)
|
||||
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):
|
||||
"""Return input command line parameter(s)
|
||||
|
||||
+39
-18
@@ -69,7 +69,7 @@ class Mage(CommandLineSolver):
|
||||
lst += [
|
||||
("mage_min_timestep", "1.0"),
|
||||
("mage_timestep_tra", "3600"),
|
||||
("mage_timestep_bin", "0"),
|
||||
("mage_timestep_bin", "3600"),
|
||||
# ("mage_timestep_melissa", "0"),
|
||||
("mage_implicitation", "0.70"),
|
||||
("mage_continuity_discretization", "S"),
|
||||
@@ -79,11 +79,11 @@ class Mage(CommandLineSolver):
|
||||
("mage_smooth_coef", "0"),
|
||||
("mage_cfl_max", "-1."),
|
||||
("mage_min_height", "0.1"),
|
||||
("mage_max_niter", "10"),
|
||||
("mage_max_niter", "99"),
|
||||
("mage_timestep_reduction_factor", "2"),
|
||||
("mage_precision_reduction_factor_Z", "1"),
|
||||
("mage_precision_reduction_factor_Q", "1"),
|
||||
("mage_niter_max_precision", "99"),
|
||||
("mage_niter_max_precision", "10"),
|
||||
("mage_niter_before_switch", "99"),
|
||||
("mage_max_froude", "1.5"),
|
||||
("mage_diffluence_node_height_balance", "-1"),
|
||||
@@ -599,29 +599,50 @@ class Mage(CommandLineSolver):
|
||||
if qlog is not None:
|
||||
qlog.put("Export VAR file")
|
||||
|
||||
with mage_file_open(os.path.join(repertory, f"{name}.VAR"), "w+") as f:
|
||||
files.append(f"{name}.VAR")
|
||||
nb_cv = 0
|
||||
for hs in hydraulic_structures:
|
||||
if hs.input_reach is None:
|
||||
continue
|
||||
|
||||
for hs in hydraulic_structures:
|
||||
if hs.input_reach is None:
|
||||
continue
|
||||
if not hs.input_reach.is_enable():
|
||||
continue
|
||||
|
||||
if not hs.input_reach.is_enable():
|
||||
continue
|
||||
if not hs.enabled:
|
||||
continue
|
||||
|
||||
for bhs in hs.basic_structures:
|
||||
for bhs in hs.basic_structures:
|
||||
if bhs.enabled:
|
||||
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
|
||||
|
||||
name = bhs.name
|
||||
if name == "":
|
||||
name = f"HS_{bhs.id:>3}".replace(" ", "0")
|
||||
if not hs.input_reach.is_enable():
|
||||
continue
|
||||
|
||||
f.write(
|
||||
f"${name} clapet"
|
||||
)
|
||||
if not hs.enabled:
|
||||
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
|
||||
|
||||
def _export_DEV(self, study, repertory, qlog, name="0"):
|
||||
|
||||
@@ -347,6 +347,14 @@ class EditBoundaryConditionWindow(PamhyrWindow):
|
||||
if node is None:
|
||||
return
|
||||
reach = self._data.reach(self._study.river)[0]
|
||||
if len(reach.profiles) == 0:
|
||||
self.message_box(
|
||||
window_title=self._trad["Warning"],
|
||||
text=self._trad["title_need_geometry"],
|
||||
informative_text=self._trad["msg_need_geometry"]
|
||||
)
|
||||
return
|
||||
|
||||
profile = reach.profiles[-1]
|
||||
dlg = GenerateDialog(self.slope_value,
|
||||
reach,
|
||||
@@ -379,6 +387,14 @@ class EditBoundaryConditionWindow(PamhyrWindow):
|
||||
if node is None:
|
||||
return
|
||||
reach = self._data.reach(self._study.river)[0]
|
||||
if len(reach.profiles) == 0:
|
||||
self.message_box(
|
||||
window_title=self._trad["Warning"],
|
||||
text=self._trad["title_need_geometry"],
|
||||
informative_text=self._trad["msg_need_geometry"]
|
||||
)
|
||||
return
|
||||
|
||||
profile = reach.profiles[-1]
|
||||
z_min = profile.z_min()
|
||||
z_max = profile.z_max()
|
||||
|
||||
@@ -44,3 +44,14 @@ class BCETranslate(BCTranslate):
|
||||
"z": self._dict["unit_elevation"],
|
||||
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
|
||||
}
|
||||
|
||||
self._dict["title_need_geometry"] = _translate(
|
||||
"BoundaryCondition", "No geometry"
|
||||
)
|
||||
self._dict["msg_need_geometry"] = _translate(
|
||||
"BoundaryCondition",
|
||||
"No geometry found for this reach.\n"
|
||||
"This feature requires a reach with a geometry."
|
||||
)
|
||||
self._dict["Warning"] = _translate("BoundaryCondition",
|
||||
"Warning")
|
||||
@@ -52,7 +52,7 @@ class PlotRKZ(PamhyrPlot):
|
||||
self.line_rk_zmin_zmax_highlight = None
|
||||
|
||||
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.plot_selected = None
|
||||
|
||||
@@ -155,7 +155,8 @@ class BasicHydraulicStructuresWindow(PamhyrWindow):
|
||||
profiles = reach.reach.get_profiles_from_rk(float(profile_rk))
|
||||
else:
|
||||
profiles = None
|
||||
if profiles is not None:
|
||||
|
||||
if profiles is not None and len(profiles) != 0:
|
||||
profile = profiles[0]
|
||||
else:
|
||||
profile = None
|
||||
|
||||
@@ -77,29 +77,29 @@ class PlotDRK(PamhyrPlot):
|
||||
rk = self.data.get_rk()
|
||||
elevation = self.data.get_elevation()
|
||||
|
||||
sorted_rk, sorted_elevation = zip(
|
||||
*sorted(zip(rk, elevation))
|
||||
)
|
||||
|
||||
self.line_rk_elevation = self.canvas.axes.plot(
|
||||
rk, elevation,
|
||||
sorted_rk, sorted_elevation,
|
||||
color=self.color_plot_river_water,
|
||||
**self.plot_default_kargs
|
||||
)
|
||||
|
||||
z_min = self.data.reach.reach.get_z_min()
|
||||
geometry_rk = self.data.reach.reach.get_rk()
|
||||
|
||||
filtred_elevation = list(
|
||||
map(
|
||||
lambda x: elevation[x[0]],
|
||||
filter(
|
||||
lambda x: x[1] in geometry_rk,
|
||||
enumerate(rk)
|
||||
)
|
||||
)
|
||||
sorted_geometry_rk, sorted_z_min = zip(
|
||||
*sorted(zip(geometry_rk, z_min), reverse=True)
|
||||
)
|
||||
|
||||
self.collection = self.canvas.axes.fill_between(
|
||||
geometry_rk, z_min, filtred_elevation,
|
||||
poly_x = sorted_rk + sorted_geometry_rk
|
||||
poly_y = sorted_elevation + sorted_z_min
|
||||
|
||||
self.collection = self.canvas.axes.fill(
|
||||
poly_x, poly_y,
|
||||
color=self.color_plot_river_water_zone,
|
||||
alpha=0.7, interpolate=True
|
||||
alpha=0.7,
|
||||
)
|
||||
|
||||
@timer
|
||||
|
||||
@@ -104,15 +104,15 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||
row = index.row()
|
||||
column = index.column()
|
||||
|
||||
if self._headers[column] is "speed":
|
||||
if self._headers[column] == "velocity":
|
||||
z = self._lst.get(row)["elevation"]
|
||||
q = self._lst.get(row)["discharge"]
|
||||
profile = self._reach.reach.get_profiles_from_rk(
|
||||
self._lst.get(row)["rk"]
|
||||
)
|
||||
if len(profile) >= 1:
|
||||
speed = profile[0].speed(q, z)
|
||||
return f"{speed:.4f}"
|
||||
velocity = profile[0].speed(q, z)
|
||||
return f"{velocity:.4f}"
|
||||
|
||||
return ""
|
||||
elif self._headers[column] not in ["name", "comment"]:
|
||||
|
||||
@@ -365,40 +365,43 @@ class InitialConditionsWindow(PamhyrWindow):
|
||||
self._update()
|
||||
|
||||
def generate_growing_constant_depth(self):
|
||||
dlg = DepthDialog(self.depth_value,
|
||||
self.depth_option,
|
||||
trad=self._trad,
|
||||
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,
|
||||
if self._reach.reach.number_profiles > 0:
|
||||
dlg = DepthDialog(self.depth_value,
|
||||
self.depth_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()
|
||||
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):
|
||||
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):
|
||||
dlg = HeightDialog(self.height_values,
|
||||
self.height_option,
|
||||
trad=self._trad,
|
||||
parent=self)
|
||||
if dlg.exec():
|
||||
self.height_values = dlg.values
|
||||
self.height_option = dlg.option
|
||||
self._table.generate("height",
|
||||
self.height_values,
|
||||
self.height_option)
|
||||
self._update()
|
||||
if self._reach.reach.number_profiles > 0:
|
||||
dlg = HeightDialog(self.height_values,
|
||||
self.height_option,
|
||||
trad=self._trad,
|
||||
parent=self)
|
||||
if dlg.exec():
|
||||
self.height_values = dlg.values
|
||||
self.height_option = dlg.option
|
||||
self._table.generate("height",
|
||||
self.height_values,
|
||||
self.height_option)
|
||||
self._update()
|
||||
@@ -39,7 +39,7 @@ class ICTranslate(MainTranslate):
|
||||
"rk": self._dict["unit_rk"],
|
||||
"discharge": self._dict["unit_discharge"],
|
||||
"elevation": self._dict["unit_elevation"],
|
||||
"height": self._dict["unit_height"],
|
||||
"speed": self._dict["unit_speed"],
|
||||
"height": self._dict["unit_depth"],
|
||||
"velocity": self._dict["unit_velocity"],
|
||||
# "comment": _translate("InitialCondition", "Comment"),
|
||||
}
|
||||
@@ -749,9 +749,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||
|
||||
def msg_select_reach(self):
|
||||
self.message_box(
|
||||
self._trad["mb_select_reach_title"],
|
||||
self._trad["mb_select_reach_msg"]
|
||||
window_title=self._trad["Warning"],
|
||||
text=self._trad["mb_select_reach_title"],
|
||||
informative_text=self._trad["mb_select_reach_msg"]
|
||||
)
|
||||
self.open_network()
|
||||
|
||||
def dialog_reopen_study(self):
|
||||
dlg = QMessageBox(self)
|
||||
|
||||
@@ -20,8 +20,13 @@ import logging
|
||||
|
||||
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 PyQt5.QtWidgets import QVBoxLayout
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@@ -38,7 +43,9 @@ class WidgetInfo(PamhyrWidget):
|
||||
parent=parent
|
||||
)
|
||||
|
||||
self.parent = parent
|
||||
self.set_initial_values()
|
||||
self.setup_graph()
|
||||
|
||||
@property
|
||||
def study(self):
|
||||
@@ -64,6 +71,25 @@ class WidgetInfo(PamhyrWidget):
|
||||
self.set_label_text("label_lc", "-")
|
||||
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):
|
||||
if self._study is None:
|
||||
self.set_initial_values()
|
||||
@@ -75,6 +101,15 @@ class WidgetInfo(PamhyrWidget):
|
||||
self.set_network_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):
|
||||
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._table_headers = self._trad.get_dict("table_headers")
|
||||
|
||||
self.label_x = self._table_headers["z"]
|
||||
self.label_y = self._table_headers["area"]
|
||||
self.label_x = self._table_headers["area"]
|
||||
self.label_y = self._table_headers["z"]
|
||||
|
||||
self._isometric_axis = False
|
||||
|
||||
@@ -71,8 +71,8 @@ class Plot(PamhyrPlot):
|
||||
self._init = True
|
||||
|
||||
def draw_data(self):
|
||||
x = list(map(lambda v: v[0], self.data.data))
|
||||
y = list(map(lambda v: v[1], self.data.data))
|
||||
x = 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(
|
||||
x, y,
|
||||
color=self.color_plot,
|
||||
@@ -89,7 +89,7 @@ class Plot(PamhyrPlot):
|
||||
self.update_idle()
|
||||
|
||||
def update_data(self):
|
||||
x = list(map(lambda v: v[0], self.data.data))
|
||||
y = list(map(lambda v: v[1], self.data.data))
|
||||
x = 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)
|
||||
@@ -42,6 +42,7 @@ class CustomPlotValuesSelectionDialog(PamhyrDialog):
|
||||
self._available_values_y = self._trad.get_dict("values_y")
|
||||
|
||||
self.setup_radio_buttons()
|
||||
self.setup_envelop_box()
|
||||
self.setup_check_boxs()
|
||||
|
||||
self.value = None
|
||||
@@ -61,6 +62,24 @@ class CustomPlotValuesSelectionDialog(PamhyrDialog):
|
||||
self._radio[0][1].setChecked(True)
|
||||
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):
|
||||
self._check = []
|
||||
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()
|
||||
@@ -21,6 +21,7 @@ import logging
|
||||
from functools import reduce
|
||||
from datetime import datetime
|
||||
from numpy import sqrt
|
||||
from numpy import asarray
|
||||
|
||||
from tools import timer
|
||||
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||
@@ -30,11 +31,16 @@ from View.Results.CustomPlot.Translate import CustomPlotTranslate
|
||||
logger = logging.getLogger()
|
||||
|
||||
unit = {
|
||||
"elevation": "0-meter",
|
||||
"bed_elevation": "0-meter",
|
||||
"bed_elevation_envelop": "0-meter",
|
||||
"water_elevation": "0-meter",
|
||||
"water_elevation_envelop": "0-meter",
|
||||
"discharge": "1-m3s",
|
||||
"discharge_envelop": "1-m3s",
|
||||
"velocity": "2-ms",
|
||||
"max_depth": "3-meter",
|
||||
"velocity_envelop": "2-ms",
|
||||
"depth": "3-meter",
|
||||
"depth_envelop": "3-meter",
|
||||
"mean_depth": "3-meter",
|
||||
"froude": "4-dimensionless",
|
||||
"wet_area": "5-m2",
|
||||
@@ -42,7 +48,7 @@ unit = {
|
||||
|
||||
|
||||
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,
|
||||
toolbar=None, parent=None):
|
||||
super(CustomPlot, self).__init__(
|
||||
@@ -55,6 +61,7 @@ class CustomPlot(PamhyrPlot):
|
||||
|
||||
self._x = x
|
||||
self._y = y
|
||||
self._envelop = envelop
|
||||
self._reach = reach
|
||||
self._profile = profile
|
||||
self._timestamp = timestamp
|
||||
@@ -77,11 +84,97 @@ class CustomPlot(PamhyrPlot):
|
||||
|
||||
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):
|
||||
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"),
|
||||
@@ -105,15 +198,45 @@ class CustomPlot(PamhyrPlot):
|
||||
self._axes[ax].spines['right'].set_position(('outward', shift))
|
||||
shift += 60
|
||||
|
||||
lines = {}
|
||||
if "elevation" in self._y:
|
||||
self.lines = {}
|
||||
if "bed_elevation" in self._y:
|
||||
|
||||
ax = self._axes[unit["elevation"]]
|
||||
ax = self._axes[unit["bed_elevation"]]
|
||||
line = ax.plot(
|
||||
rk, z_min,
|
||||
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:
|
||||
|
||||
@@ -122,14 +245,46 @@ class CustomPlot(PamhyrPlot):
|
||||
rk, z, lw=1.,
|
||||
color='blue',
|
||||
)
|
||||
lines["water_elevation"] = line
|
||||
self.lines["water_elevation"] = line
|
||||
|
||||
if "elevation" in self._y:
|
||||
ax.fill_between(
|
||||
if "bed_elevation" in self._y:
|
||||
self.fill = ax.fill_between(
|
||||
rk, z_min, z,
|
||||
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:
|
||||
|
||||
ax = self._axes[unit["discharge"]]
|
||||
@@ -137,7 +292,37 @@ class CustomPlot(PamhyrPlot):
|
||||
rk, q, lw=1.,
|
||||
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:
|
||||
|
||||
@@ -155,11 +340,40 @@ class CustomPlot(PamhyrPlot):
|
||||
rk, v, lw=1.,
|
||||
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(
|
||||
map(
|
||||
lambda p: p.geometry.max_water_depth(
|
||||
@@ -171,7 +385,37 @@ class CustomPlot(PamhyrPlot):
|
||||
rk, d,
|
||||
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:
|
||||
|
||||
@@ -188,7 +432,7 @@ class CustomPlot(PamhyrPlot):
|
||||
rk, d,
|
||||
color='orange', lw=1.,
|
||||
)
|
||||
lines["mean_depth"] = line
|
||||
self.lines["mean_depth"] = line
|
||||
|
||||
if "froude" in self._y:
|
||||
|
||||
@@ -212,7 +456,7 @@ class CustomPlot(PamhyrPlot):
|
||||
line = ax.plot(
|
||||
rk, fr, color='black', linestyle='--', lw=1.,
|
||||
)
|
||||
lines["froude"] = line
|
||||
self.lines["froude"] = line
|
||||
|
||||
if "wet_area" in self._y:
|
||||
|
||||
@@ -229,17 +473,115 @@ class CustomPlot(PamhyrPlot):
|
||||
rk, d,
|
||||
color='blue', linestyle='--', lw=1.,
|
||||
)
|
||||
lines["wet_area"] = line
|
||||
self.lines["wet_area"] = line
|
||||
|
||||
# Legend
|
||||
lns = reduce(
|
||||
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")
|
||||
|
||||
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"):
|
||||
# Custom time display
|
||||
nb = len(ts)
|
||||
@@ -301,24 +643,27 @@ class CustomPlot(PamhyrPlot):
|
||||
q = profile.get_key("Q")
|
||||
z = profile.get_key("Z")
|
||||
z_min = profile.geometry.z_min()
|
||||
ts_z_min = list(
|
||||
map(
|
||||
lambda ts: z_min,
|
||||
ts
|
||||
if reach.has_sediment():
|
||||
ts_z_min = self.get_ts_zmin(self._profile)
|
||||
else:
|
||||
ts_z_min = list(
|
||||
map(
|
||||
lambda ts: z_min,
|
||||
ts
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
lines = {}
|
||||
if "elevation" in self._y:
|
||||
self.lines = {}
|
||||
if "bed_elevation" in self._y:
|
||||
# Z min is constant in time
|
||||
|
||||
ax = self._axes[unit["elevation"]]
|
||||
ax = self._axes[unit["bed_elevation"]]
|
||||
|
||||
line = ax.plot(
|
||||
ts, ts_z_min,
|
||||
color='grey', lw=1.
|
||||
)
|
||||
lines["elevation"] = line
|
||||
self.lines["bed_elevation"] = line
|
||||
|
||||
if "water_elevation" in self._y:
|
||||
|
||||
@@ -327,11 +672,11 @@ class CustomPlot(PamhyrPlot):
|
||||
ts, z, lw=1.,
|
||||
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,
|
||||
color='blue', alpha=0.5, interpolate=True
|
||||
)
|
||||
@@ -343,7 +688,7 @@ class CustomPlot(PamhyrPlot):
|
||||
ts, q, lw=1.,
|
||||
color='r',
|
||||
)
|
||||
lines["discharge"] = line
|
||||
self.lines["discharge"] = line
|
||||
|
||||
if "velocity" in self._y:
|
||||
|
||||
@@ -359,11 +704,11 @@ class CustomPlot(PamhyrPlot):
|
||||
ts, v, lw=1.,
|
||||
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(
|
||||
map(lambda z: profile.geometry.max_water_depth(z), z)
|
||||
)
|
||||
@@ -372,7 +717,7 @@ class CustomPlot(PamhyrPlot):
|
||||
ts, d,
|
||||
color='brown', lw=1.,
|
||||
)
|
||||
lines["max_depth"] = line
|
||||
self.lines["depth"] = line
|
||||
|
||||
if "mean_depth" in self._y:
|
||||
|
||||
@@ -385,7 +730,7 @@ class CustomPlot(PamhyrPlot):
|
||||
ts, d,
|
||||
color='orange', lw=1.,
|
||||
)
|
||||
lines["mean_depth"] = line
|
||||
self.lines["mean_depth"] = line
|
||||
|
||||
if "froude" in self._y:
|
||||
|
||||
@@ -402,7 +747,7 @@ class CustomPlot(PamhyrPlot):
|
||||
line = ax.plot(
|
||||
ts, d, color='black', linestyle='--', lw=1.,
|
||||
)
|
||||
lines["froude"] = line
|
||||
self.lines["froude"] = line
|
||||
|
||||
if "wet_area" in self._y:
|
||||
|
||||
@@ -414,21 +759,108 @@ class CustomPlot(PamhyrPlot):
|
||||
line = ax.plot(
|
||||
ts, d, color='blue', linestyle='--', lw=1.,
|
||||
)
|
||||
lines["wet_area"] = line
|
||||
self.lines["wet_area"] = line
|
||||
|
||||
self._customize_x_axes_time(ts)
|
||||
|
||||
# Legend
|
||||
lns = reduce(
|
||||
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")
|
||||
|
||||
@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):
|
||||
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.grid(color='grey', linestyle='--', linewidth=0.5)
|
||||
|
||||
@@ -478,16 +910,16 @@ class CustomPlot(PamhyrPlot):
|
||||
lw=1.,
|
||||
)
|
||||
|
||||
self.canvas.figure.canvas.draw_idle()
|
||||
if self.toolbar is not None:
|
||||
self.toolbar.update()
|
||||
self.canvas.draw_idle()
|
||||
|
||||
@timer
|
||||
def update(self):
|
||||
if not self._init:
|
||||
self.draw()
|
||||
self.draw_current()
|
||||
return
|
||||
self.draw_update()
|
||||
self.draw_current()
|
||||
# self.draw_static()
|
||||
return
|
||||
|
||||
def set_reach(self, reach_id):
|
||||
self._reach = reach_id
|
||||
@@ -519,4 +951,5 @@ class CustomPlot(PamhyrPlot):
|
||||
elif self._x == "time":
|
||||
x = self._timestamp
|
||||
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['rk'] = self._dict["unit_rk"]
|
||||
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['elevation'] = _translate(
|
||||
"CustomPlot", "Bed elevation (m)"
|
||||
)
|
||||
self._dict['velocity'] = self._dict["unit_speed"]
|
||||
self._dict['discharge_envelop'] = self._dict["unit_discharge_envelop"]
|
||||
self._dict['bed_elevation'] = self._dict["unit_bed_elevation"]
|
||||
self._dict['bed_elevation_envelop'] = self._dict[
|
||||
"unit_bed_elevation_envelop"
|
||||
]
|
||||
self._dict['velocity'] = self._dict["unit_velocity"]
|
||||
self._dict['width'] = self._dict["unit_width"]
|
||||
self._dict['max_depth'] = self._dict["unit_max_height"]
|
||||
self._dict['mean_depth'] = self._dict["unit_mean_height"]
|
||||
self._dict['velocity_envelop'] = self._dict["unit_velocity_envelop"]
|
||||
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_perimeter'] = self._dict["unit_wet_perimeter"]
|
||||
self._dict['hydraulic_radius'] = self._dict["unit_hydraulic_radius"]
|
||||
@@ -55,7 +62,7 @@ class CustomPlotTranslate(ResultsTranslate):
|
||||
"CustomPlot", "Elevation (m)"
|
||||
)
|
||||
self._dict['1-m3s'] = self._dict["unit_discharge"]
|
||||
self._dict['2-ms'] = self._dict["unit_speed"]
|
||||
self._dict['3-meter'] = self._dict["unit_height"]
|
||||
self._dict['2-ms'] = self._dict["unit_velocity"]
|
||||
self._dict['3-meter'] = self._dict["unit_depth"]
|
||||
self._dict['4-dimensionless'] = self._dict["unit_froude"]
|
||||
self._dict['5-m2'] = self._dict["wet_area"]
|
||||
@@ -146,8 +146,9 @@ class PlotXY(PamhyrPlot):
|
||||
return
|
||||
|
||||
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_max(reach)
|
||||
self.draw_guide_lines(reach)
|
||||
@@ -156,12 +157,12 @@ class PlotXY(PamhyrPlot):
|
||||
self.idle()
|
||||
self._init = True
|
||||
|
||||
def draw_profiles(self, reach):
|
||||
def draw_profiles(self, reach, reaches):
|
||||
if reach.geometry.number_profiles == 0:
|
||||
self._init = False
|
||||
return
|
||||
|
||||
self.line_xy = []
|
||||
# TODO uncomment to draw all the reaches
|
||||
# self.draw_other_profiles(reaches)
|
||||
for xy in zip(reach.geometry.get_x(),
|
||||
reach.geometry.get_y()):
|
||||
self.line_xy.append(np.column_stack(xy))
|
||||
@@ -176,6 +177,19 @@ class PlotXY(PamhyrPlot):
|
||||
)
|
||||
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):
|
||||
x_complete = reach.geometry.get_guidelines_x()
|
||||
y_complete = reach.geometry.get_guidelines_y()
|
||||
|
||||
@@ -97,7 +97,7 @@ class TableModel(PamhyrTableModel):
|
||||
z = self._lst[row].get_ts_key(self._timestamp, "Z")
|
||||
v = self._lst[row].geometry.wet_width(z)
|
||||
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")
|
||||
v = self._lst[row].geometry.max_water_depth(z)
|
||||
return f"{v:.4f}"
|
||||
|
||||
+112
-40
@@ -490,11 +490,13 @@ class ResultsWindow(PamhyrWindow):
|
||||
def _add_custom_plot(self):
|
||||
dlg = CustomPlotValuesSelectionDialog(parent=self)
|
||||
if dlg.exec():
|
||||
x, y = dlg.value
|
||||
self.create_new_tab_custom_plot(x, y)
|
||||
x, y, envelop = dlg.value
|
||||
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)}"
|
||||
if envelop and x == "rk":
|
||||
name += "_envelop"
|
||||
wname = f"tab_custom_{x}_{y}"
|
||||
|
||||
tab_widget = self.find(QTabWidget, f"tabWidget")
|
||||
@@ -518,7 +520,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
)
|
||||
|
||||
plot = CustomPlot(
|
||||
x, y,
|
||||
x, y, envelop,
|
||||
self._get_current_reach(),
|
||||
self._get_current_profile(),
|
||||
self._get_current_timestamp(),
|
||||
@@ -589,7 +591,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
|
||||
dlg = CustomPlotValuesSelectionDialog(parent=self)
|
||||
if dlg.exec():
|
||||
x, y = dlg.value
|
||||
x, y, envelop = dlg.value
|
||||
else:
|
||||
return
|
||||
|
||||
@@ -599,32 +601,39 @@ class ResultsWindow(PamhyrWindow):
|
||||
)
|
||||
self.file_dialog(
|
||||
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",
|
||||
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"))
|
||||
reach = self._results.river.reachs[self._get_current_reach()]
|
||||
first_line = [f"Study: {self._results.study.name}",
|
||||
f"Reach: {reach.name}"]
|
||||
if x == "rk":
|
||||
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":
|
||||
profile = self._get_current_profile()
|
||||
val_dict = self._export_time(profile, y, filename)
|
||||
profile_id = self._get_current_profile()
|
||||
profile = reach.profile(profile_id)
|
||||
pname = profile.name if profile.name != "" else profile.rk
|
||||
first_line.append(f"Profile: {pname}")
|
||||
val_dict = self._export_time(profile_id, y, filename)
|
||||
|
||||
with open(filename, 'w', newline='') as csvfile:
|
||||
writer = csv.writer(csvfile, delimiter=',',
|
||||
quotechar='|', quoting=csv.QUOTE_MINIMAL)
|
||||
dict_x = self._trad.get_dict("values_x")
|
||||
dict_y = self._trad.get_dict("values_y")
|
||||
header = [dict_x[x]]
|
||||
for text in y:
|
||||
header.append(dict_y[text])
|
||||
header = []
|
||||
writer.writerow(first_line)
|
||||
for text in val_dict.keys():
|
||||
header.append(text)
|
||||
writer.writerow(header)
|
||||
for row in range(len(val_dict[x])):
|
||||
line = [val_dict[x][row]]
|
||||
for var in y:
|
||||
for row in range(len(val_dict[dict_x[x]])):
|
||||
line = []
|
||||
for var in val_dict.keys():
|
||||
line.append(val_dict[var][row])
|
||||
writer.writerow(line)
|
||||
|
||||
@@ -666,28 +675,60 @@ class ResultsWindow(PamhyrWindow):
|
||||
self._additional_plot.pop(tab_widget.tabText(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()]
|
||||
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["rk"] = reach.geometry.get_rk()
|
||||
if "elevation" in y:
|
||||
my_dict["elevation"] = reach.geometry.get_z_min()
|
||||
my_dict[dict_x["rk"]] = reach.geometry.get_rk()
|
||||
if "bed_elevation" in y:
|
||||
my_dict[dict_y["bed_elevation"]] = reach.geometry.get_z_min()
|
||||
#if envelop and reach.has_sediment():
|
||||
if "discharge" in y:
|
||||
my_dict["discharge"] = list(
|
||||
my_dict[dict_y["discharge"]] = list(
|
||||
map(
|
||||
lambda p: p.get_ts_key(timestamp, "Q"),
|
||||
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:
|
||||
my_dict["water_elevation"] = list(
|
||||
my_dict[dict_y["water_elevation"]] = list(
|
||||
map(
|
||||
lambda p: p.get_ts_key(timestamp, "Z"),
|
||||
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:
|
||||
my_dict["velocity"] = list(
|
||||
my_dict[dict_y["velocity"]] = list(
|
||||
map(
|
||||
lambda p: p.geometry.speed(
|
||||
p.get_ts_key(timestamp, "Q"),
|
||||
@@ -695,16 +736,44 @@ class ResultsWindow(PamhyrWindow):
|
||||
reach.profiles
|
||||
)
|
||||
)
|
||||
if "max_depth" in y:
|
||||
my_dict["max_depth"] = list(
|
||||
if envelop:
|
||||
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(
|
||||
lambda p: p.geometry.max_water_depth(
|
||||
p.get_ts_key(timestamp, "Z")),
|
||||
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:
|
||||
my_dict["mean_depth"] = list(
|
||||
my_dict[dict_y["mean_depth"]] = list(
|
||||
map(
|
||||
lambda p: p.geometry.mean_water_depth(
|
||||
p.get_ts_key(timestamp, "Z")),
|
||||
@@ -712,7 +781,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
)
|
||||
)
|
||||
if "froude" in y:
|
||||
my_dict["froude"] = list(
|
||||
my_dict[dict_y["froude"]] = list(
|
||||
map(
|
||||
lambda p:
|
||||
p.geometry.speed(
|
||||
@@ -728,7 +797,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
)
|
||||
)
|
||||
if "wet_area" in y:
|
||||
my_dict["wet_area"] = list(
|
||||
my_dict[dict_y["wet_area"]] = list(
|
||||
map(
|
||||
lambda p: p.geometry.wet_area(
|
||||
p.get_ts_key(timestamp, "Z")),
|
||||
@@ -743,33 +812,36 @@ class ResultsWindow(PamhyrWindow):
|
||||
profile = reach.profile(profile)
|
||||
ts = list(self._results.get("timestamps"))
|
||||
ts.sort()
|
||||
dict_x = self._trad.get_dict("values_x")
|
||||
dict_y = self._trad.get_dict("values_y")
|
||||
my_dict = {}
|
||||
my_dict["time"] = ts
|
||||
my_dict[dict_x["time"]] = ts
|
||||
z = profile.get_key("Z")
|
||||
q = profile.get_key("Q")
|
||||
if "elevation" in y:
|
||||
my_dict["elevation"] = [profile.geometry.z_min()] * len(ts)
|
||||
if "bed_elevation" in y:
|
||||
my_dict[dict_y["bed_elevation"]] = [
|
||||
profile.geometry.z_min()] * len(ts)
|
||||
if "discharge" in y:
|
||||
my_dict["discharge"] = q
|
||||
my_dict[dict_y["discharge"]] = q
|
||||
if "water_elevation" in y:
|
||||
my_dict["water_elevation"] = z
|
||||
my_dict[dict_y["water_elevation"]] = z
|
||||
if "velocity" in y:
|
||||
my_dict["velocity"] = list(
|
||||
my_dict[dict_y["velocity"]] = list(
|
||||
map(
|
||||
lambda q, z: profile.geometry.speed(q, z),
|
||||
q, z
|
||||
)
|
||||
)
|
||||
if "max_depth" in y:
|
||||
my_dict["max_depth"] = list(
|
||||
if "depth" in y:
|
||||
my_dict[dict_y["depth"]] = list(
|
||||
map(lambda z: profile.geometry.max_water_depth(z), z)
|
||||
)
|
||||
if "mean_depth" in y:
|
||||
my_dict["mean_depth"] = list(
|
||||
my_dict[dict_y["mean_depth"]] = list(
|
||||
map(lambda z: profile.geometry.mean_water_depth(z), z)
|
||||
)
|
||||
if "froude" in y:
|
||||
my_dict["froude"] = list(
|
||||
my_dict[dict_y["froude"]] = list(
|
||||
map(lambda z, q:
|
||||
profile.geometry.speed(q, z) /
|
||||
sqrt(9.81 * (
|
||||
@@ -778,7 +850,7 @@ class ResultsWindow(PamhyrWindow):
|
||||
), z, q)
|
||||
)
|
||||
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)
|
||||
)
|
||||
|
||||
|
||||
@@ -57,10 +57,10 @@ class ResultsTranslate(MainTranslate):
|
||||
"name": _translate("Results", "Profile"),
|
||||
"water_elevation": self._dict["unit_water_elevation"],
|
||||
"discharge": self._dict["unit_discharge"],
|
||||
"velocity": self._dict["unit_speed"],
|
||||
"velocity": self._dict["unit_velocity"],
|
||||
"width": self._dict["unit_width"],
|
||||
"max_depth": self._dict["unit_max_height"],
|
||||
"mean_depth": self._dict["unit_mean_height"],
|
||||
"depth": self._dict["unit_depth"],
|
||||
"mean_depth": self._dict["unit_mean_depth"],
|
||||
"wet_area": self._dict["unit_wet_area"],
|
||||
"wet_perimeter": self._dict["unit_wet_perimeter"],
|
||||
"hydraulic_radius": self._dict["unit_hydraulic_radius"],
|
||||
@@ -73,12 +73,25 @@ class ResultsTranslate(MainTranslate):
|
||||
}
|
||||
|
||||
self._sub_dict["values_y"] = {
|
||||
"elevation": self._dict["unit_elevation"],
|
||||
"bed_elevation": self._dict["unit_bed_elevation"],
|
||||
"water_elevation": self._dict["unit_water_elevation"],
|
||||
"discharge": self._dict["unit_discharge"],
|
||||
"velocity": self._dict["unit_speed"],
|
||||
"max_depth": self._dict["unit_max_height"],
|
||||
"mean_depth": self._dict["unit_mean_height"],
|
||||
"velocity": self._dict["unit_velocity"],
|
||||
"depth": self._dict["unit_depth"],
|
||||
"mean_depth": self._dict["unit_mean_depth"],
|
||||
"froude": self._dict["unit_froude"],
|
||||
"wet_area": self._dict["unit_wet_area"],
|
||||
}
|
||||
|
||||
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_y = self._trad["height"]
|
||||
self.label_y = self._trad["elevation"]
|
||||
|
||||
self.line_rk_zmin = None
|
||||
self.line_rk_sl = []
|
||||
|
||||
@@ -44,7 +44,7 @@ class Plot(PamhyrPlot):
|
||||
)
|
||||
|
||||
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_sl = []
|
||||
|
||||
@@ -30,7 +30,7 @@ class SedimentProfileTranslate(SedimentReachTranslate):
|
||||
self._dict["x"] = _translate(
|
||||
"SedimentLayers", "X (m)"
|
||||
)
|
||||
self._dict["height"] = self._dict["unit_height"]
|
||||
self._dict["elevation"] = self._dict["unit_elevation"]
|
||||
|
||||
self._dict["Profile sediment layers"] = _translate(
|
||||
"SedimentLayers", "Profile sediment layers"
|
||||
|
||||
@@ -35,7 +35,7 @@ class SedimentReachTranslate(SedimentTranslate):
|
||||
)
|
||||
|
||||
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"] = {
|
||||
"name": self._dict["name"],
|
||||
|
||||
@@ -142,7 +142,7 @@ class WindowToolKit(object):
|
||||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
msg = QMessageBox()
|
||||
msg = QMessageBox(parent=self)
|
||||
|
||||
msg.setIcon(QMessageBox.Warning)
|
||||
msg.setText(text)
|
||||
|
||||
+60
-9
@@ -54,18 +54,65 @@ class UnitTranslate(CommonWordTranslate):
|
||||
|
||||
self._dict["unit_rk"] = _translate("Unit", "River Kilometer (m)")
|
||||
self._dict["unit_width"] = _translate("Unit", "Width (m)")
|
||||
self._dict["unit_height"] = _translate("Unit", "Depth (m)")
|
||||
self._dict["unit_max_height"] = _translate("Unit", "Max Depth (m)")
|
||||
self._dict["unit_mean_height"] = _translate("Unit", "Mean Depth (m)")
|
||||
self._dict["unit_width_envelop"] = _translate(
|
||||
"Unit", "Width Envelop (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_thickness"] = _translate("Unit", "Thickness (m)")
|
||||
self._dict["unit_elevation"] = _translate("Unit", "Elevation (m)")
|
||||
self._dict["unit_water_elevation"] = _translate(
|
||||
"Unit", "Water elevation (m)"
|
||||
self._dict["unit_bed_elevation"] = _translate(
|
||||
"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_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_time_s"] = _translate("Unit", "Time (sec)")
|
||||
@@ -73,8 +120,7 @@ class UnitTranslate(CommonWordTranslate):
|
||||
|
||||
self._dict["unit_date_s"] = _translate("Unit", "Date (sec)")
|
||||
self._dict["unit_date_iso"] = _translate("Unit", "Date (ISO format)")
|
||||
|
||||
self._dict["unit_wet_area"] = _translate("Unit", "Wet Area (m^2)")
|
||||
self._dict["unit_wet_area"] = _translate("Unit", "Wet Area (m²)")
|
||||
self._dict["unit_wet_perimeter"] = _translate(
|
||||
"Unit", "Wet Perimeter (m)"
|
||||
)
|
||||
@@ -106,6 +152,9 @@ class MainTranslate(UnitTranslate):
|
||||
)
|
||||
|
||||
# Message box
|
||||
self._dict["Warning"] = _translate(
|
||||
"MainWindow", "Warning"
|
||||
)
|
||||
self._dict["mb_select_reach_title"] = _translate(
|
||||
"MainWindow", "Please select a reach"
|
||||
)
|
||||
@@ -130,3 +179,5 @@ class MainTranslate(UnitTranslate):
|
||||
"MainWindow",
|
||||
"Do you want to save current study before closing it?"
|
||||
)
|
||||
self._dict["x"] = _translate("MainWindow", "X (m)")
|
||||
self._dict["y"] = _translate("MainWindow", "Y (m)")
|
||||
+65
-16
@@ -247,6 +247,23 @@
|
||||
<source>Boundary Condition Options</source>
|
||||
<translation>Options des conditions limites</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/BoundaryCondition/Edit/translate.py" line="48"/>
|
||||
<source>No geometry</source>
|
||||
<translation>Pas de géométrie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/BoundaryCondition/Edit/translate.py" line="51"/>
|
||||
<source>No geometry found for this reach.
|
||||
This feature requires a reach with a geometry.</source>
|
||||
<translation>Aucune géométrie n'a été trouvée sur ce bief.
|
||||
Cette fonctionnalité nécessite un bief muni d'une géométrie.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/BoundaryCondition/Edit/translate.py" line="56"/>
|
||||
<source>Warning</source>
|
||||
<translation>Avertissement</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BoundaryConditions</name>
|
||||
@@ -1190,7 +1207,7 @@
|
||||
<message>
|
||||
<location filename="../View/Frictions/translate.py" line="38"/>
|
||||
<source>Edit frictions</source>
|
||||
<translation>Éditer les frotements</translation>
|
||||
<translation>Éditer les frottements</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Frictions/translate.py" line="31"/>
|
||||
@@ -1355,6 +1372,18 @@
|
||||
<source>Shift</source>
|
||||
<translation>Translater</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/BoundaryCondition/Edit/translate.py" line="48"/>
|
||||
<source>No geometry</source>
|
||||
<translation type="obsolete">Aucune géométrie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/BoundaryCondition/Edit/translate.py" line="51"/>
|
||||
<source>No geometry found for this reach.
|
||||
This feature requires a reach with a geometry.</source>
|
||||
<translation type="obsolete">Aucune géométrie n'a été trouvée sur ce bief.
|
||||
Cette fonctionnalité nécessite un bief muni d'une géométrie.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HydraulicStructures</name>
|
||||
@@ -1423,17 +1452,17 @@
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="98"/>
|
||||
<location filename="../View/Translate.py" line="97"/>
|
||||
<source>Open debug window</source>
|
||||
<translation>Ouvrir la fenêtre de débogage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="101"/>
|
||||
<location filename="../View/Translate.py" line="100"/>
|
||||
<source>Open SQLite debuging tool ('sqlitebrowser')</source>
|
||||
<translation>Ouvrir l'outil de débogage SQLite ('sqlitebrowser')</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="104"/>
|
||||
<location filename="../View/Translate.py" line="103"/>
|
||||
<source>Enable this window</source>
|
||||
<translation>Activer cette fenêtre</translation>
|
||||
</message>
|
||||
@@ -2278,12 +2307,12 @@
|
||||
<translation>Maillage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="91"/>
|
||||
<location filename="../View/Translate.py" line="90"/>
|
||||
<source>Summary</source>
|
||||
<translation>Résumé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="94"/>
|
||||
<location filename="../View/Translate.py" line="93"/>
|
||||
<source>Checks</source>
|
||||
<translation>Vérifications</translation>
|
||||
</message>
|
||||
@@ -2390,7 +2419,7 @@
|
||||
<message>
|
||||
<location filename="../View/ui/MainWindow.ui" line="482"/>
|
||||
<source>Edit frictions</source>
|
||||
<translation>Éditer les frotements</translation>
|
||||
<translation>Éditer les frottements</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/ui/GeometryCrossSection.ui" line="138"/>
|
||||
@@ -2503,7 +2532,7 @@
|
||||
<translation>Données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="109"/>
|
||||
<location filename="../View/Translate.py" line="111"/>
|
||||
<source>Please select a reach</source>
|
||||
<translation>Veuillez sélectionner un bief</translation>
|
||||
</message>
|
||||
@@ -2513,30 +2542,45 @@
|
||||
<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>
|
||||
<location filename="../View/Translate.py" line="118"/>
|
||||
<location filename="../View/Translate.py" line="120"/>
|
||||
<source>Last open study</source>
|
||||
<translation>Dernière étude ouverte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="121"/>
|
||||
<location filename="../View/Translate.py" line="123"/>
|
||||
<source>Do you want to open again the last open study?</source>
|
||||
<translation>Voulez-vous rouvrir la dernière étude ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="112"/>
|
||||
<location filename="../View/Translate.py" line="114"/>
|
||||
<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>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="126"/>
|
||||
<location filename="../View/Translate.py" line="128"/>
|
||||
<source>Close without saving study</source>
|
||||
<translation>Fermer sans sauvegarder l'étude</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="129"/>
|
||||
<location filename="../View/Translate.py" line="131"/>
|
||||
<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>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="108"/>
|
||||
<source>Warning</source>
|
||||
<translation>Avertissement</translation>
|
||||
</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>
|
||||
<name>MainWindow_reach</name>
|
||||
@@ -3217,17 +3261,17 @@
|
||||
<translation>Vitesse (m/s)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="78"/>
|
||||
<location filename="../View/Translate.py" line="77"/>
|
||||
<source>Wet Perimeter (m)</source>
|
||||
<translation>Périmètre mouillé (m)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="81"/>
|
||||
<location filename="../View/Translate.py" line="80"/>
|
||||
<source>Hydraulic Radius (m)</source>
|
||||
<translation>Rayon hydraulique (m)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="84"/>
|
||||
<location filename="../View/Translate.py" line="83"/>
|
||||
<source>Froude number</source>
|
||||
<translation>Nombre de Froude</translation>
|
||||
</message>
|
||||
@@ -3239,6 +3283,11 @@
|
||||
<message>
|
||||
<location filename="../View/Translate.py" line="77"/>
|
||||
<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>
|
||||
</message>
|
||||
</context>
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@
|
||||
Repport an issue :
|
||||
https://gitlab.irstea.fr/theophile.terraz/pamhyr/-/issues
|
||||
or by email at :
|
||||
<pierre-antoine.rouby@inrae.fr>
|
||||
<theophile.terraz@inrae.fr>
|
||||
------------------------------------------
|
||||
|
||||
---⚠️--Warning---------------------------
|
||||
|
||||
Reference in new issue
Block a user