mirror of
https://gitlab.com/pamhyr/pamhyr2.git
synced 2026-10-30 03:20:41 +01:00
Compare commits
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
# Pamhyr .editorconfig
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 8
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
+334
@@ -1,6 +1,7 @@
|
|||||||
### CUSTOM ###
|
### CUSTOM ###
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
|
*.msi
|
||||||
*.tar.xz
|
*.tar.xz
|
||||||
*.zip
|
*.zip
|
||||||
*.spec
|
*.spec
|
||||||
@@ -9,15 +10,33 @@
|
|||||||
|
|
||||||
tmp
|
tmp
|
||||||
|
|
||||||
|
*.tar
|
||||||
*.tar.*
|
*.tar.*
|
||||||
|
*.tgz
|
||||||
*.zip
|
*.zip
|
||||||
|
|
||||||
|
*.html
|
||||||
|
*.pdf
|
||||||
|
*.odt
|
||||||
|
|
||||||
|
doc/dev/images/auto_*
|
||||||
|
doc/dev/documentation.*
|
||||||
|
!doc/dev/*.org
|
||||||
|
|
||||||
|
doc/dev/images/auto_*
|
||||||
|
doc/users/documentation.*
|
||||||
|
!doc/users/*.org
|
||||||
|
|
||||||
|
TAGS
|
||||||
|
|
||||||
pamhyrBuild
|
pamhyrBuild
|
||||||
wine-pamhyr-build*
|
wine-pamhyr-build*
|
||||||
|
|
||||||
_PAMHYR_
|
_PAMHYR_
|
||||||
__old__
|
__old__
|
||||||
|
|
||||||
|
*-venv
|
||||||
|
|
||||||
### END CUSTOM ###
|
### END CUSTOM ###
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||||
@@ -309,3 +328,318 @@ compile_commands.json
|
|||||||
*_qmlcache.qrc
|
*_qmlcache.qrc
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/qt
|
# End of https://www.toptal.com/developers/gitignore/api/qt
|
||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/latex
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=latex
|
||||||
|
|
||||||
|
### LaTeX ###
|
||||||
|
## Core latex/pdflatex auxiliary files:
|
||||||
|
*.aux
|
||||||
|
*.lof
|
||||||
|
*.log
|
||||||
|
*.lot
|
||||||
|
*.fls
|
||||||
|
*.out
|
||||||
|
*.toc
|
||||||
|
*.fmt
|
||||||
|
*.fot
|
||||||
|
*.cb
|
||||||
|
*.cb2
|
||||||
|
.*.lb
|
||||||
|
|
||||||
|
## Intermediate documents:
|
||||||
|
*.dvi
|
||||||
|
*.xdv
|
||||||
|
*-converted-to.*
|
||||||
|
# these rules might exclude image files for figures etc.
|
||||||
|
# *.ps
|
||||||
|
# *.eps
|
||||||
|
# *.pdf
|
||||||
|
|
||||||
|
## Generated if empty string is given at "Please type another file name for output:"
|
||||||
|
.pdf
|
||||||
|
|
||||||
|
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||||
|
*.bbl
|
||||||
|
*.bcf
|
||||||
|
*.blg
|
||||||
|
*-blx.aux
|
||||||
|
*-blx.bib
|
||||||
|
*.run.xml
|
||||||
|
|
||||||
|
## Build tool auxiliary files:
|
||||||
|
*.fdb_latexmk
|
||||||
|
*.synctex
|
||||||
|
*.synctex(busy)
|
||||||
|
*.synctex.gz
|
||||||
|
*.synctex.gz(busy)
|
||||||
|
*.pdfsync
|
||||||
|
|
||||||
|
## Build tool directories for auxiliary files
|
||||||
|
# latexrun
|
||||||
|
latex.out/
|
||||||
|
|
||||||
|
## Auxiliary and intermediate files from other packages:
|
||||||
|
# algorithms
|
||||||
|
*.alg
|
||||||
|
*.loa
|
||||||
|
|
||||||
|
# achemso
|
||||||
|
acs-*.bib
|
||||||
|
|
||||||
|
# amsthm
|
||||||
|
*.thm
|
||||||
|
|
||||||
|
# beamer
|
||||||
|
*.nav
|
||||||
|
*.pre
|
||||||
|
*.snm
|
||||||
|
*.vrb
|
||||||
|
|
||||||
|
# changes
|
||||||
|
*.soc
|
||||||
|
|
||||||
|
# comment
|
||||||
|
*.cut
|
||||||
|
|
||||||
|
# cprotect
|
||||||
|
*.cpt
|
||||||
|
|
||||||
|
# elsarticle (documentclass of Elsevier journals)
|
||||||
|
*.spl
|
||||||
|
|
||||||
|
# endnotes
|
||||||
|
*.ent
|
||||||
|
|
||||||
|
# fixme
|
||||||
|
*.lox
|
||||||
|
|
||||||
|
# feynmf/feynmp
|
||||||
|
*.mf
|
||||||
|
*.mp
|
||||||
|
*.t[1-9]
|
||||||
|
*.t[1-9][0-9]
|
||||||
|
*.tfm
|
||||||
|
|
||||||
|
#(r)(e)ledmac/(r)(e)ledpar
|
||||||
|
*.end
|
||||||
|
*.?end
|
||||||
|
*.[1-9]
|
||||||
|
*.[1-9][0-9]
|
||||||
|
*.[1-9][0-9][0-9]
|
||||||
|
*.[1-9]R
|
||||||
|
*.[1-9][0-9]R
|
||||||
|
*.[1-9][0-9][0-9]R
|
||||||
|
*.eledsec[1-9]
|
||||||
|
*.eledsec[1-9]R
|
||||||
|
*.eledsec[1-9][0-9]
|
||||||
|
*.eledsec[1-9][0-9]R
|
||||||
|
*.eledsec[1-9][0-9][0-9]
|
||||||
|
*.eledsec[1-9][0-9][0-9]R
|
||||||
|
|
||||||
|
# glossaries
|
||||||
|
*.acn
|
||||||
|
*.acr
|
||||||
|
*.glg
|
||||||
|
*.glo
|
||||||
|
*.gls
|
||||||
|
*.glsdefs
|
||||||
|
*.lzo
|
||||||
|
*.lzs
|
||||||
|
*.slg
|
||||||
|
*.slo
|
||||||
|
*.sls
|
||||||
|
|
||||||
|
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||||
|
# *.ist
|
||||||
|
|
||||||
|
# gnuplot
|
||||||
|
*.gnuplot
|
||||||
|
*.table
|
||||||
|
|
||||||
|
# gnuplottex
|
||||||
|
*-gnuplottex-*
|
||||||
|
|
||||||
|
# gregoriotex
|
||||||
|
*.gaux
|
||||||
|
*.glog
|
||||||
|
*.gtex
|
||||||
|
|
||||||
|
# htlatex
|
||||||
|
*.4ct
|
||||||
|
*.4tc
|
||||||
|
*.idv
|
||||||
|
*.lg
|
||||||
|
*.trc
|
||||||
|
*.xref
|
||||||
|
|
||||||
|
# hyperref
|
||||||
|
*.brf
|
||||||
|
|
||||||
|
# knitr
|
||||||
|
*-concordance.tex
|
||||||
|
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||||
|
# *.tikz
|
||||||
|
*-tikzDictionary
|
||||||
|
|
||||||
|
# listings
|
||||||
|
*.lol
|
||||||
|
|
||||||
|
# luatexja-ruby
|
||||||
|
*.ltjruby
|
||||||
|
|
||||||
|
# makeidx
|
||||||
|
*.idx
|
||||||
|
*.ilg
|
||||||
|
*.ind
|
||||||
|
|
||||||
|
# minitoc
|
||||||
|
*.maf
|
||||||
|
*.mlf
|
||||||
|
*.mlt
|
||||||
|
*.mtc[0-9]*
|
||||||
|
*.slf[0-9]*
|
||||||
|
*.slt[0-9]*
|
||||||
|
*.stc[0-9]*
|
||||||
|
|
||||||
|
# minted
|
||||||
|
_minted*
|
||||||
|
*.pyg
|
||||||
|
|
||||||
|
# morewrites
|
||||||
|
*.mw
|
||||||
|
|
||||||
|
# newpax
|
||||||
|
*.newpax
|
||||||
|
|
||||||
|
# nomencl
|
||||||
|
*.nlg
|
||||||
|
*.nlo
|
||||||
|
*.nls
|
||||||
|
|
||||||
|
# pax
|
||||||
|
*.pax
|
||||||
|
|
||||||
|
# pdfpcnotes
|
||||||
|
*.pdfpc
|
||||||
|
|
||||||
|
# sagetex
|
||||||
|
*.sagetex.sage
|
||||||
|
*.sagetex.py
|
||||||
|
*.sagetex.scmd
|
||||||
|
|
||||||
|
# scrwfile
|
||||||
|
*.wrt
|
||||||
|
|
||||||
|
# svg
|
||||||
|
svg-inkscape/
|
||||||
|
|
||||||
|
# sympy
|
||||||
|
*.sout
|
||||||
|
*.sympy
|
||||||
|
sympy-plots-for-*.tex/
|
||||||
|
|
||||||
|
# pdfcomment
|
||||||
|
*.upa
|
||||||
|
*.upb
|
||||||
|
|
||||||
|
# pythontex
|
||||||
|
*.pytxcode
|
||||||
|
pythontex-files-*/
|
||||||
|
|
||||||
|
# tcolorbox
|
||||||
|
*.listing
|
||||||
|
|
||||||
|
# thmtools
|
||||||
|
*.loe
|
||||||
|
|
||||||
|
# TikZ & PGF
|
||||||
|
*.dpth
|
||||||
|
*.md5
|
||||||
|
*.auxlock
|
||||||
|
|
||||||
|
# titletoc
|
||||||
|
*.ptc
|
||||||
|
|
||||||
|
# todonotes
|
||||||
|
*.tdo
|
||||||
|
|
||||||
|
# vhistory
|
||||||
|
*.hst
|
||||||
|
*.ver
|
||||||
|
|
||||||
|
# easy-todo
|
||||||
|
*.lod
|
||||||
|
|
||||||
|
# xcolor
|
||||||
|
*.xcp
|
||||||
|
|
||||||
|
# xmpincl
|
||||||
|
*.xmpi
|
||||||
|
|
||||||
|
# xindy
|
||||||
|
*.xdy
|
||||||
|
|
||||||
|
# xypic precompiled matrices and outlines
|
||||||
|
*.xyc
|
||||||
|
*.xyd
|
||||||
|
|
||||||
|
# endfloat
|
||||||
|
*.ttt
|
||||||
|
*.fff
|
||||||
|
|
||||||
|
# Latexian
|
||||||
|
TSWLatexianTemp*
|
||||||
|
|
||||||
|
## Editors:
|
||||||
|
# WinEdt
|
||||||
|
*.bak
|
||||||
|
*.sav
|
||||||
|
|
||||||
|
# Texpad
|
||||||
|
.texpadtmp
|
||||||
|
|
||||||
|
# LyX
|
||||||
|
*.lyx~
|
||||||
|
|
||||||
|
# Kile
|
||||||
|
*.backup
|
||||||
|
|
||||||
|
# gummi
|
||||||
|
.*.swp
|
||||||
|
|
||||||
|
# KBibTeX
|
||||||
|
*~[0-9]*
|
||||||
|
|
||||||
|
# TeXnicCenter
|
||||||
|
*.tps
|
||||||
|
|
||||||
|
# auto folder when using emacs and auctex
|
||||||
|
./auto/*
|
||||||
|
*.el
|
||||||
|
|
||||||
|
# expex forward references with \gathertags
|
||||||
|
*-tags.tex
|
||||||
|
|
||||||
|
# standalone packages
|
||||||
|
*.sta
|
||||||
|
|
||||||
|
# Makeindex log files
|
||||||
|
*.lpz
|
||||||
|
|
||||||
|
# xwatermark package
|
||||||
|
*.xwm
|
||||||
|
|
||||||
|
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||||
|
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||||
|
# Uncomment the next line to have this generated file ignored.
|
||||||
|
#*Notes.bib
|
||||||
|
|
||||||
|
### LaTeX Patch ###
|
||||||
|
# LIPIcs / OASIcs
|
||||||
|
*.vtc
|
||||||
|
|
||||||
|
# glossaries
|
||||||
|
*.glstex
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/latex
|
||||||
+286
-100
@@ -15,97 +15,57 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- build
|
- downloads
|
||||||
|
- configure
|
||||||
- test
|
- test
|
||||||
|
- build
|
||||||
- package
|
- package
|
||||||
- release
|
- release
|
||||||
|
|
||||||
#########
|
#############
|
||||||
# BUILD #
|
# DOWNLOADS #
|
||||||
#########
|
#############
|
||||||
|
|
||||||
build-mage-linux:
|
dl-mage-linux:
|
||||||
stage: build
|
stage: downloads
|
||||||
tags:
|
tags:
|
||||||
- linux
|
- linux
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
script:
|
script:
|
||||||
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test6/downloads/packages/mage_linux.tgz
|
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test6/downloads/packages/mage_linux.tgz
|
||||||
- mkdir -p mage
|
- mkdir -p mage-linux
|
||||||
- cd mage
|
- cd mage-linux
|
||||||
- tar xvf ../mage.tgz
|
- tar xvf ../mage.tgz
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- mage/mage
|
- mage-linux/mage
|
||||||
- mage/mage_extraire
|
- mage-linux/mage_extraire
|
||||||
- mage/mailleurPF
|
- mage-linux/mailleurPF
|
||||||
|
|
||||||
# build-mage-linux:
|
dl-mage-windows:
|
||||||
# stage: build
|
stage: downloads
|
||||||
# tags:
|
|
||||||
# - linux
|
|
||||||
# rules:
|
|
||||||
# - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
|
||||||
# variables:
|
|
||||||
# GIT_SUBMODULE_STRATEGY: recursive
|
|
||||||
# GIT_SUBMODULE_DEPTH: 20
|
|
||||||
# script:
|
|
||||||
# - cd mage/src/
|
|
||||||
# - mkdir -p build
|
|
||||||
# - cd build
|
|
||||||
# - cmake ..
|
|
||||||
# - make
|
|
||||||
# artifacts:
|
|
||||||
# paths:
|
|
||||||
# - mage/src/build/mage
|
|
||||||
# - mage/src/build/mage_extraire
|
|
||||||
# - mage/src/build/mailleurPF
|
|
||||||
|
|
||||||
build-mage-windows:
|
|
||||||
stage: build
|
|
||||||
tags:
|
tags:
|
||||||
- linux
|
- linux
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
script:
|
script:
|
||||||
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test6/downloads/packages/mage_windows.tgz
|
- curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test6/downloads/packages/mage_windows.tgz
|
||||||
- mkdir -p mage
|
- mkdir -p mage-windows
|
||||||
- cd mage
|
- cd mage-windows
|
||||||
- tar xvf ../mage.tgz
|
- tar xvf ../mage.tgz
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- mage/mage.exe
|
- mage-windows/mage.exe
|
||||||
- mage/mage_extraire.exe
|
- mage-windows/mage_extraire.exe
|
||||||
- mage/mailleurPF.exe
|
- mage-windows/mailleurPF.exe
|
||||||
|
|
||||||
# build-mage-windows:
|
#############
|
||||||
# stage: build
|
# CONFIGURE #
|
||||||
# tags:
|
#############
|
||||||
# - wine
|
|
||||||
# rules:
|
|
||||||
# - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
|
||||||
# variables:
|
|
||||||
# GIT_SUBMODULE_STRATEGY: recursive
|
|
||||||
# GIT_SUBMODULE_DEPTH: 20
|
|
||||||
# script:
|
|
||||||
# - cd mage/src/
|
|
||||||
# - sed s/add_compile_definitions(win)/add_compile_definitions(windows)/ CMakeLists.txt > __tmp__
|
|
||||||
# - echo set(CMAKE_Fortran_COMPILER "C:/Program\ Files/gcc/bin/gfortran.exe") > CMakeLists.txt
|
|
||||||
# - echo set(CMAKE_MAKE_PROGRAM "C:/Program Files\ \(x86\)/GnuWin32/bin/make.exe") >> CMakeLists.txt
|
|
||||||
# - type __tmp__ >> CMakeLists.txt
|
|
||||||
# - mkdir build
|
|
||||||
# - cd build
|
|
||||||
# - cmake -G "MinGW Makefiles" ..
|
|
||||||
# - make
|
|
||||||
# artifacts:
|
|
||||||
# paths:
|
|
||||||
# - mage/src/build/mage.exe
|
|
||||||
# - mage/src/build/mage_extraire.exe
|
|
||||||
# - mage/src/build/mailleurPF.exe
|
|
||||||
|
|
||||||
build:
|
set-version:
|
||||||
stage: build
|
stage: configure
|
||||||
tags:
|
tags:
|
||||||
- linux
|
- linux
|
||||||
script:
|
script:
|
||||||
@@ -116,7 +76,7 @@ build:
|
|||||||
- VERSION
|
- VERSION
|
||||||
|
|
||||||
build-lang:
|
build-lang:
|
||||||
stage: build
|
stage: configure
|
||||||
tags:
|
tags:
|
||||||
- linux
|
- linux
|
||||||
script:
|
script:
|
||||||
@@ -130,56 +90,261 @@ build-lang:
|
|||||||
# TESTS #
|
# TESTS #
|
||||||
#########
|
#########
|
||||||
|
|
||||||
test:
|
unittest:
|
||||||
stage: test
|
stage: test
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
needs:
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
script:
|
script:
|
||||||
- echo "TODO PAMHYR tests"
|
- python3 -m venv venv
|
||||||
|
- . venv/bin/activate
|
||||||
|
- pip3 install -U pip
|
||||||
|
- pip3 install -r ./full-requirements.txt
|
||||||
|
- pip3 install -U -r ./full-requirements.txt
|
||||||
|
- cd src
|
||||||
|
- python3 -m unittest discover -t .
|
||||||
|
|
||||||
|
test-pep8:
|
||||||
|
stage: test
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
needs:
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
|
- job: unittest
|
||||||
|
script:
|
||||||
|
# Setup virtual env
|
||||||
|
- python3 -m venv venv
|
||||||
|
- . venv/bin/activate
|
||||||
|
- pip3 install -U pip
|
||||||
|
- pip3 install -r ./requirements.txt
|
||||||
|
- pip3 install -U -r ./requirements.txt
|
||||||
|
- pip3 install pycodestyle
|
||||||
|
- pycodestyle ./src
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
#########
|
||||||
|
# BUILD #
|
||||||
|
#########
|
||||||
|
|
||||||
|
build-users-doc:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
needs:
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
|
script:
|
||||||
|
- cd ./doc/users/
|
||||||
|
- ./build.sh
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- doc/users/documentation.pdf
|
||||||
|
- doc/users/documentation.html
|
||||||
|
- doc/users/images/
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
build-developers-doc:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
needs:
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
|
script:
|
||||||
|
- cd ./doc/dev/
|
||||||
|
- ./build.sh
|
||||||
|
# Create html documentation
|
||||||
|
- cd ../../src
|
||||||
|
- python3 -m venv doc-venv
|
||||||
|
- . doc-venv/bin/activate
|
||||||
|
- pip3 install -U pip
|
||||||
|
- pip3 install -r ../full-requirements.txt
|
||||||
|
- pip3 install -U -r ../full-requirements.txt
|
||||||
|
- pip3 install pdoc3
|
||||||
|
- pdoc --html .
|
||||||
|
# Create archive
|
||||||
|
- tar cf html.tar ./html
|
||||||
|
- cd ../doc/dev
|
||||||
|
- mv ../../src/html.tar ./
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- doc/dev/documentation.pdf
|
||||||
|
- doc/dev/documentation.html
|
||||||
|
- doc/dev/html.tar
|
||||||
|
- doc/dev/images/
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- linux
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
needs:
|
||||||
|
- job: dl-mage-linux
|
||||||
|
artifacts: true
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
|
- job: build-lang
|
||||||
|
artifacts: true
|
||||||
|
- job: build-developers-doc
|
||||||
|
artifacts: true
|
||||||
|
- job: build-users-doc
|
||||||
|
artifacts: true
|
||||||
|
script:
|
||||||
|
- mkdir -p linux
|
||||||
|
- cd linux
|
||||||
|
# Setup virtual env
|
||||||
|
- python3 -m venv linux-venv
|
||||||
|
- . linux-venv/bin/activate
|
||||||
|
- pip3 install -U pip
|
||||||
|
- pip3 install -r ../requirements.txt
|
||||||
|
- pip3 install -U -r ../requirements.txt
|
||||||
|
# Run Pyinstaller
|
||||||
|
- pyinstaller -y --paths linux-venv/lib/python3.8/site-packages ../src/pamhyr.py
|
||||||
|
# Create directory
|
||||||
|
- mkdir -p pamhyr
|
||||||
|
- mkdir -p pamhyr/pamhyr
|
||||||
|
- mkdir -p pamhyr/pamhyr/_internal
|
||||||
|
# Copy Pamhyr info
|
||||||
|
- cp -v ../VERSION pamhyr/pamhyr/_internal/
|
||||||
|
- cp -v ../AUTHORS pamhyr/pamhyr/_internal/
|
||||||
|
- cp -v ../LICENSE pamhyr/pamhyr/_internal/
|
||||||
|
- cp -v ../src/motd.txt pamhyr/pamhyr/_internal/
|
||||||
|
# Copy mage
|
||||||
|
- mkdir -p pamhyr/mage
|
||||||
|
- cp -v ../mage-linux/* pamhyr/mage/
|
||||||
|
# Copy Pamhyr
|
||||||
|
- cp -r dist/pamhyr pamhyr/
|
||||||
|
# Copy Pamhyr resources
|
||||||
|
- mkdir -p pamhyr/pamhyr/_internal/View
|
||||||
|
- mkdir -p pamhyr/pamhyr/_internal/View/ui
|
||||||
|
- mkdir -p pamhyr/pamhyr/_internal/View/ui/Widgets
|
||||||
|
- cp -r ../src/View/ui/*.ui pamhyr/pamhyr/_internal/View/ui/
|
||||||
|
- cp -r ../src/View/ui/ressources/ pamhyr/pamhyr/_internal/View/ui
|
||||||
|
- cp -r ../src/View/ui/Widgets/*.ui pamhyr/pamhyr/_internal/View/ui/Widgets
|
||||||
|
# Copy lang
|
||||||
|
- mkdir -p pamhyr/pamhyr/_internal/lang
|
||||||
|
- cp -r ../src/lang/*.qm pamhyr/pamhyr/_internal/lang
|
||||||
|
# Copy tests cases
|
||||||
|
- mkdir -p pamhyr/tests_cases/
|
||||||
|
- mkdir -p pamhyr/tests_cases/Saar
|
||||||
|
- cp ../tests_cases/Saar/Saar.pamhyr pamhyr/tests_cases/Saar/
|
||||||
|
# Copy documentations
|
||||||
|
- mkdir -p pamhyr/doc/
|
||||||
|
- mkdir -p pamhyr/doc/images/
|
||||||
|
- mkdir -p pamhyr/doc/html/
|
||||||
|
- cp ../doc/users/documentation.pdf pamhyr/doc/Pamhyr2-users.pdf
|
||||||
|
- cp ../doc/users/documentation.html pamhyr/doc/Pamhyr2-users.html
|
||||||
|
- cp ../doc/dev/documentation.pdf pamhyr/doc/Pamhyr2-dev.pdf
|
||||||
|
- cp ../doc/dev/documentation.html pamhyr/doc/Pamhyr2-dev.html
|
||||||
|
#- cp ../doc/users/images/* pamhyr/doc/images
|
||||||
|
- cp ../doc/dev/images/* pamhyr/doc/images
|
||||||
|
- cp ../doc/images/* pamhyr/doc/images
|
||||||
|
# Create running script
|
||||||
|
- echo "#!/bin/sh" > pamhyr/Pamhyr2
|
||||||
|
- echo "./pamhyr/pamhyr $@" >> pamhyr/Pamhyr2
|
||||||
|
- chmod u+x pamhyr/Pamhyr2
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- linux/pamhyr
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- wine
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
||||||
|
needs:
|
||||||
|
- job: dl-mage-windows
|
||||||
|
artifacts: true
|
||||||
|
- job: set-version
|
||||||
|
artifacts: true
|
||||||
|
- job: build-lang
|
||||||
|
artifacts: true
|
||||||
|
- job: build-developers-doc
|
||||||
|
artifacts: true
|
||||||
|
- job: build-users-doc
|
||||||
|
artifacts: true
|
||||||
|
script:
|
||||||
|
- mkdir windows
|
||||||
|
- cd windows
|
||||||
|
# Setup env
|
||||||
|
- python -m pip install -r ..\requirements.txt
|
||||||
|
- python -m pip install -U -r ..\requirements.txt
|
||||||
|
# Run Pyinstaller
|
||||||
|
- pyinstaller -y ..\src\pamhyr.py
|
||||||
|
# Create directory
|
||||||
|
- mkdir pamhyr
|
||||||
|
- dir
|
||||||
|
- copy ..\packages\make-windows-dir.bat .\make-windows-dir.bat
|
||||||
|
- .\make-windows-dir.bat
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- windows/pamhyr
|
||||||
|
|
||||||
############
|
############
|
||||||
# PACKAGES #
|
# PACKAGES #
|
||||||
############
|
############
|
||||||
|
|
||||||
linux-package:
|
linux-package-tar:
|
||||||
stage: package
|
stage: package
|
||||||
tags:
|
tags:
|
||||||
- release
|
- release
|
||||||
- linux
|
- linux
|
||||||
needs:
|
needs:
|
||||||
- job: build-lang
|
# - job: test-linux
|
||||||
artifacts: true
|
- job: build-linux
|
||||||
- job: build
|
|
||||||
artifacts: true
|
|
||||||
- job: build-mage-linux
|
|
||||||
artifacts: true
|
artifacts: true
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_TAG
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- packages/pamhyr-gnulinux-amd64.tar.xz
|
- linux/pamhyr-gnulinux.tar.xz
|
||||||
script:
|
script:
|
||||||
- cd packages
|
- cd linux
|
||||||
- ./linux.sh
|
- tar --xz -cf pamhyr-gnulinux.tar.xz ./pamhyr --checkpoint=.100
|
||||||
|
|
||||||
windows-package:
|
windows-package-zip:
|
||||||
|
stage: package
|
||||||
|
tags:
|
||||||
|
- release
|
||||||
|
- linux
|
||||||
|
needs:
|
||||||
|
# - job: test-windows
|
||||||
|
- job: build-windows
|
||||||
|
artifacts: true
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_TAG
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- windows/pamhyr-windows.zip
|
||||||
|
script:
|
||||||
|
- cd windows
|
||||||
|
- zip -r pamhyr-windows.zip pamhyr
|
||||||
|
|
||||||
|
windows-package-exe:
|
||||||
stage: package
|
stage: package
|
||||||
tags:
|
tags:
|
||||||
- release
|
- release
|
||||||
- wine
|
- wine
|
||||||
needs:
|
needs:
|
||||||
- job: build-lang
|
# - job: test-windows
|
||||||
artifacts: true
|
- job: build-windows
|
||||||
- job: build
|
|
||||||
artifacts: true
|
|
||||||
- job: build-mage-windows
|
|
||||||
artifacts: true
|
artifacts: true
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
|
- if: $CI_COMMIT_BRANCH == 'ci-test' || $CI_COMMIT_TAG
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- packages/pamhyr-win-amd64.exe
|
- windows/pamhyr-windows.exe
|
||||||
script:
|
script:
|
||||||
- cd packages
|
- cd windows
|
||||||
- ./windows.bat
|
- copy ..\packages\make-windows-exe.bat make-windows-exe.bat
|
||||||
|
- copy ..\packages\pamhyr.nsi pamhyr.nsi
|
||||||
|
- .\make-windows-exe.bat
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# RELEASE #
|
# RELEASE #
|
||||||
@@ -191,16 +356,25 @@ tag-release:
|
|||||||
- release
|
- release
|
||||||
- linux
|
- linux
|
||||||
needs:
|
needs:
|
||||||
- job: linux-package
|
- job: linux-package-tar
|
||||||
artifacts: true
|
artifacts: true
|
||||||
- job: windows-package
|
- job: windows-package-zip
|
||||||
|
artifacts: true
|
||||||
|
- job: windows-package-exe
|
||||||
|
artifacts: true
|
||||||
|
- job: build-users-doc
|
||||||
|
artifacts: true
|
||||||
|
- job: build-developers-doc
|
||||||
artifacts: true
|
artifacts: true
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_TAG
|
- if: $CI_COMMIT_TAG
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- packages/pamhyr-gnulinux-amd64.tar.xz
|
- linux/pamhyr-gnulinux.tar.xz
|
||||||
- packages/pamhyr-win-amd64.exe
|
- windows/pamhyr-windows.zip
|
||||||
|
- windows/pamhyr-windows.exe
|
||||||
|
- doc/dev/documentation.pdf
|
||||||
|
- doc/users/documentation.pdf
|
||||||
script:
|
script:
|
||||||
- cd packages
|
- cd packages
|
||||||
release:
|
release:
|
||||||
@@ -210,11 +384,23 @@ tag-release:
|
|||||||
ref: '$CI_COMMIT_SHA'
|
ref: '$CI_COMMIT_SHA'
|
||||||
assets:
|
assets:
|
||||||
links:
|
links:
|
||||||
- name: 'GNU/Linux amd64 (tar.xz)'
|
- name: 'GNU/Linux (tar.xz)'
|
||||||
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-gnulinux-amd64.tar.xz'
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/linux/pamhyr-gnulinux.tar.xz'
|
||||||
filepath: '/packages/pamhyr-gnulinux-amd64.tar.xz'
|
filepath: '/linux/pamhyr-gnulinux.tar.xz'
|
||||||
link_type: 'package'
|
link_type: 'package'
|
||||||
- name: 'Windows amd64 (exe)'
|
- name: 'Windows (exe)'
|
||||||
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-win-amd64.exe'
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.exe'
|
||||||
filepath: '/packages/pamhyr-win-amd64.exe'
|
filepath: '/windows/pamhyr-windows.exe'
|
||||||
link_type: 'package'
|
link_type: 'package'
|
||||||
|
- name: 'Windows (zip)'
|
||||||
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/windows/pamhyr-windows.zip'
|
||||||
|
filepath: '/windows/pamhyr-windows.zip'
|
||||||
|
link_type: 'package'
|
||||||
|
- name: 'User documentations (pdf)'
|
||||||
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/doc/users/documentation.pdf'
|
||||||
|
filepath: '/doc/users/documentation.pdf'
|
||||||
|
link_type: 'other'
|
||||||
|
- name: 'Dev documentations (pdf)'
|
||||||
|
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/doc/dev/documentation.pdf'
|
||||||
|
filepath: '/doc/dev/documentation.pdf'
|
||||||
|
link_type: 'other'
|
||||||
@@ -47,5 +47,4 @@ pip3 install -r requirements.txt
|
|||||||
|
|
||||||
# Run pamhyr
|
# Run pamhyr
|
||||||
./src/pamhyr.py
|
./src/pamhyr.py
|
||||||
|
|
||||||
```
|
```
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
echo " PDF documentation.org"
|
||||||
|
emacs -nw --batch \
|
||||||
|
--eval "(require 'org)" \
|
||||||
|
--eval "(require 'ox-latex)" \
|
||||||
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
|
--file ./documentation.org \
|
||||||
|
-f org-latex-export-to-pdf
|
||||||
|
|
||||||
|
echo " HTML documentation.org"
|
||||||
|
emacs -nw --batch \
|
||||||
|
--eval "(require 'org)" \
|
||||||
|
--eval "(require 'ox-latex)" \
|
||||||
|
--eval "(require 'ox-html)" \
|
||||||
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
|
--file ./documentation.org \
|
||||||
|
-f org-html-export-to-html
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../tools/ref.bib
|
||||||
File diff suppressed because it is too large.
Load diff
Whitespace-only changes.
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,163 @@
|
|||||||
|
\ProvidesClass{Pamhyr}[Pamhyr class]
|
||||||
|
\NeedsTeXFormat{LaTeX2e}
|
||||||
|
\ProcessOptions\relax
|
||||||
|
\LoadClass[11pt,a4paper]{article}
|
||||||
|
|
||||||
|
\usepackage[hmargin=2cm, vmargin=3cm]{geometry}
|
||||||
|
\usepackage[british,UKenglish,USenglish,english,american]{babel}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage{times}
|
||||||
|
\usepackage[usenames,dvipsnames]{xcolor}
|
||||||
|
\usepackage[absolute]{textpos}
|
||||||
|
\usepackage{titlesec}
|
||||||
|
\usepackage{amssymb}
|
||||||
|
\usepackage{tcolorbox}
|
||||||
|
|
||||||
|
\usepackage{enumitem}
|
||||||
|
\setlist[enumerate]{itemsep=-0.5em}
|
||||||
|
\setlist[itemize]{itemsep=-0.5em}
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Bibtex
|
||||||
|
%%
|
||||||
|
|
||||||
|
\bibliographystyle{plain}
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Colors
|
||||||
|
%%
|
||||||
|
|
||||||
|
\definecolor{primary}{HTML}{212121}
|
||||||
|
\definecolor{lightheadings}{HTML}{5c5c5c}
|
||||||
|
\definecolor{headings}{HTML}{212121}
|
||||||
|
\definecolor{links}{HTML}{e12121}
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Title
|
||||||
|
%%
|
||||||
|
|
||||||
|
\setlength{\columnsep}{20pt}
|
||||||
|
\setlength{\parskip}{0pt} %% inter paragraph space
|
||||||
|
|
||||||
|
\renewcommand{\maketitle}{
|
||||||
|
{
|
||||||
|
\centering
|
||||||
|
{
|
||||||
|
\fontsize{35}{40}
|
||||||
|
\selectfont
|
||||||
|
\scshape
|
||||||
|
Pamhyr2 \\
|
||||||
|
\medskip
|
||||||
|
}
|
||||||
|
{
|
||||||
|
%\centering
|
||||||
|
\scshape
|
||||||
|
\fontsize{20pt}{24pt}
|
||||||
|
\selectfont
|
||||||
|
A graphical user interface for 1D hydro-sedimentary modelling
|
||||||
|
of rivers \\
|
||||||
|
\medskip
|
||||||
|
}
|
||||||
|
\rule{3cm}{0.4pt}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
{
|
||||||
|
%\centering
|
||||||
|
\scshape
|
||||||
|
\fontsize{26pt}{24pt}
|
||||||
|
\selectfont
|
||||||
|
\@title \\
|
||||||
|
Document licence: GPLv3 \\
|
||||||
|
\medskip
|
||||||
|
\includegraphics[width=3cm]{../images/GPLv3_Logo.png} \\
|
||||||
|
\medskip
|
||||||
|
\fontsize{14pt}{16pt}
|
||||||
|
\selectfont
|
||||||
|
© \@author \\
|
||||||
|
\medskip
|
||||||
|
}
|
||||||
|
{
|
||||||
|
%\centering
|
||||||
|
%\scshape
|
||||||
|
\fontsize{12pt}{14pt}
|
||||||
|
\selectfont
|
||||||
|
\@date
|
||||||
|
%\medskip
|
||||||
|
}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
\rule{3cm}{0.4pt}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
{
|
||||||
|
\begin{minipage}[h]{0.24\textwidth}
|
||||||
|
\includegraphics[width=4cm]{../../src/View/ui/ressources/Logo-INRAE.png}
|
||||||
|
\end{minipage}
|
||||||
|
\begin{minipage}[h]{0.24\textwidth}
|
||||||
|
\includegraphics[width=4cm]{../images/riverly.png}
|
||||||
|
\end{minipage}
|
||||||
|
}\\
|
||||||
|
\vspace{0.3cm}
|
||||||
|
%%\rule{\textwidth}{0.4pt}
|
||||||
|
%%\newpage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Texttt
|
||||||
|
%%
|
||||||
|
|
||||||
|
\usepackage[htt]{hyphenat} % Make texttt split at end of line
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Verbatim
|
||||||
|
%%
|
||||||
|
|
||||||
|
\AtBeginEnvironment{verbatim}{\footnotesize}
|
||||||
|
|
||||||
|
%% Add box arrond of verbatim
|
||||||
|
\BeforeBeginEnvironment{verbatim}{\begin{tcolorbox}[boxsep=0pt, left=0.1cm, right=0.1cm, arc=0pt, boxrule=0.5pt, colback=white]}%
|
||||||
|
\AfterEndEnvironment{verbatim}{\end{tcolorbox}}%
|
||||||
|
|
||||||
|
\makeatletter
|
||||||
|
\AtBeginEnvironment{verbatim}{\dontdofcolorbox}
|
||||||
|
|
||||||
|
\def\dontdofcolorbox{\renewcommand\fcolorbox[4][]{##4}}
|
||||||
|
\makeatother
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Source code blocks
|
||||||
|
%%
|
||||||
|
|
||||||
|
%% Use minted
|
||||||
|
\usepackage{minted}
|
||||||
|
\usemintedstyle{tango}
|
||||||
|
\setminted[c]{fontsize=\footnotesize,encoding=utf8,linenos}
|
||||||
|
\setminted[c++]{breaklines,fontsize=\footnotesize,encoding=utf8,linenos}
|
||||||
|
\setminted[python]{breaklines,fontsize=\footnotesize,encoding=utf8,linenos}
|
||||||
|
\setminted[shell]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[scheme]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[commun-lisp]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[text]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
\setminted[llvm]{breaklines,fontsize=\footnotesize,encoding=utf8}
|
||||||
|
|
||||||
|
%% Add box arrond of minted
|
||||||
|
\BeforeBeginEnvironment{minted}{\begin{tcolorbox}[boxsep=0pt, left=0.1cm, right=0.1cm, arc=0pt, boxrule=0.5pt, colback=white]}%
|
||||||
|
\AfterEndEnvironment{minted}{\end{tcolorbox}}%
|
||||||
|
|
||||||
|
\makeatletter
|
||||||
|
\AtBeginEnvironment{minted}{\dontdofcolorbox}
|
||||||
|
|
||||||
|
\def\dontdofcolorbox{\renewcommand\fcolorbox[4][]{##4}}
|
||||||
|
\makeatother
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Water mark
|
||||||
|
%%
|
||||||
|
|
||||||
|
%% FIXME: Delete me for the first realease
|
||||||
|
\usepackage{draftwatermark}
|
||||||
|
\SetWatermarkLightness{0.8}
|
||||||
|
\SetWatermarkAngle{25}
|
||||||
|
\SetWatermarkScale{3}
|
||||||
|
\SetWatermarkFontSize{1cm}
|
||||||
|
\SetWatermarkText{Work in progress}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# latex.org -- Pamhyr documentation latex config
|
||||||
|
# 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 -*-
|
||||||
|
|
||||||
|
#+LaTeX_CLASS: PamhyrDoc
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# macro.org -- Pamhyr documentation macro
|
||||||
|
# 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 -*-
|
||||||
|
|
||||||
|
# Constant name
|
||||||
|
#+MACRO: oldPamhyr PAMHyR
|
||||||
|
#+MACRO: Pamhyr Pamhyr2
|
||||||
|
#+MACRO: Mage Mage
|
||||||
|
#+MACRO: Rubarbe RubarBE
|
||||||
|
#+MACRO: Inrae INRAE
|
||||||
|
#+MACRO: latex \LaTeX
|
||||||
|
|
||||||
|
# Information
|
||||||
|
#+MACRO: version (eval (pamhyr-version))
|
||||||
|
#+MACRO: current-file (eval (pamhyr-current-file))
|
||||||
|
|
||||||
|
# Special format
|
||||||
|
#+MACRO: file =$1=
|
||||||
|
|
||||||
|
# Biblio
|
||||||
|
#+MACRO: cite [cite:$1]
|
||||||
|
#+MACRO: biblio \bibliography{documentation}
|
||||||
|
|
||||||
|
# Wrapper
|
||||||
|
#+NAME: attr_wrap
|
||||||
|
#+HEADER: :var width="\\textwidth"
|
||||||
|
#+HEADER: :var caption=""
|
||||||
|
#+HEADER: :var smallcaption=""
|
||||||
|
#+HEADER: :var name=""
|
||||||
|
#+HEADER: :var data=""
|
||||||
|
#+HEADER: :var float="nil"
|
||||||
|
#+BEGIN_SRC sh :results output :exports none
|
||||||
|
echo "#+CAPTION[$smallcaption]: $caption"
|
||||||
|
echo "#+NAME: $name"
|
||||||
|
echo "#+ATTR_LATEX: :width $width :float $float"
|
||||||
|
echo "$data"
|
||||||
|
#+END_SRC
|
||||||
Whitespace-only changes.
@@ -0,0 +1,66 @@
|
|||||||
|
(require 'org)
|
||||||
|
(require 'subr-x)
|
||||||
|
|
||||||
|
;; LaTeX config
|
||||||
|
|
||||||
|
(add-to-list
|
||||||
|
'org-latex-classes
|
||||||
|
'("PamhyrDoc"
|
||||||
|
"\\documentclass{../tools/PamhyrDoc}"
|
||||||
|
("\\section{%s}" . "\\section*{%s}")
|
||||||
|
("\\subsection{%s}" . "\\subsection*{%s}")
|
||||||
|
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
|
||||||
|
("\\paragraph{%s}" . "\\paragraph*{%s}")
|
||||||
|
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
|
||||||
|
|
||||||
|
(setq org-confirm-babel-evaluate nil)
|
||||||
|
(setq org-latex-caption-above nil)
|
||||||
|
|
||||||
|
(org-babel-do-load-languages
|
||||||
|
'org-babel-load-languages
|
||||||
|
(add-to-list 'org-babel-load-languages '(shell . t)))
|
||||||
|
|
||||||
|
(org-babel-do-load-languages
|
||||||
|
'org-babel-load-languages
|
||||||
|
(add-to-list 'org-babel-load-languages '(dot . t)))
|
||||||
|
|
||||||
|
(org-babel-do-load-languages
|
||||||
|
'org-babel-load-languages
|
||||||
|
(add-to-list 'org-babel-load-languages '(python . t)))
|
||||||
|
|
||||||
|
(add-to-list 'org-latex-packages-alist '("" "minted"))
|
||||||
|
(setq org-latex-listings 'minted)
|
||||||
|
(setq org-src-fontify-natively t)
|
||||||
|
|
||||||
|
(setq org-latex-pdf-process
|
||||||
|
'("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
|
||||||
|
"bibtex documentation"
|
||||||
|
"pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
|
||||||
|
"pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"))
|
||||||
|
|
||||||
|
;; Citations
|
||||||
|
|
||||||
|
(org-add-link-type
|
||||||
|
"cite" 'ebib
|
||||||
|
(lambda (path desc format)
|
||||||
|
(cond
|
||||||
|
((eq format 'html)
|
||||||
|
(format "(<cite>%s</cite>)" 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))))))
|
||||||
|
|
||||||
|
;; Functools
|
||||||
|
|
||||||
|
(defun pamhyr-version ()
|
||||||
|
"Return the contents of the pamhyr version file."
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents "../../VERSION")
|
||||||
|
(buffer-string)))
|
||||||
|
|
||||||
|
(defun pamhyr-current-file ()
|
||||||
|
(let ((lst (split-string (buffer-file-name) "/")))
|
||||||
|
(string-join (nthcdr (- (length lst) 3) lst) "/")))
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
echo " PDF documentation.org"
|
||||||
|
emacs -nw --batch \
|
||||||
|
--eval "(require 'org)" \
|
||||||
|
--eval "(require 'ox-latex)" \
|
||||||
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
|
--file ./documentation.org \
|
||||||
|
-f org-latex-export-to-pdf
|
||||||
|
|
||||||
|
echo " HTML documentation.org"
|
||||||
|
emacs -nw --batch \
|
||||||
|
--eval "(require 'org)" \
|
||||||
|
--eval "(require 'ox-latex)" \
|
||||||
|
--eval "(require 'ox-html)" \
|
||||||
|
--eval "(load-file \"../tools/setup.el\")" \
|
||||||
|
--file ./documentation.org \
|
||||||
|
-f org-html-export-to-html
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../tools/ref.bib
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#+STARTUP: indent
|
||||||
|
|
||||||
|
#+INCLUDE: ../tools/macro.org
|
||||||
|
#+INCLUDE: ../tools/latex.org
|
||||||
|
|
||||||
|
#+TITLE: User documentation
|
||||||
|
#+SUBTITLE: Version: {{{version}}}
|
||||||
|
#+AUTHOR: {{{INRAE}}}
|
||||||
|
|
||||||
|
#+OPTIONS: toc:t
|
||||||
|
#+LANGUAGE: UKenglish
|
||||||
|
|
||||||
|
* TODO Over view
|
||||||
|
* TODO Get started
|
||||||
|
** Installation
|
||||||
|
*** Linux
|
||||||
|
*** Windows
|
||||||
|
* TODO Usage
|
||||||
|
|
||||||
|
{{{biblio}}}
|
||||||
Whitespace-only changes.
@@ -0,0 +1,11 @@
|
|||||||
|
PyQt5==5.15.4
|
||||||
|
PyQt5-Qt5==5.15.2
|
||||||
|
PyQt5-sip==12.12.2
|
||||||
|
PyQtWebEngine==5.15.6
|
||||||
|
QScintilla>=2.14.1
|
||||||
|
pyqtgraph>=0.12.1
|
||||||
|
matplotlib>=3.4.1
|
||||||
|
numpy>=1.24.2
|
||||||
|
colorama>=0.4.3
|
||||||
|
pyinstaller>=5.11.0
|
||||||
|
shapely>=2.0.1
|
||||||
+30
-13
@@ -25,6 +25,7 @@ echo " *** SETUP ENV"
|
|||||||
|
|
||||||
python3 -m venv linux-pamhyr-venv
|
python3 -m venv linux-pamhyr-venv
|
||||||
. linux-pamhyr-venv/bin/activate
|
. linux-pamhyr-venv/bin/activate
|
||||||
|
pip3 install -U pip
|
||||||
pip3 install -r ../requirements.txt
|
pip3 install -r ../requirements.txt
|
||||||
|
|
||||||
echo " *** PYINSTALL"
|
echo " *** PYINSTALL"
|
||||||
@@ -43,18 +44,22 @@ cd $OLD_PWD
|
|||||||
|
|
||||||
echo " *** COPY DATA"
|
echo " *** COPY DATA"
|
||||||
|
|
||||||
mkdir -p dist/pamhyr/View/ui
|
mkdir -p dist/pamhyr/_internal/View/ui
|
||||||
mkdir -p dist/pamhyr/View/ui/Widgets
|
mkdir -p dist/pamhyr/_internal/View/ui/Widgets
|
||||||
cp -r ../src/View/ui/ressources/ dist/pamhyr/View/ui/
|
cp -r ../src/View/ui/ressources/ dist/pamhyr/_internal/View/ui/
|
||||||
cp -r ../src/View/ui/Widgets/*.ui dist/pamhyr/View/ui/Widgets/
|
cp -r ../src/View/ui/Widgets/*.ui dist/pamhyr/_internal/View/ui/Widgets/
|
||||||
cp -r ../src/View/ui/*.ui dist/pamhyr/View/ui/
|
cp -r ../src/View/ui/*.ui dist/pamhyr/_internal/View/ui/
|
||||||
|
|
||||||
mkdir -p dist/pamhyr/lang
|
mkdir -p dist/pamhyr/lang
|
||||||
cp -r ../src/lang/*.qm dist/pamhyr/lang/
|
cp -r ../src/lang/*.qm dist/pamhyr/lang/
|
||||||
|
|
||||||
cp ../VERSION dist/pamhyr/
|
mkdir dist/pamhyr/_internal/
|
||||||
cp ../AUTHORS dist/pamhyr/
|
#cp ../VERSION dist/pamhyr/_internal/
|
||||||
cp ../LICENSE dist/pamhyr/
|
VERSION=$(cat ../VERSION)
|
||||||
|
echo "local-build-$VERSION" > dist/pamhyr/_internal/VERSION
|
||||||
|
cp ../AUTHORS dist/pamhyr/_internal/
|
||||||
|
cp ../LICENSE dist/pamhyr/_internal/
|
||||||
|
cp ../src/motd.txt dist/pamhyr/_internal/
|
||||||
|
|
||||||
mkdir -p dist/pamhyr/mage/
|
mkdir -p dist/pamhyr/mage/
|
||||||
cp ../mage/mage dist/pamhyr/mage/
|
cp ../mage/mage dist/pamhyr/mage/
|
||||||
@@ -65,6 +70,18 @@ mkdir -p dist/pamhyr/tests_cases/
|
|||||||
mkdir -p dist/pamhyr/tests_cases/Saar
|
mkdir -p dist/pamhyr/tests_cases/Saar
|
||||||
cp ../tests_cases/Saar/Saar.pamhyr dist/pamhyr/tests_cases/Saar/
|
cp ../tests_cases/Saar/Saar.pamhyr dist/pamhyr/tests_cases/Saar/
|
||||||
|
|
||||||
|
mkdir -p dist/pamhyr/doc/
|
||||||
|
cp ../doc/dev/documentation.pdf dist/pamhyr/doc/Pamhyr2-dev.pdf
|
||||||
|
cp ../doc/dev/documentation.html dist/pamhyr/doc/Pamhyr2-dev.html
|
||||||
|
|
||||||
|
cp ../doc/users/documentation.pdf dist/pamhyr/doc/Pamhyr2-users.pdf
|
||||||
|
cp ../doc/users/documentation.html dist/pamhyr/doc/Pamhyr2-users.html
|
||||||
|
|
||||||
|
mkdir -p dist/pamhyr/doc/images
|
||||||
|
cp ../doc/users/images/* dist/pamhyr/doc/images/
|
||||||
|
cp ../doc/dev/images/* dist/pamhyr/doc/images/
|
||||||
|
cp ../doc/images/* dist/pamhyr/doc/images/
|
||||||
|
|
||||||
echo " *** MAKE SRC PACKAGE"
|
echo " *** MAKE SRC PACKAGE"
|
||||||
|
|
||||||
OLD_PWD=$PWD
|
OLD_PWD=$PWD
|
||||||
@@ -76,11 +93,11 @@ mv ../pamhyr-src.tar.gz ./
|
|||||||
|
|
||||||
echo " *** MAKE BIN PACKAGE"
|
echo " *** MAKE BIN PACKAGE"
|
||||||
|
|
||||||
OLD_PWD=$PWD
|
# OLD_PWD=$PWD
|
||||||
cd dist/
|
# cd dist/
|
||||||
tar --xz -cf pamhyr-gnulinux-amd64.tar.xz pamhyr --checkpoint=.100
|
# tar --xz -cf pamhyr-gnulinux-amd64.tar.xz pamhyr --checkpoint=.100
|
||||||
cd $OLD_PWD
|
# cd $OLD_PWD
|
||||||
|
|
||||||
mv dist/pamhyr-gnulinux-amd64.tar.xz ./
|
# mv dist/pamhyr-gnulinux-amd64.tar.xz ./
|
||||||
|
|
||||||
echo " *** DONE"
|
echo " *** DONE"
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
rem windows.bat -- Pamhyr Windows batch for windows version building
|
||||||
|
rem Copyright (C) 2023 INRAE
|
||||||
|
rem
|
||||||
|
rem This program is free software: you can redistribute it and/or modify
|
||||||
|
rem it under the terms of the GNU General Public License as published by
|
||||||
|
rem the Free Software Foundation, either version 3 of the License, or
|
||||||
|
rem (at your option) any later version.
|
||||||
|
rem
|
||||||
|
rem This program is distributed in the hope that it will be useful,
|
||||||
|
rem but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
rem GNU General Public License for more details.
|
||||||
|
rem
|
||||||
|
rem You should have received a copy of the GNU General Public License
|
||||||
|
rem along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
@ECHO ON
|
||||||
|
|
||||||
|
mkdir pamhyr\pamhyr\_internal
|
||||||
|
xcopy /s /e /y dist\pamhyr pamhyr\pamhyr
|
||||||
|
|
||||||
|
rem Copy data
|
||||||
|
mkdir pamhyr\pamhyr\_internal\lang
|
||||||
|
mkdir pamhyr\pamhyr\_internal\View\ui\ressources
|
||||||
|
mkdir pamhyr\pamhyr\_internal\View\ui\Widgets
|
||||||
|
|
||||||
|
rem UI
|
||||||
|
copy /y ..\src\View\ui\ressources\ pamhyr\pamhyr\_internal\View\ui\ressources
|
||||||
|
copy /y ..\src\View\ui\Widgets\*.ui pamhyr\pamhyr\_internal\View\ui\Widgets
|
||||||
|
copy /y ..\src\View\ui\*.ui pamhyr\pamhyr\_internal\View\ui\
|
||||||
|
|
||||||
|
rem Lang
|
||||||
|
copy /y ..\src\lang\*.qm pamhyr\pamhyr\_internal\lang\
|
||||||
|
|
||||||
|
rem Information
|
||||||
|
copy /y ..\VERSION pamhyr\pamhyr\_internal
|
||||||
|
copy /y ..\AUTHORS pamhyr\pamhyr\_internal
|
||||||
|
copy /y ..\LICENSE pamhyr\pamhyr\_internal
|
||||||
|
copy /y ..\src\motd.txt pamhyr\pamhyr\_internal
|
||||||
|
|
||||||
|
rem MAGE
|
||||||
|
mkdir pamhyr\mage
|
||||||
|
copy /y ..\mage-windows\mage.exe pamhyr\mage\
|
||||||
|
copy /y ..\mage-windows\mage_extraire.exe pamhyr\mage\
|
||||||
|
copy /y ..\mage-windows\mailleurPF.exe pamhyr\mage\
|
||||||
|
|
||||||
|
rem Copy tests_cases
|
||||||
|
mkdir pamhyr\tests_cases
|
||||||
|
mkdir pamhyr\tests_cases\Saar
|
||||||
|
copy /y ..\tests_cases\Saar\Saar.pamhyr pamhyr\tests_cases\Saar\
|
||||||
|
|
||||||
|
rem Documentations
|
||||||
|
mkdir pamhyr\doc
|
||||||
|
mkdir pamhyr\doc\images
|
||||||
|
copy /y ..\doc\users\documentation.pdf pamhyr\doc\Pamhyr2-users.pdf
|
||||||
|
copy /y ..\doc\dev\documentation.pdf pamhyr\doc\Pamhyr2-dev.pdf
|
||||||
|
copy /y ..\doc\users\documentation.html pamhyr\doc\Pamhyr2-users.html
|
||||||
|
copy /y ..\doc\dev\documentation.html pamhyr\doc\Pamhyr2-dev.html
|
||||||
|
copy /y ..\doc\users\images\* pamhyr\doc\images
|
||||||
|
copy /y ..\doc\dev\images\* pamhyr\doc\images
|
||||||
|
copy /y ..\doc\images\* pamhyr\doc\images
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
rem windows.bat -- Pamhyr Windows batch for windows version building
|
||||||
|
rem Copyright (C) 2023 INRAE
|
||||||
|
rem
|
||||||
|
rem This program is free software: you can redistribute it and/or modify
|
||||||
|
rem it under the terms of the GNU General Public License as published by
|
||||||
|
rem the Free Software Foundation, either version 3 of the License, or
|
||||||
|
rem (at your option) any later version.
|
||||||
|
rem
|
||||||
|
rem This program is distributed in the hope that it will be useful,
|
||||||
|
rem but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
rem GNU General Public License for more details.
|
||||||
|
rem
|
||||||
|
rem You should have received a copy of the GNU General Public License
|
||||||
|
rem along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
@ECHO ON
|
||||||
|
|
||||||
|
rem Make installer
|
||||||
|
"C:\Program Files (x86)\NSIS\makensis.exe" pamhyr.nsi
|
||||||
+23
-19
@@ -3,17 +3,17 @@
|
|||||||
!define LIC_NAME "LICENSE"
|
!define LIC_NAME "LICENSE"
|
||||||
!define APP_NAME "PAMHYR"
|
!define APP_NAME "PAMHYR"
|
||||||
|
|
||||||
Name "PAMHYR"
|
Name "Pamhyr2"
|
||||||
OutFile "pamhyr-win-amd64.exe"
|
OutFile "pamhyr-windows.exe"
|
||||||
LicenseData "..\LICENSE"
|
LicenseData "pamhyr\pamhyr\_internal\LICENSE"
|
||||||
LicenseText "I Agree"
|
LicenseText "I Agree"
|
||||||
|
|
||||||
RequestExecutionLevel admin
|
RequestExecutionLevel admin
|
||||||
|
|
||||||
Unicode True
|
Unicode True
|
||||||
InstallDir $PROGRAMFILES\PAMHYR
|
InstallDir $PROGRAMFILES\Pamhyr2
|
||||||
|
|
||||||
InstallDirRegKey HKLM "Software\PAMHYR" "Install_Dir"
|
InstallDirRegKey HKLM "Software\Pamhyr2" "Install_Dir"
|
||||||
|
|
||||||
Page license
|
Page license
|
||||||
Page components
|
Page components
|
||||||
@@ -23,35 +23,39 @@ Page instfiles
|
|||||||
UninstPage uninstConfirm
|
UninstPage uninstConfirm
|
||||||
UninstPage instfiles
|
UninstPage instfiles
|
||||||
|
|
||||||
Section "PAMHYR"
|
Section "Pamhyr2"
|
||||||
SectionIn RO
|
SectionIn RO
|
||||||
|
|
||||||
SetOutPath $INSTDIR
|
SetOutPath $INSTDIR
|
||||||
|
|
||||||
File /r "dist\pamhyr\*"
|
File /r "pamhyr\*"
|
||||||
|
|
||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "DisplayName" "NSIS PAMHYR"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "DisplayName" "NSIS Pamhyr2"
|
||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "UninstallString" "$INSTDIR\uninstall.exe"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "NoModify" 1
|
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "NoModify" 1
|
||||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR" "NoRepair" 1
|
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2" "NoRepair" 1
|
||||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Start Menu Shortcuts"
|
Section "Start Menu Shortcuts"
|
||||||
|
CreateDirectory "$SMPROGRAMS\Pamhyr2"
|
||||||
|
CreateShortcut "$SMPROGRAMS\Pamhyr2\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
||||||
|
CreateShortcut "$SMPROGRAMS\Pamhyr2\Pamhyr2.lnk" "$INSTDIR\pamhyr\pamhyr.exe"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
CreateDirectory "$SMPROGRAMS\PAMHYR"
|
Section "Desktop Shortcuts"
|
||||||
CreateShortcut "$SMPROGRAMS\PAMHYR\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
SetShellVarContext all
|
||||||
CreateShortcut "$SMPROGRAMS\PAMHYR\PAMHYR.lnk" "$INSTDIR\pamhyr.exe"
|
CreateShortcut "$desktop\Pamhyr2.lnk" "$instdir\pamhyr\pamhyr.exe"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Uninstall"
|
Section "Uninstall"
|
||||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\PAMHYR"
|
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pamhyr2"
|
||||||
DeleteRegKey HKLM SOFTWARE\NSIS_PAMHYR
|
DeleteRegKey HKLM SOFTWARE\NSIS_Pamhyr2
|
||||||
|
|
||||||
Delete "$SMPROGRAMS\PAMHYR\*.lnk"
|
Delete "$SMPROGRAMS\Pamhyr2\*.lnk"
|
||||||
|
Delete "$desktop\Pamhyr2.lnk"
|
||||||
|
|
||||||
RMDir "$SMPROGRAMS\PAMHYR"
|
RMDir "$SMPROGRAMS\Pamhyr2"
|
||||||
RMDir /R "$INSTDIR"
|
RMDir /R "$INSTDIR"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
+45
-16
@@ -81,13 +81,42 @@ wine pyinstaller ../src/pamhyr.py -y
|
|||||||
|
|
||||||
echo " *** COPY DATA"
|
echo " *** COPY DATA"
|
||||||
|
|
||||||
mkdir -p dist/pamhyr/View/ui
|
mkdir -p pamhyr
|
||||||
cp -r ../src/View/ui/ressources/ dist/pamhyr/View/ui/
|
mkdir -p pamhyr/pamhyr
|
||||||
cp -r ../src/View/ui/Widgets/*.ui dist/pamhyr/View/ui/
|
|
||||||
cp -r ../src/View/ui/*.ui dist/pamhyr/View/ui/
|
|
||||||
|
|
||||||
cp ../VERSION dist/pamhyr/
|
# Copy Pamhyr info
|
||||||
cp ../AUTHORS dist/pamhyr/
|
cp -v ../VERSION pamhyr/pamhyr/
|
||||||
|
cp -v ../AUTHORS pamhyr/pamhyr/
|
||||||
|
cp -v ../LICENSE pamhyr/pamhyr/
|
||||||
|
|
||||||
|
# Copy mage
|
||||||
|
mkdir -p pamhyr/mage
|
||||||
|
cp -v ../mage/* pamhyr/mage/
|
||||||
|
|
||||||
|
# Copy Pamhyr
|
||||||
|
cp -r dist/pamhyr pamhyr/
|
||||||
|
|
||||||
|
# Copy Pamhyr resources
|
||||||
|
mkdir -p pamhyr/pamhyr/View
|
||||||
|
mkdir -p pamhyr/pamhyr/View/ui
|
||||||
|
mkdir -p pamhyr/pamhyr/View/ui/Widgets
|
||||||
|
cp -r ../src/View/ui/*.ui pamhyr/pamhyr/View/ui/
|
||||||
|
cp -r ../src/View/ui/ressources/ pamhyr/pamhyr/View/ui
|
||||||
|
cp -r ../src/View/ui/Widgets/*.ui pamhyr/pamhyr/View/ui/Widgets
|
||||||
|
|
||||||
|
# Copy lang
|
||||||
|
mkdir -p pamhyr/pamhyr/lang
|
||||||
|
cp -r ../src/lang/*.qm pamhyr/pamhyr/lang
|
||||||
|
|
||||||
|
# Copy tests cases
|
||||||
|
mkdir -p pamhyr/tests_cases/
|
||||||
|
mkdir -p pamhyr/tests_cases/Saar
|
||||||
|
cp ../tests_cases/Saar/Saar.pamhyr pamhyr/tests_cases/Saar/
|
||||||
|
|
||||||
|
# Copy documentations
|
||||||
|
mkdir -p pamhyr/doc/
|
||||||
|
cp ../doc/users/documentation.pdf pamhyr/doc/Pamhyr2-users.pdf
|
||||||
|
cp ../doc/dev/documentation.pdf pamhyr/doc/Pamhyr2-dev.pdf
|
||||||
|
|
||||||
# Update TS and build QM files
|
# Update TS and build QM files
|
||||||
OLD_PWD=$PWD
|
OLD_PWD=$PWD
|
||||||
@@ -102,19 +131,19 @@ echo " *** MAKE PACKAGES"
|
|||||||
|
|
||||||
echo " TAR pamhyr-win-amd64.tar.xz"
|
echo " TAR pamhyr-win-amd64.tar.xz"
|
||||||
|
|
||||||
OLD_PWD=$PWD
|
# OLD_PWD=$PWD
|
||||||
cd dist/
|
# cd dist/
|
||||||
tar --xz -cf pamhyr-win-amd64.tar.xz pamhyr --checkpoint=.100
|
# tar --xz -cf pamhyr-win-amd64.tar.xz pamhyr --checkpoint=.100
|
||||||
cd $OLD_PWD
|
# cd $OLD_PWD
|
||||||
mv dist/pamhyr-win-amd64.tar.xz ./
|
# mv dist/pamhyr-win-amd64.tar.xz ./
|
||||||
|
|
||||||
echo " ZIP pamhyr-win-amd64.zip"
|
echo " ZIP pamhyr-win-amd64.zip"
|
||||||
|
|
||||||
OLD_PWD=$PWD
|
# OLD_PWD=$PWD
|
||||||
cd dist/
|
# cd dist/
|
||||||
zip -r pamhyr-win-amd64.zip pamhyr/
|
# zip -r pamhyr-win-amd64.zip pamhyr/
|
||||||
cd $OLD_PWD
|
# cd $OLD_PWD
|
||||||
mv dist/pamhyr-win-amd64.zip ./
|
# mv dist/pamhyr-win-amd64.zip ./
|
||||||
|
|
||||||
echo " *** MAKE INSTALLER"
|
echo " *** MAKE INSTALLER"
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,8 @@
|
|||||||
PyQt5==5.15.4
|
PyQt5==5.15.4
|
||||||
PyQt5-Qt5==5.15.2
|
PyQt5-Qt5==5.15.2
|
||||||
PyQt5-sip==12.8.1
|
PyQt5-sip==12.12.2
|
||||||
|
#PyQtWebEngine==5.15.6
|
||||||
|
QScintilla>=2.14.1
|
||||||
pyqtgraph>=0.12.1
|
pyqtgraph>=0.12.1
|
||||||
matplotlib>=3.4.1
|
matplotlib>=3.4.1
|
||||||
numpy>=1.24.2
|
numpy>=1.24.2
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ from enum import Enum
|
|||||||
|
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
|
||||||
class STATUS(Enum):
|
class STATUS(Enum):
|
||||||
UNKNOWN = -1
|
UNKNOWN = -1
|
||||||
OK = 0
|
OK = 0
|
||||||
WARNING = 1
|
WARNING = 1
|
||||||
ERROR = 2
|
ERROR = 2
|
||||||
|
|
||||||
|
|
||||||
class AbstractModelChecker(object):
|
class AbstractModelChecker(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._name = ""
|
self._name = ""
|
||||||
@@ -62,6 +64,12 @@ class AbstractModelChecker(object):
|
|||||||
|
|
||||||
# Abstract function
|
# Abstract function
|
||||||
|
|
||||||
|
def _run(self, study):
|
||||||
|
from Model.Study import Study
|
||||||
|
|
||||||
|
thread_study = Study.open(study._filename)
|
||||||
|
self.run(thread_study)
|
||||||
|
|
||||||
def run(self, study):
|
def run(self, study):
|
||||||
"""Run checker function
|
"""Run checker function
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -27,8 +27,9 @@ from Checker.Checker import AbstractModelChecker, STATUS
|
|||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class MageNetworkGraphChecker(AbstractModelChecker):
|
class MageNetworkGraphChecker(AbstractModelChecker):
|
||||||
def __init__(self, connectivity = True):
|
def __init__(self, connectivity=True):
|
||||||
super(MageNetworkGraphChecker, self).__init__()
|
super(MageNetworkGraphChecker, self).__init__()
|
||||||
|
|
||||||
self._mode_conn = connectivity
|
self._mode_conn = connectivity
|
||||||
@@ -38,8 +39,10 @@ class MageNetworkGraphChecker(AbstractModelChecker):
|
|||||||
else:
|
else:
|
||||||
mode = "cycle"
|
mode = "cycle"
|
||||||
|
|
||||||
self._name = _translate("Checker", f"Mage network graph {mode} checker")
|
self._name = _translate(
|
||||||
self._description = _translate("Checker", "Check if the network graph is valid")
|
"Checker", f"Mage network graph {mode} checker")
|
||||||
|
self._description = _translate(
|
||||||
|
"Checker", "Check if the network graph is valid")
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def _connectivity(self, summary, status, graph):
|
def _connectivity(self, summary, status, graph):
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ class StudyNetworkReachChecker(AbstractModelChecker):
|
|||||||
super(StudyNetworkReachChecker, self).__init__()
|
super(StudyNetworkReachChecker, self).__init__()
|
||||||
|
|
||||||
self._name = _translate("Checker", "Study network reach checker")
|
self._name = _translate("Checker", "Study network reach checker")
|
||||||
self._description = _translate("Checker", "Check if exists at least one reach for study")
|
self._description = _translate(
|
||||||
|
"Checker", "Check if exists at least one reach for study")
|
||||||
|
|
||||||
def run(self, study):
|
def run(self, study):
|
||||||
if study is None:
|
if study is None:
|
||||||
@@ -54,12 +55,14 @@ class StudyNetworkReachChecker(AbstractModelChecker):
|
|||||||
self._status = STATUS.OK
|
self._status = STATUS.OK
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class StudyGeometryChecker(AbstractModelChecker):
|
class StudyGeometryChecker(AbstractModelChecker):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(StudyGeometryChecker, self).__init__()
|
super(StudyGeometryChecker, self).__init__()
|
||||||
|
|
||||||
self._name = _translate("Checker", "Study geometry checker")
|
self._name = _translate("Checker", "Study geometry checker")
|
||||||
self._description = _translate("Checker", "Check if exists geometry for each reach of study")
|
self._description = _translate(
|
||||||
|
"Checker", "Check if exists geometry for each reach of study")
|
||||||
self._reachs = []
|
self._reachs = []
|
||||||
|
|
||||||
def run(self, study):
|
def run(self, study):
|
||||||
@@ -128,6 +131,7 @@ class DummyWARNING(AbstractModelChecker):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class DummyERROR(AbstractModelChecker):
|
class DummyERROR(AbstractModelChecker):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(DummyERROR, self).__init__()
|
super(DummyERROR, self).__init__()
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
class AbstractModelComponent(object):
|
|
||||||
def __init__(self):
|
|
||||||
super(AbstractModelComponent, self).__init__()
|
|
||||||
|
|
||||||
def new(self, filename):
|
|
||||||
|
|
||||||
|
|
||||||
def export(self, filename):
|
|
||||||
@@ -20,17 +20,18 @@ import logging
|
|||||||
|
|
||||||
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class BoundaryCondition(SQLSubModel):
|
class BoundaryCondition(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, id:int = -1, name:str = "",
|
def __init__(self, id: int = -1, name: str = "",
|
||||||
status = None):
|
status=None):
|
||||||
super(BoundaryCondition, self).__init__()
|
super(BoundaryCondition, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -101,7 +102,7 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
|
||||||
@@ -115,9 +116,9 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
t = row[2]
|
t = row[2]
|
||||||
ctor = cls._get_ctor_from_type(t)
|
ctor = cls._get_ctor_from_type(t)
|
||||||
bc = ctor(
|
bc = ctor(
|
||||||
id = row[0],
|
id=row[0],
|
||||||
name = row[1],
|
name=row[1],
|
||||||
status = data['status']
|
status=data['status']
|
||||||
)
|
)
|
||||||
|
|
||||||
bc.node = None
|
bc.node = None
|
||||||
@@ -143,7 +144,7 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
|
||||||
execute(f"DELETE FROM boundary_condition WHERE id = {self.id}")
|
execute(f"DELETE FROM boundary_condition WHERE id = {self.id}")
|
||||||
@@ -155,7 +156,7 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"boundary_condition(id, name, type, tab, node) "+
|
"boundary_condition(id, name, type, tab, node) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._sql_format(self._name)}', " +
|
f"{self.id}, '{self._sql_format(self._name)}', " +
|
||||||
f"'{self._sql_format(self._type)}', '{tab}', {node}" +
|
f"'{self._sql_format(self._type)}', '{tab}', {node}" +
|
||||||
@@ -170,7 +171,7 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"boundary_condition_data(ind, data0, data1, bc) "+
|
"boundary_condition_data(ind, data0, data1, bc) " +
|
||||||
f"VALUES ({ind}, '{data0}', {data1}, {self.id})"
|
f"VALUES ({ind}, '{data0}', {data1}, {self.id})"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
@@ -187,7 +188,7 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def time_convert(cls, data):
|
def time_convert(cls, data):
|
||||||
if type(data) == str and data.count(":") == 3:
|
if data is str and data.count(":") == 3:
|
||||||
return old_pamhyr_date_to_timestamp(data)
|
return old_pamhyr_date_to_timestamp(data)
|
||||||
|
|
||||||
return int(data)
|
return int(data)
|
||||||
@@ -246,7 +247,7 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
new_1 = self._default_1
|
new_1 = self._default_1
|
||||||
|
|
||||||
if len(header) != 0:
|
if len(header) != 0:
|
||||||
for i in [0,1]:
|
for i in [0, 1]:
|
||||||
for j in range(len(header)):
|
for j in range(len(header)):
|
||||||
if self._header[i] == header[j]:
|
if self._header[i] == header[j]:
|
||||||
if i == 0:
|
if i == 0:
|
||||||
@@ -259,13 +260,13 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
|
|
||||||
return (new_0, new_1)
|
return (new_0, new_1)
|
||||||
|
|
||||||
def add(self, index:int):
|
def add(self, index: int):
|
||||||
value = (self._default_0, self._default_1)
|
value = (self._default_0, self._default_1)
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def insert(self, index:int, value):
|
def insert(self, index: int, value):
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -301,11 +302,10 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
return self.data[index]
|
return self.data[index]
|
||||||
|
|
||||||
def get_range(self, _range):
|
def get_range(self, _range):
|
||||||
l = []
|
lst = []
|
||||||
for r in _range:
|
for r in _range:
|
||||||
l.append(r)
|
lst.append(r)
|
||||||
return l
|
return lst
|
||||||
|
|
||||||
|
|
||||||
def _set_i_c_v(self, index, column, value):
|
def _set_i_c_v(self, index, column, value):
|
||||||
v = list(self._data[index])
|
v = list(self._data[index])
|
||||||
@@ -313,22 +313,22 @@ class BoundaryCondition(SQLSubModel):
|
|||||||
self._data[index] = tuple(v)
|
self._data[index] = tuple(v)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def set_i_0(self, index:int, value):
|
def set_i_0(self, index: int, value):
|
||||||
self._set_i_c_v(index, 0, value)
|
self._set_i_c_v(index, 0, value)
|
||||||
|
|
||||||
def set_i_1(self, index:int, value):
|
def set_i_1(self, index: int, value):
|
||||||
self._set_i_c_v(index, 1, value)
|
self._set_i_c_v(index, 1, value)
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def convert(self, cls):
|
def convert(self, cls):
|
||||||
new = cls(name = self.name, status = self._status)
|
new = cls(name=self.name, status=self._status)
|
||||||
new.node = self.node
|
new.node = self.node
|
||||||
|
|
||||||
for i, _ in enumerate(self.data):
|
for i, _ in enumerate(self.data):
|
||||||
new.add(i)
|
new.add(i)
|
||||||
|
|
||||||
for i in [0,1]:
|
for i in [0, 1]:
|
||||||
for j in [0,1]:
|
for j in [0, 1]:
|
||||||
if self._header[i] == new.header[j]:
|
if self._header[i] == new.header[j]:
|
||||||
for ind, v in self.data:
|
for ind, v in self.data:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrList import PamhyrModelListWithTab
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
||||||
@@ -30,33 +30,16 @@ from Model.BoundaryCondition.BoundaryConditionTypes import (
|
|||||||
Solid,
|
Solid,
|
||||||
)
|
)
|
||||||
|
|
||||||
class BoundaryConditionList(SQLSubModel):
|
|
||||||
|
class BoundaryConditionList(PamhyrModelListWithTab):
|
||||||
|
_tabs_list = ["liquid", "solid", "suspenssion"]
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
BoundaryCondition,
|
BoundaryCondition,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(BoundaryConditionList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._tabs = {
|
|
||||||
"liquid" : [],
|
|
||||||
"solid" : [],
|
|
||||||
"suspenssion" : []
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_load(cls, execute, data=None):
|
||||||
return cls._create_submodel(execute)
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return True
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_load(cls, execute, data = None):
|
|
||||||
new = cls(status = data['status'])
|
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
@@ -69,7 +52,7 @@ class BoundaryConditionList(SQLSubModel):
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
execute("DELETE FROM boundary_condition")
|
execute("DELETE FROM boundary_condition")
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
@@ -78,83 +61,29 @@ class BoundaryConditionList(SQLSubModel):
|
|||||||
for tab in self._tabs:
|
for tab in self._tabs:
|
||||||
data["tab"] = tab
|
data["tab"] = tab
|
||||||
for bc in self._tabs[tab]:
|
for bc in self._tabs[tab]:
|
||||||
bc._sql_save(execute, data = data)
|
bc._sql_save(execute, data=data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def len(self, lst):
|
|
||||||
return len(self._tabs[lst])
|
|
||||||
|
|
||||||
def get_tab(self, lst):
|
|
||||||
return self._tabs[lst].copy()
|
|
||||||
|
|
||||||
def get(self, lst, row):
|
|
||||||
return self._tabs[lst][row]
|
|
||||||
|
|
||||||
def set(self, lst, row, new):
|
|
||||||
self._tabs[lst][row] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, lst, index):
|
def new(self, lst, index):
|
||||||
n = NotDefined(status=self._status)
|
n = NotDefined(status=self._status)
|
||||||
self._tabs[lst].insert(index, n)
|
self._tabs[lst].insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, lst, index, new):
|
|
||||||
self._tabs[lst].insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, lst, bcs):
|
|
||||||
for bc in bcs:
|
|
||||||
self._tabs[lst].remove(bc)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, lst, indexes):
|
|
||||||
bcs = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._tabs[lst])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(lst, bcs)
|
|
||||||
|
|
||||||
def sort(self, lst, reverse=False, key=None):
|
|
||||||
self._tabs[lst].sort(reverse=reverse, key=key)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_up(self, lst, index):
|
|
||||||
if index < len(self._tabs[lst]):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, lst, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def __copy__(self):
|
def __copy__(self):
|
||||||
new = BoundaryConditionList()
|
new = BoundaryConditionList()
|
||||||
|
|
||||||
for l in self._tabs:
|
for lst in self._tabs:
|
||||||
new.tabs[l] = self._tabs[l].copy()
|
new.tabs[lst] = self._tabs[lst].copy()
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def __deepcopy__(self):
|
def __deepcopy__(self):
|
||||||
new = BoundaryConditionList()
|
new = BoundaryConditionList()
|
||||||
|
|
||||||
for l in self._tabs:
|
for lst in self._tabs:
|
||||||
new.tabs[l] = self._tabs[l].deepcopy()
|
new.tabs[lst] = self._tabs[lst].deepcopy()
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
|||||||
|
|
||||||
|
|
||||||
class NotDefined(BoundaryCondition):
|
class NotDefined(BoundaryCondition):
|
||||||
def __init__(self, id:int = -1, name:str = "", status = None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(NotDefined, self).__init__(id=id, name=name, status=status)
|
super(NotDefined, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "ND"
|
self._type = "ND"
|
||||||
@@ -32,9 +32,11 @@ class NotDefined(BoundaryCondition):
|
|||||||
def _default_0(self):
|
def _default_0(self):
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
class PonctualContribution(BoundaryCondition):
|
class PonctualContribution(BoundaryCondition):
|
||||||
def __init__(self, id:int = -1, name:str = "", status = None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(PonctualContribution, self).__init__(id=id, name=name, status=status)
|
super(PonctualContribution, self).__init__(
|
||||||
|
id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "PC"
|
self._type = "PC"
|
||||||
self._header = ["time", "discharge"]
|
self._header = ["time", "discharge"]
|
||||||
@@ -44,8 +46,9 @@ class PonctualContribution(BoundaryCondition):
|
|||||||
def compatibility(cls):
|
def compatibility(cls):
|
||||||
return ["liquid"]
|
return ["liquid"]
|
||||||
|
|
||||||
|
|
||||||
class TimeOverZ(BoundaryCondition):
|
class TimeOverZ(BoundaryCondition):
|
||||||
def __init__(self, id:int = -1, name:str = "", status = None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(TimeOverZ, self).__init__(id=id, name=name, status=status)
|
super(TimeOverZ, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "TZ"
|
self._type = "TZ"
|
||||||
@@ -56,9 +59,11 @@ class TimeOverZ(BoundaryCondition):
|
|||||||
def compatibility(cls):
|
def compatibility(cls):
|
||||||
return ["liquid"]
|
return ["liquid"]
|
||||||
|
|
||||||
|
|
||||||
class TimeOverDischarge(BoundaryCondition):
|
class TimeOverDischarge(BoundaryCondition):
|
||||||
def __init__(self, id:int = -1, name:str = "", status = None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(TimeOverDischarge, self).__init__(id=id, name=name, status=status)
|
super(TimeOverDischarge, self).__init__(
|
||||||
|
id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "TD"
|
self._type = "TD"
|
||||||
self._header = ["time", "discharge"]
|
self._header = ["time", "discharge"]
|
||||||
@@ -68,8 +73,9 @@ class TimeOverDischarge(BoundaryCondition):
|
|||||||
def compatibility(cls):
|
def compatibility(cls):
|
||||||
return ["liquid"]
|
return ["liquid"]
|
||||||
|
|
||||||
|
|
||||||
class ZOverDischarge(BoundaryCondition):
|
class ZOverDischarge(BoundaryCondition):
|
||||||
def __init__(self, id:int = -1, name:str = "", status = None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(ZOverDischarge, self).__init__(id=id, name=name, status=status)
|
super(ZOverDischarge, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "ZD"
|
self._type = "ZD"
|
||||||
@@ -86,7 +92,7 @@ class ZOverDischarge(BoundaryCondition):
|
|||||||
|
|
||||||
|
|
||||||
class Solid(BoundaryCondition):
|
class Solid(BoundaryCondition):
|
||||||
def __init__(self, id:int = -1, name:str = "", status = None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(Solid, self).__init__(id=id, name=name, status=status)
|
super(Solid, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self.d50 = 0.002
|
self.d50 = 0.002
|
||||||
|
|||||||
+11
-5
@@ -45,8 +45,9 @@ def exception_message_box(exception):
|
|||||||
# Custom error #
|
# Custom error #
|
||||||
################
|
################
|
||||||
|
|
||||||
|
|
||||||
class ExeceptionWithMessageBox(Exception):
|
class ExeceptionWithMessageBox(Exception):
|
||||||
def __init__(self, title = "Exeception"):
|
def __init__(self, title="Exeception"):
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
def header(self):
|
def header(self):
|
||||||
@@ -72,7 +73,7 @@ class ExeceptionWithMessageBox(Exception):
|
|||||||
class NotImplementedMethodeError(ExeceptionWithMessageBox):
|
class NotImplementedMethodeError(ExeceptionWithMessageBox):
|
||||||
def __init__(self, obj, func):
|
def __init__(self, obj, func):
|
||||||
super(NotImplementedMethodeError, self).__init__(
|
super(NotImplementedMethodeError, self).__init__(
|
||||||
title = _translate("Exception", "Method not implemented")
|
title=_translate("Exception", "Method not implemented")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
@@ -81,12 +82,16 @@ class NotImplementedMethodeError(ExeceptionWithMessageBox):
|
|||||||
self.alert()
|
self.alert()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
class_type = self.obj
|
||||||
|
if self.obj.__class__ != type:
|
||||||
|
class_type = self.obj.__class__
|
||||||
|
|
||||||
return (
|
return (
|
||||||
_translate("Exception", "Method") +
|
_translate("Exception", "Method") +
|
||||||
f" '{self.func.__name__}' " +
|
f" '{self.func.__name__}' " +
|
||||||
_translate("Exception", "not implemented") +
|
_translate("Exception", "not implemented") +
|
||||||
_translate("Exception", "for class") +
|
_translate("Exception", "for class") +
|
||||||
f" '{self.obj.__class__ if self.obj.__class__ != type else self.obj}'"
|
f" '{class_type}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
def header(self):
|
def header(self):
|
||||||
@@ -104,10 +109,11 @@ class NotImplementedMethodeError(ExeceptionWithMessageBox):
|
|||||||
f" '{self.obj.__class__}'"
|
f" '{self.obj.__class__}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FileFormatError(ExeceptionWithMessageBox):
|
class FileFormatError(ExeceptionWithMessageBox):
|
||||||
def __init__(self, filename, reason):
|
def __init__(self, filename, reason):
|
||||||
super(FileFormatError, self).__init__(
|
super(FileFormatError, self).__init__(
|
||||||
title = _translate("Exception", "FileFormatError")
|
title=_translate("Exception", "FileFormatError")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.reason = reason
|
self.reason = reason
|
||||||
@@ -137,7 +143,7 @@ class FileFormatError(ExeceptionWithMessageBox):
|
|||||||
class ClipboardFormatError(ExeceptionWithMessageBox):
|
class ClipboardFormatError(ExeceptionWithMessageBox):
|
||||||
def __init__(self, mime=None, header=None, data=None):
|
def __init__(self, mime=None, header=None, data=None):
|
||||||
super(ClipboardFormatError, self).__init__(
|
super(ClipboardFormatError, self).__init__(
|
||||||
title = _translate("Exception", "Clipboard format error")
|
title=_translate("Exception", "Clipboard format error")
|
||||||
)
|
)
|
||||||
|
|
||||||
self._mime = mime
|
self._mime = mime
|
||||||
|
|||||||
@@ -18,10 +18,11 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
|
|
||||||
class Friction(SQLSubModel):
|
class Friction(SQLSubModel):
|
||||||
def __init__(self, name:str = "", status = None):
|
def __init__(self, name: str = "", status=None):
|
||||||
super(Friction, self).__init__()
|
super(Friction, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -57,7 +58,7 @@ class Friction(SQLSubModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
reach = data["parent"] # Reach object
|
reach = data["parent"] # Reach object
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
@@ -78,22 +79,21 @@ class Friction(SQLSubModel):
|
|||||||
es = next(filter(lambda s: s.id == row[4], stricklers))
|
es = next(filter(lambda s: s.id == row[4], stricklers))
|
||||||
|
|
||||||
# Create friction
|
# Create friction
|
||||||
sec = cls(status = status)
|
sec = cls(status=status)
|
||||||
sec.edge = reach
|
sec.edge = reach
|
||||||
sec.begin_kp = row[1]
|
sec.begin_kp = row[1]
|
||||||
sec.end_kp = row[2]
|
sec.end_kp = row[2]
|
||||||
sec.begin_strickler = bs
|
sec.begin_strickler = bs
|
||||||
sec.end_strickler = es
|
sec.end_strickler = es
|
||||||
|
|
||||||
new[ind] = sec
|
yield ind, sec
|
||||||
|
|
||||||
return new
|
def _sql_save(self, execute, data=None):
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
execute(
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"friction(ind, begin_kp, end_kp, reach, begin_strickler, end_strickler) " +
|
"friction(ind, begin_kp, end_kp, " +
|
||||||
|
"reach, begin_strickler, end_strickler) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{ind}, {self._begin_kp}, {self._end_kp}, " +
|
f"{ind}, {self._begin_kp}, {self._end_kp}, " +
|
||||||
f"{self._edge.id}, " +
|
f"{self._edge.id}, " +
|
||||||
@@ -121,7 +121,7 @@ class Friction(SQLSubModel):
|
|||||||
self._edge = edge
|
self._edge = edge
|
||||||
if (edge is not None and
|
if (edge is not None and
|
||||||
self._begin_kp == 0.0 and
|
self._begin_kp == 0.0 and
|
||||||
self._end_kp == 0.0):
|
self._end_kp == 0.0):
|
||||||
self._begin_kp = self._edge.reach.get_kp_min()
|
self._begin_kp = self._edge.reach.get_kp_min()
|
||||||
self._end_kp = self._edge.reach.get_kp_max()
|
self._end_kp = self._edge.reach.get_kp_max()
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|||||||
@@ -21,26 +21,19 @@ import logging
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
|
||||||
from Model.Friction.Friction import Friction
|
from Model.Friction.Friction import Friction
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class FrictionList(SQLSubModel):
|
|
||||||
|
class FrictionList(PamhyrModelList):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
Friction
|
Friction
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(FrictionList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
self._frictions = []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_create(cls, execute):
|
|
||||||
return cls._create_submodel(execute)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_update_0_0_1(cls, execute, version):
|
def _sql_update_0_0_1(cls, execute, version):
|
||||||
execute("ALTER TABLE `section` RENAME TO `friction`")
|
execute("ALTER TABLE `section` RENAME TO `friction`")
|
||||||
@@ -54,85 +47,54 @@ class FrictionList(SQLSubModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = cls(status = data['status'])
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
new._frictions = Friction._sql_load(
|
new._lst = Friction._sql_load(
|
||||||
execute, data
|
execute, data
|
||||||
)
|
)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
reach = data["reach"]
|
reach = data["reach"]
|
||||||
execute(f"DELETE FROM friction WHERE reach = {reach.id}")
|
execute(f"DELETE FROM friction WHERE reach = {reach.id}")
|
||||||
|
|
||||||
ok = True
|
ok = True
|
||||||
ind = 0
|
ind = 0
|
||||||
for friction in self._frictions:
|
for friction in self._lst:
|
||||||
data["ind"] = ind
|
data["ind"] = ind
|
||||||
ok &= friction._sql_save(execute, data = data)
|
ok &= friction._sql_save(execute, data=data)
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def __len__(self):
|
def _get_frictions_list(self):
|
||||||
return len(self._frictions)
|
# Frictions list generator is type (int, Point) with the first
|
||||||
|
# element the index of the Point in list
|
||||||
@property
|
return list(
|
||||||
def frictions(self):
|
|
||||||
return self._frictions.copy()
|
|
||||||
|
|
||||||
def get(self, row):
|
|
||||||
return self._frictions[row]
|
|
||||||
|
|
||||||
def set(self, row, new):
|
|
||||||
self._frictions[row] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, index):
|
|
||||||
n = Friction(status = self._status)
|
|
||||||
self._frictions.insert(index, n)
|
|
||||||
self._status.modified()
|
|
||||||
return n
|
|
||||||
|
|
||||||
def insert(self, index, new):
|
|
||||||
self._frictions.insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, frictions):
|
|
||||||
for friction in frictions:
|
|
||||||
self._frictions.remove(friction)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
frictions = list(
|
|
||||||
map(
|
map(
|
||||||
lambda x: x[1],
|
lambda p: p[1],
|
||||||
filter(
|
sorted(
|
||||||
lambda x: x[0] in indexes,
|
self._lst,
|
||||||
enumerate(self._frictions)
|
key=lambda p: p[0]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.delete(frictions)
|
|
||||||
|
|
||||||
def sort(self, reverse=False, key=None):
|
@property
|
||||||
self._frictions.sort(reverse=reverse, key=key)
|
def lst(self):
|
||||||
|
if not isinstance(self._lst, list):
|
||||||
|
self._lst = self._get_frictions_list()
|
||||||
|
|
||||||
|
return self._lst
|
||||||
|
|
||||||
|
@property
|
||||||
|
def frictions(self):
|
||||||
|
return self.lst
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
n = Friction(status=self._status)
|
||||||
|
self._lst.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
return n
|
||||||
def move_up(self, index):
|
|
||||||
if index < len(self._frictions):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._frictions
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._frictions
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
@@ -18,8 +18,9 @@
|
|||||||
|
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
|
||||||
class Point(object):
|
class Point(object):
|
||||||
def __init__(self, name:str = "", profile=None, status = None):
|
def __init__(self, name: str = "", profile=None, status=None):
|
||||||
super(Point, self).__init__()
|
super(Point, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -28,7 +29,6 @@ class Point(object):
|
|||||||
self._profile = profile
|
self._profile = profile
|
||||||
self._sl = None
|
self._sl = None
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sl(self):
|
def sl(self):
|
||||||
if self._sl is None:
|
if self._sl is None:
|
||||||
@@ -40,8 +40,8 @@ class Point(object):
|
|||||||
def sl(self, sl):
|
def sl(self, sl):
|
||||||
if sl == self._profile.sl:
|
if sl == self._profile.sl:
|
||||||
self._sl = None
|
self._sl = None
|
||||||
|
else:
|
||||||
self._sl = sl
|
self._sl = sl
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ from math import dist
|
|||||||
|
|
||||||
from Model.Geometry.Point import Point
|
from Model.Geometry.Point import Point
|
||||||
|
|
||||||
|
|
||||||
class PointAC(Point):
|
class PointAC(Point):
|
||||||
def __init__(self, a:float = 0.0, c:float = 0.0,
|
def __init__(self, a: float = 0.0, c: float = 0.0,
|
||||||
name: str = "", status = None):
|
name: str = "", status=None):
|
||||||
super(PointXY, self).__init__(name = name, status = status)
|
super(PointXY, self).__init__(name=name, status=status)
|
||||||
|
|
||||||
self._a = float(a)
|
self._a = float(a)
|
||||||
self._c = float(c)
|
self._c = float(c)
|
||||||
|
|||||||
@@ -19,15 +19,17 @@
|
|||||||
from math import dist
|
from math import dist
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Geometry.Point import Point
|
from Model.Geometry.Point import Point
|
||||||
|
|
||||||
|
|
||||||
class PointXYZ(Point, SQLSubModel):
|
class PointXYZ(Point, SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
|
|
||||||
def __init__(self, x:float = 0.0, y:float = 0.0, z:float = 0.0,
|
def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0,
|
||||||
name:str = "", profile = None, status = None):
|
name: str = "", profile=None, status=None):
|
||||||
super(PointXYZ, self).__init__(name=name, profile=profile, status=status)
|
super(PointXYZ, self).__init__(
|
||||||
|
name=name, profile=profile, status=status)
|
||||||
|
|
||||||
self._x = float(x)
|
self._x = float(x)
|
||||||
self._y = float(y)
|
self._y = float(y)
|
||||||
@@ -69,9 +71,7 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
points = []
|
|
||||||
|
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
profile = data["profile"]
|
profile = data["profile"]
|
||||||
|
|
||||||
@@ -81,10 +81,6 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
f"WHERE profile = {profile.id}"
|
f"WHERE profile = {profile.id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create points list
|
|
||||||
for _ in table:
|
|
||||||
points.append(None)
|
|
||||||
|
|
||||||
# Fill points list with new point
|
# Fill points list with new point
|
||||||
for row in table:
|
for row in table:
|
||||||
ind = row[0]
|
ind = row[0]
|
||||||
@@ -95,13 +91,13 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
sl = row[5]
|
sl = row[5]
|
||||||
|
|
||||||
new = cls(
|
new = cls(
|
||||||
name = name,
|
name=name,
|
||||||
x = x, y = y, z = z,
|
x=x, y=y, z=z,
|
||||||
profile = profile,
|
profile=profile,
|
||||||
status = status
|
status=status
|
||||||
)
|
)
|
||||||
|
|
||||||
if sl == -1 or sl == None:
|
if sl == -1 or sl is None:
|
||||||
new._sl = None
|
new._sl = None
|
||||||
else:
|
else:
|
||||||
new._sl = next(
|
new._sl = next(
|
||||||
@@ -111,11 +107,9 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
points[ind] = new
|
yield ind, new
|
||||||
|
|
||||||
return points
|
def _sql_save(self, execute, data=None):
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
|
||||||
profile = data["profile"]
|
profile = data["profile"]
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
@@ -123,7 +117,7 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT OR REPLACE INTO " +
|
"INSERT OR REPLACE INTO " +
|
||||||
"geometry_pointXYZ(ind, name, x, y, z, profile, sl) "+
|
"geometry_pointXYZ(ind, name, x, y, z, profile, sl) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{ind}, '{self._sql_format(self._name)}', " +
|
f"{ind}, '{self._sql_format(self._name)}', " +
|
||||||
f"{self.x}, {self.y}, {self.z}, " +
|
f"{self.x}, {self.y}, {self.z}, " +
|
||||||
@@ -134,7 +128,6 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data(cls, header, data):
|
def from_data(cls, header, data):
|
||||||
point = None
|
point = None
|
||||||
@@ -157,7 +150,6 @@ class PointXYZ(Point, SQLSubModel):
|
|||||||
|
|
||||||
return point
|
return point
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"({self._x}, {self._y}, {self._z}, {self._name})"
|
return f"({self._x}, {self._y}, {self._z}, {self._name})"
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,15 @@ from Model.Except import NotImplementedMethodeError
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Profile(object):
|
class Profile(object):
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, id:int = -1, num:int = 0,
|
def __init__(self, id: int = -1, num: int = 0,
|
||||||
kp:float = 0.0, name:str = "",
|
kp: float = 0.0, name: str = "",
|
||||||
code1:int = 0, code2:int = 0,
|
code1: int = 0, code2: int = 0,
|
||||||
_type:str = "", reach = None,
|
_type: str = "", reach=None,
|
||||||
status = None):
|
status=None):
|
||||||
super(Profile, self).__init__()
|
super(Profile, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -56,16 +57,35 @@ class Profile(object):
|
|||||||
|
|
||||||
self._profile_type = _type
|
self._profile_type = _type
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.points)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def number_points(self):
|
def number_points(self):
|
||||||
return len(self._points)
|
return len(self.points)
|
||||||
|
|
||||||
|
def _get_points_list(self):
|
||||||
|
# Points list generator is type (int, Point) with the first
|
||||||
|
# element the index of the Point in list
|
||||||
|
return list(
|
||||||
|
map(
|
||||||
|
lambda p: p[1],
|
||||||
|
sorted(
|
||||||
|
self._points,
|
||||||
|
key=lambda p: p[0]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def points(self):
|
def points(self):
|
||||||
return self._points.copy()
|
if not isinstance(self._points, list):
|
||||||
|
self._points = self._get_points_list()
|
||||||
|
|
||||||
|
return self._points
|
||||||
|
|
||||||
def point(self, index):
|
def point(self, index):
|
||||||
return self._points[index]
|
return self.points[index]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reach(self):
|
def reach(self):
|
||||||
@@ -112,7 +132,7 @@ class Profile(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def nb_points(self):
|
def nb_points(self):
|
||||||
return len(self._points)
|
return len(self.points)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def kp(self):
|
def kp(self):
|
||||||
@@ -166,9 +186,9 @@ class Profile(object):
|
|||||||
self._profile_type = value
|
self._profile_type = value
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def point(self, i:int):
|
def point(self, i: int):
|
||||||
if i < len(self._points):
|
if i < len(self.points):
|
||||||
return self._points[i]
|
return self.points[i]
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -178,11 +198,10 @@ class Profile(object):
|
|||||||
Returns:
|
Returns:
|
||||||
The list of named point
|
The list of named point
|
||||||
"""
|
"""
|
||||||
return [point for point in self._points
|
return [point for point in self.points
|
||||||
if point.point_is_named()]
|
if point.point_is_named()]
|
||||||
|
|
||||||
|
def insert_point(self, index: int, point: Point):
|
||||||
def insert_point(self, index: int, point:Point):
|
|
||||||
"""Insert point at index.
|
"""Insert point at index.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -192,10 +211,9 @@ class Profile(object):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self._points.insert(index, point)
|
self.points.insert(index, point)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
def delete(self, indexes: int):
|
def delete(self, indexes: int):
|
||||||
"""Delete points at index
|
"""Delete points at index
|
||||||
|
|
||||||
@@ -215,7 +233,7 @@ class Profile(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self._points = list(
|
self.points = list(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p not in points,
|
lambda p: p not in points,
|
||||||
self.points
|
self.points
|
||||||
@@ -232,7 +250,7 @@ class Profile(object):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self._points = list(
|
self.points = list(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p not in points,
|
lambda p: p not in points,
|
||||||
self.points
|
self.points
|
||||||
@@ -243,10 +261,10 @@ class Profile(object):
|
|||||||
# Move
|
# Move
|
||||||
|
|
||||||
def move_up_point(self, index: int):
|
def move_up_point(self, index: int):
|
||||||
if index < len(self._points):
|
if index < len(self.points):
|
||||||
next = index - 1
|
next = index - 1
|
||||||
|
|
||||||
p = self._points
|
p = self.points
|
||||||
p[index], p[next] = p[next], p[index]
|
p[index], p[next] = p[next], p[index]
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -254,7 +272,7 @@ class Profile(object):
|
|||||||
if index >= 0:
|
if index >= 0:
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
|
|
||||||
p = self._points
|
p = self.points
|
||||||
p[index], p[prev] = p[prev], p[index]
|
p[index], p[prev] = p[prev], p[index]
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -262,14 +280,14 @@ class Profile(object):
|
|||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort(self, column, is_reversed: bool = False):
|
def sort(self, column, is_reversed: bool = False):
|
||||||
predicate = lambda p: p.x
|
def predicate(p): return p.x
|
||||||
if column == 'y':
|
if column == 'y':
|
||||||
predicate = lambda p: p.y
|
def predicate(p): return p.y
|
||||||
elif column == 'z':
|
elif column == 'z':
|
||||||
predicate = lambda p: p.z
|
def predicate(p): return p.z
|
||||||
|
|
||||||
self._points = sorted(
|
self.points = sorted(
|
||||||
self._points,
|
self.points,
|
||||||
key=predicate,
|
key=predicate,
|
||||||
reverse=is_reversed
|
reverse=is_reversed
|
||||||
)
|
)
|
||||||
@@ -277,10 +295,10 @@ class Profile(object):
|
|||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort_with_indexes(self, indexes: list):
|
def sort_with_indexes(self, indexes: list):
|
||||||
if len(self._points) != len(indexes):
|
if len(self.points) != len(indexes):
|
||||||
logger.critical("Indexes list do not correspond to point list")
|
logger.critical("Indexes list do not correspond to point list")
|
||||||
|
|
||||||
self._points = list(
|
self.points = list(
|
||||||
map(
|
map(
|
||||||
lambda x: x[1],
|
lambda x: x[1],
|
||||||
sorted(
|
sorted(
|
||||||
|
|||||||
@@ -16,17 +16,21 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from tools import timer
|
from tools import timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import ClipboardFormatError
|
from Model.Except import ClipboardFormatError
|
||||||
from Model.Geometry.Profile import Profile
|
from Model.Geometry.Profile import Profile
|
||||||
from Model.Geometry.PointXYZ import PointXYZ
|
from Model.Geometry.PointXYZ import PointXYZ
|
||||||
from Model.Geometry.Vector_1d import Vector1d
|
from Model.Geometry.Vector_1d import Vector1d
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class ProfileXYZ(Profile, SQLSubModel):
|
class ProfileXYZ(Profile, SQLSubModel):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
PointXYZ,
|
PointXYZ,
|
||||||
@@ -36,11 +40,11 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
id: int = -1,
|
id: int = -1,
|
||||||
name: str = "",
|
name: str = "",
|
||||||
kp: float = 0.,
|
kp: float = 0.,
|
||||||
reach = None,
|
reach=None,
|
||||||
num = 0,
|
num=0,
|
||||||
nb_point: int = 0,
|
nb_point: int = 0,
|
||||||
code1: int = 0, code2: int = 0,
|
code1: int = 0, code2: int = 0,
|
||||||
status = None):
|
status=None):
|
||||||
"""ProfileXYZ constructor
|
"""ProfileXYZ constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -54,14 +58,14 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
super(ProfileXYZ, self).__init__(
|
super(ProfileXYZ, self).__init__(
|
||||||
id = id,
|
id=id,
|
||||||
num = num,
|
num=num,
|
||||||
name = name,
|
name=name,
|
||||||
kp = kp,
|
kp=kp,
|
||||||
code1 = code1, code2 = code2,
|
code1=code1, code2=code2,
|
||||||
_type = "XYZ",
|
_type="XYZ",
|
||||||
reach = reach,
|
reach=reach,
|
||||||
status = status,
|
status=status,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -100,7 +104,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
profiles = []
|
profiles = []
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
reach = data["reach"]
|
reach = data["reach"]
|
||||||
@@ -108,7 +112,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, ind, name, kp, num, code1, code2, sl " +
|
"SELECT id, ind, name, kp, num, code1, code2, sl " +
|
||||||
"FROM geometry_profileXYZ " +
|
"FROM geometry_profileXYZ " +
|
||||||
f"WHERE reach = {reach}"
|
f"WHERE reach = {reach.id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
for _ in table:
|
for _ in table:
|
||||||
@@ -125,14 +129,14 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
sl = row[7]
|
sl = row[7]
|
||||||
|
|
||||||
new = cls(
|
new = cls(
|
||||||
id=id, num = num,
|
id=id, num=num,
|
||||||
name = name, kp = kp,
|
name=name, kp=kp,
|
||||||
code1 = code1, code2 = code2,
|
code1=code1, code2=code2,
|
||||||
reach = data["parent"],
|
reach=data["parent"],
|
||||||
status = status
|
status=status
|
||||||
)
|
)
|
||||||
|
|
||||||
if sl == -1 or sl == None:
|
if sl == -1 or sl is None:
|
||||||
new._sl = None
|
new._sl = None
|
||||||
else:
|
else:
|
||||||
new._sl = next(
|
new._sl = next(
|
||||||
@@ -143,13 +147,15 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
data["profile"] = new
|
data["profile"] = new
|
||||||
new._points = PointXYZ._sql_load(execute, data)
|
new._points = PointXYZ._sql_load(execute, data.copy())
|
||||||
|
|
||||||
profiles[ind] = new
|
yield ind, new
|
||||||
|
|
||||||
return profiles
|
# profiles[ind] = new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
# return profiles
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data=None):
|
||||||
ok = True
|
ok = True
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
@@ -157,7 +163,8 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT OR REPLACE INTO " +
|
"INSERT OR REPLACE INTO " +
|
||||||
"geometry_profileXYZ(id, ind, name, reach, kp, num, code1, code2, sl) "+
|
"geometry_profileXYZ(id, ind, name, reach, " +
|
||||||
|
"kp, num, code1, code2, sl) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
|
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
|
||||||
f"{self.reach.id}, {self.kp}, {self.num}, " +
|
f"{self.reach.id}, {self.kp}, {self.num}, " +
|
||||||
@@ -170,7 +177,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
execute(f"DELETE FROM geometry_pointXYZ WHERE profile = {self.id}")
|
execute(f"DELETE FROM geometry_pointXYZ WHERE profile = {self.id}")
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for point in self._points:
|
for point in self.points:
|
||||||
data["ind"] = ind
|
data["ind"] = ind
|
||||||
ok &= point._sql_save(execute, data)
|
ok &= point._sql_save(execute, data)
|
||||||
ind += 1
|
ind += 1
|
||||||
@@ -220,18 +227,17 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
|
|
||||||
return point
|
return point
|
||||||
|
|
||||||
|
|
||||||
def x(self):
|
def x(self):
|
||||||
return [point.x for point in self._points]
|
return [point.x for point in self.points]
|
||||||
|
|
||||||
def y(self):
|
def y(self):
|
||||||
return [point.y for point in self._points]
|
return [point.y for point in self.points]
|
||||||
|
|
||||||
def z(self):
|
def z(self):
|
||||||
return [point.z for point in self._points]
|
return [point.z for point in self.points]
|
||||||
|
|
||||||
def names(self):
|
def names(self):
|
||||||
return [point.name for point in self._points]
|
return [point.name for point in self.points]
|
||||||
|
|
||||||
def x_max(self):
|
def x_max(self):
|
||||||
return max(self.filter_isnan(self.x()))
|
return max(self.filter_isnan(self.x()))
|
||||||
@@ -262,7 +268,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
for point in list_points:
|
for point in list_points:
|
||||||
pt = PointXYZ(*point, profile=self, status=self._status)
|
pt = PointXYZ(*point, profile=self, status=self._status)
|
||||||
self._points.append(pt)
|
self.points.append(pt)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def get_point_i(self, index: int) -> PointXYZ:
|
def get_point_i(self, index: int) -> PointXYZ:
|
||||||
@@ -275,7 +281,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
The point.
|
The point.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self._points[index]
|
return self.points[index]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise IndexError(f"Invalid point index: {index}")
|
raise IndexError(f"Invalid point index: {index}")
|
||||||
|
|
||||||
@@ -286,7 +292,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
||||||
self._points.append(point_xyz)
|
self.points.append(point_xyz)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def insert(self, index: int):
|
def insert(self, index: int):
|
||||||
@@ -299,7 +305,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
The new point.
|
The new point.
|
||||||
"""
|
"""
|
||||||
point = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
point = PointXYZ(0., 0., 0., profile=self, status=self._status)
|
||||||
self._points.insert(index, point)
|
self.points.insert(index, point)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return point
|
return point
|
||||||
|
|
||||||
@@ -315,9 +321,9 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
return [x for x in lst if not np.isnan(x)]
|
return [x for x in lst if not np.isnan(x)]
|
||||||
|
|
||||||
def _first_point_not_nan(self):
|
def _first_point_not_nan(self):
|
||||||
first_point = self._points[0]
|
first_point = self.points[0]
|
||||||
|
|
||||||
for point in self._points:
|
for point in self.points:
|
||||||
if not point.is_nan():
|
if not point.is_nan():
|
||||||
first_point = point
|
first_point = point
|
||||||
break
|
break
|
||||||
@@ -325,9 +331,9 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
return first_point
|
return first_point
|
||||||
|
|
||||||
def _last_point_not_nan(self):
|
def _last_point_not_nan(self):
|
||||||
last_point = self._points[-1]
|
last_point = self.points[-1]
|
||||||
|
|
||||||
for point in self._points[::-1]:
|
for point in self.points[::-1]:
|
||||||
if not point.is_nan():
|
if not point.is_nan():
|
||||||
last_point = point
|
last_point = point
|
||||||
break
|
break
|
||||||
@@ -354,13 +360,13 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
first_point_not_nan = self._first_point_not_nan()
|
first_point_not_nan = self._first_point_not_nan()
|
||||||
last_point_not_nan = self._last_point_not_nan()
|
last_point_not_nan = self._last_point_not_nan()
|
||||||
|
|
||||||
for index, point in enumerate(self._points):
|
for index, point in enumerate(self.points):
|
||||||
if point.point_is_named():
|
if point.point_is_named():
|
||||||
index_first_named_point = index
|
index_first_named_point = index
|
||||||
first_named_point = point
|
first_named_point = point
|
||||||
break
|
break
|
||||||
|
|
||||||
for point in reversed(self._points):
|
for point in reversed(self.points):
|
||||||
if point.point_is_named():
|
if point.point_is_named():
|
||||||
last_named_point = point
|
last_named_point = point
|
||||||
break
|
break
|
||||||
@@ -369,32 +375,32 @@ class ProfileXYZ(Profile, SQLSubModel):
|
|||||||
constant = 0.0
|
constant = 0.0
|
||||||
|
|
||||||
if (first_named_point is not None and
|
if (first_named_point is not None and
|
||||||
last_named_point is not None):
|
last_named_point is not None):
|
||||||
if (first_named_point != last_named_point and
|
if (first_named_point != last_named_point and
|
||||||
first_named_point.x != last_named_point.x):
|
first_named_point.x != last_named_point.x):
|
||||||
vector = Vector1d(first_named_point, last_named_point)
|
vector = Vector1d(first_named_point, last_named_point)
|
||||||
normalized_direction_vec = vector.normalized_direction_vector()
|
norm_dir_vec = vector.normalized_direction_vector()
|
||||||
else:
|
else:
|
||||||
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
||||||
normalized_direction_vec = vector.normalized_direction_vector()
|
norm_dir_vec = vector.normalized_direction_vector()
|
||||||
|
|
||||||
for point in self._points:
|
for point in self.points:
|
||||||
xi = point.x - first_named_point.x
|
xi = point.x - first_named_point.x
|
||||||
yi = point.y - first_named_point.y
|
yi = point.y - first_named_point.y
|
||||||
station_i = (normalized_direction_vec[0] * xi +
|
station_i = (norm_dir_vec[0] * xi +
|
||||||
normalized_direction_vec[1] * yi)
|
norm_dir_vec[1] * yi)
|
||||||
station.append(station_i)
|
station.append(station_i)
|
||||||
|
|
||||||
constant = station[index_first_named_point]
|
constant = station[index_first_named_point]
|
||||||
elif first_named_point is None:
|
elif first_named_point is None:
|
||||||
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
||||||
normalized_direction_vec = vector.normalized_direction_vector()
|
norm_dir_vec = vector.normalized_direction_vector()
|
||||||
|
|
||||||
for point in self._points:
|
for point in self.points:
|
||||||
xi = point.x - first_point_not_nan.x
|
xi = point.x - first_point_not_nan.x
|
||||||
yi = point.y - first_point_not_nan.y
|
yi = point.y - first_point_not_nan.y
|
||||||
station_i = (normalized_direction_vec[0] * xi +
|
station_i = (norm_dir_vec[0] * xi +
|
||||||
normalized_direction_vec[1] * yi)
|
norm_dir_vec[1] * yi)
|
||||||
station.append(station_i)
|
station.append(station_i)
|
||||||
|
|
||||||
z_min = self.z_min()
|
z_min = self.z_min()
|
||||||
|
|||||||
+61
-37
@@ -27,7 +27,7 @@ from functools import reduce
|
|||||||
|
|
||||||
from tools import flatten, timer, trace
|
from tools import flatten, timer, trace
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
from Model.Geometry.Profile import Profile
|
from Model.Geometry.Profile import Profile
|
||||||
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
||||||
@@ -36,13 +36,14 @@ from Model.Except import FileFormatError, exception_message_box
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Reach(SQLSubModel):
|
class Reach(SQLSubModel):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
ProfileXYZ,
|
ProfileXYZ,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status=None, parent=None):
|
def __init__(self, status=None, parent=None):
|
||||||
self.id = parent.id
|
self.id = parent.id if parent is not None else 0
|
||||||
self._status = status
|
self._status = status
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self._profiles: List[Profile] = []
|
self._profiles: List[Profile] = []
|
||||||
@@ -59,17 +60,17 @@ class Reach(SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = cls(status = data["status"], parent = data["parent"])
|
new = cls(status=data["status"], parent=data["parent"])
|
||||||
|
|
||||||
new._profiles = ProfileXYZ._sql_load(
|
new._profiles = ProfileXYZ._sql_load(
|
||||||
execute,
|
execute,
|
||||||
data = data
|
data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
# Delete old data
|
# Delete old data
|
||||||
execute(f"DELETE FROM geometry_profileXYZ WHERE reach = {self.id}")
|
execute(f"DELETE FROM geometry_profileXYZ WHERE reach = {self.id}")
|
||||||
# execute(f"DELETE FROM geometry_pointXYZ")
|
# execute(f"DELETE FROM geometry_pointXYZ")
|
||||||
@@ -78,7 +79,7 @@ class Reach(SQLSubModel):
|
|||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for profile in self._profiles:
|
for profile in self.profiles:
|
||||||
data["ind"] = ind
|
data["ind"] = ind
|
||||||
profile._sql_save(execute, data)
|
profile._sql_save(execute, data)
|
||||||
ind += 1
|
ind += 1
|
||||||
@@ -94,26 +95,49 @@ class Reach(SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
The profile at index i
|
The profile at index i
|
||||||
"""
|
"""
|
||||||
if i < len(self._profiles):
|
if i < len(self.profiles):
|
||||||
return self._profiles[i]
|
return self.profiles[i]
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._parent == None:
|
if self._parent is None:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
return self._parent.name
|
return self._parent.name
|
||||||
|
|
||||||
|
def _get_profiles_list(self):
|
||||||
|
# Profiles list generator is type (int, Point) with the first
|
||||||
|
# element the index of the Point in list
|
||||||
|
logger.info(f"Load profiles from reach {self.name}")
|
||||||
|
return list(
|
||||||
|
map(
|
||||||
|
lambda p: p[1],
|
||||||
|
sorted(
|
||||||
|
self._profiles,
|
||||||
|
key=lambda p: p[0]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
if not isinstance(self._profiles, list):
|
||||||
|
self._profiles = self._get_profiles_list()
|
||||||
|
|
||||||
|
return len(self._profiles)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def profiles(self):
|
def profiles(self):
|
||||||
return self._profiles.copy()
|
if not isinstance(self._profiles, list):
|
||||||
|
self._profiles = self._get_profiles_list()
|
||||||
|
|
||||||
|
return self._profiles
|
||||||
|
|
||||||
def get_profiles_from_kp(self, kp):
|
def get_profiles_from_kp(self, kp):
|
||||||
return list(
|
return list(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p.kp == kp, self._profiles
|
lambda p: p.kp == kp, self.profiles
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -123,14 +147,14 @@ class Reach(SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Number of profiles
|
Number of profiles
|
||||||
"""
|
"""
|
||||||
return len(self._profiles)
|
return len(self.profiles)
|
||||||
|
|
||||||
def get_geometry(self) -> List[Profile]:
|
def get_geometry(self) -> List[Profile]:
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
The profiles list.
|
The profiles list.
|
||||||
"""
|
"""
|
||||||
return self._profiles
|
return self.profiles
|
||||||
|
|
||||||
def _update_profile_numbers(self):
|
def _update_profile_numbers(self):
|
||||||
"""Update profiles index
|
"""Update profiles index
|
||||||
@@ -152,7 +176,7 @@ class Reach(SQLSubModel):
|
|||||||
"""
|
"""
|
||||||
profile = ProfileXYZ(reach=self, status=self._status)
|
profile = ProfileXYZ(reach=self, status=self._status)
|
||||||
|
|
||||||
self._profiles.insert(index, profile)
|
self.profiles.insert(index, profile)
|
||||||
self._update_profile_numbers()
|
self._update_profile_numbers()
|
||||||
|
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
@@ -168,11 +192,10 @@ class Reach(SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self._profiles.insert(index, profile)
|
self.profiles.insert(index, profile)
|
||||||
self._update_profile_numbers()
|
self._update_profile_numbers()
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
def delete(self, indexes):
|
def delete(self, indexes):
|
||||||
"""Delete some elements in profile list
|
"""Delete some elements in profile list
|
||||||
|
|
||||||
@@ -192,7 +215,7 @@ class Reach(SQLSubModel):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self._profiles = list(
|
self.profiles = list(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p not in profiles,
|
lambda p: p not in profiles,
|
||||||
self.profiles
|
self.profiles
|
||||||
@@ -210,7 +233,7 @@ class Reach(SQLSubModel):
|
|||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
self._profiles = list(
|
self.profiles = list(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p not in profiles,
|
lambda p: p not in profiles,
|
||||||
self.profiles
|
self.profiles
|
||||||
@@ -219,12 +242,11 @@ class Reach(SQLSubModel):
|
|||||||
self._update_profile_numbers()
|
self._update_profile_numbers()
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
def move_up_profile(self, index: int):
|
def move_up_profile(self, index: int):
|
||||||
if index < len(self.profiles):
|
if index < len(self.profiles):
|
||||||
next = index - 1
|
next = index - 1
|
||||||
|
|
||||||
p = self._profiles
|
p = self.profiles
|
||||||
p[index], p[next] = p[next], p[index]
|
p[index], p[next] = p[next], p[index]
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -232,7 +254,7 @@ class Reach(SQLSubModel):
|
|||||||
if index >= 0:
|
if index >= 0:
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
|
|
||||||
p = self._profiles
|
p = self.profiles
|
||||||
p[index], p[prev] = p[prev], p[index]
|
p[index], p[prev] = p[prev], p[index]
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -275,7 +297,6 @@ class Reach(SQLSubModel):
|
|||||||
def get_kp_max(self):
|
def get_kp_max(self):
|
||||||
return max(self.get_kp())
|
return max(self.get_kp())
|
||||||
|
|
||||||
|
|
||||||
# Sediment Layers
|
# Sediment Layers
|
||||||
|
|
||||||
def get_sl(self):
|
def get_sl(self):
|
||||||
@@ -324,12 +345,12 @@ class Reach(SQLSubModel):
|
|||||||
for guide in guide_set:
|
for guide in guide_set:
|
||||||
self._guidelines[guide] = flatten(
|
self._guidelines[guide] = flatten(
|
||||||
map(
|
map(
|
||||||
lambda l: list(
|
lambda lst: list(
|
||||||
# Filter point with name (we assume we have
|
# Filter point with name (we assume we have
|
||||||
# only one point by profile)
|
# only one point by profile)
|
||||||
filter(
|
filter(
|
||||||
lambda p: p.name == guide,
|
lambda p: p.name == guide,
|
||||||
l
|
lst
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
named_points
|
named_points
|
||||||
@@ -344,7 +365,7 @@ class Reach(SQLSubModel):
|
|||||||
Tuple of complete and incomplete guidelines name.
|
Tuple of complete and incomplete guidelines name.
|
||||||
"""
|
"""
|
||||||
# Get all point contains into a guideline
|
# Get all point contains into a guideline
|
||||||
named_points = [profile.named_points() for profile in self._profiles]
|
named_points = [profile.named_points() for profile in self.profiles]
|
||||||
points_name = list(
|
points_name = list(
|
||||||
map(
|
map(
|
||||||
lambda lst: list(map(lambda p: p.name, lst)),
|
lambda lst: list(map(lambda p: p.name, lst)),
|
||||||
@@ -364,7 +385,9 @@ class Reach(SQLSubModel):
|
|||||||
reduce(
|
reduce(
|
||||||
lambda acc, h: acc + h,
|
lambda acc, h: acc + h,
|
||||||
map(
|
map(
|
||||||
lambda l: list(set(l).symmetric_difference(guide_set)),
|
lambda lst: list(
|
||||||
|
set(lst).symmetric_difference(guide_set)
|
||||||
|
),
|
||||||
points_name
|
points_name
|
||||||
),
|
),
|
||||||
[]
|
[]
|
||||||
@@ -414,13 +437,12 @@ class Reach(SQLSubModel):
|
|||||||
def get_guidelines_z(self):
|
def get_guidelines_z(self):
|
||||||
return self._map_guidelines_points(lambda p: p.z)
|
return self._map_guidelines_points(lambda p: p.z)
|
||||||
|
|
||||||
|
|
||||||
# Sort
|
# Sort
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort(self, is_reversed: bool = False):
|
def sort(self, is_reversed: bool = False):
|
||||||
self._profiles = sorted(
|
self.profiles = sorted(
|
||||||
self._profiles,
|
self.profiles,
|
||||||
key=lambda profile: profile.kp,
|
key=lambda profile: profile.kp,
|
||||||
reverse=is_reversed
|
reverse=is_reversed
|
||||||
)
|
)
|
||||||
@@ -428,10 +450,10 @@ class Reach(SQLSubModel):
|
|||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort_with_indexes(self, indexes: list):
|
def sort_with_indexes(self, indexes: list):
|
||||||
if len(self._profiles) != len(indexes):
|
if len(self.profiles) != len(indexes):
|
||||||
logger.critical("Indexes list do not correspond to profile list")
|
logger.critical("Indexes list do not correspond to profile list")
|
||||||
|
|
||||||
self._profiles = list(
|
self.profiles = list(
|
||||||
map(
|
map(
|
||||||
lambda x: x[1],
|
lambda x: x[1],
|
||||||
sorted(
|
sorted(
|
||||||
@@ -449,7 +471,8 @@ class Reach(SQLSubModel):
|
|||||||
"""Import a geometry from file (.ST or .st)
|
"""Import a geometry from file (.ST or .st)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
file_path_name: The absolute path of geometry file (.ST or .st) to import.
|
file_path_name: The absolute path of geometry file (.ST or .st)
|
||||||
|
to import.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Nothing.
|
Nothing.
|
||||||
@@ -459,7 +482,8 @@ class Reach(SQLSubModel):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
list_profile, list_header = self.read_file_st(str(file_path_name))
|
list_profile, list_header = self.read_file_st(str(file_path_name))
|
||||||
profile_header = ["num", "code1", "code2", "nb_point", "kp", "name"]
|
profile_header = ["num", "code1",
|
||||||
|
"code2", "nb_point", "kp", "name"]
|
||||||
|
|
||||||
if list_profile and list_header:
|
if list_profile and list_header:
|
||||||
for ind, profile in enumerate(list_profile):
|
for ind, profile in enumerate(list_profile):
|
||||||
@@ -471,7 +495,7 @@ class Reach(SQLSubModel):
|
|||||||
**d, reach=self, status=self._status
|
**d, reach=self, status=self._status
|
||||||
)
|
)
|
||||||
prof.import_points(profile)
|
prof.import_points(profile)
|
||||||
self._profiles.append(prof)
|
self.profiles.append(prof)
|
||||||
self._update_profile_numbers()
|
self._update_profile_numbers()
|
||||||
|
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
@@ -535,8 +559,8 @@ class Reach(SQLSubModel):
|
|||||||
# TODO: Move this function to model reach
|
# TODO: Move this function to model reach
|
||||||
def export_reach(self, filename):
|
def export_reach(self, filename):
|
||||||
with open(f"{filename}", "w") as file_st:
|
with open(f"{filename}", "w") as file_st:
|
||||||
for index in range(len(self._profiles)):
|
for index in range(len(self.profiles)):
|
||||||
profile = self._profiles[index]
|
profile = self.profiles[index]
|
||||||
|
|
||||||
for v in profile.header:
|
for v in profile.header:
|
||||||
file_st.write(f"{v:>6}")
|
file_st.write(f"{v:>6}")
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from Model.Geometry.PointXYZ import PointXYZ
|
from Model.Geometry.PointXYZ import PointXYZ
|
||||||
|
|
||||||
|
|
||||||
class Vector1d:
|
class Vector1d:
|
||||||
def __init__(self, a: PointXYZ, b: PointXYZ):
|
def __init__(self, a: PointXYZ, b: PointXYZ):
|
||||||
self.A = a
|
self.A = a
|
||||||
|
|||||||
@@ -20,14 +20,15 @@ from copy import copy, deepcopy
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
|
|
||||||
class Data(SQLSubModel):
|
class Data(SQLSubModel):
|
||||||
def __init__(self, name:str = "",
|
def __init__(self, name: str = "",
|
||||||
comment:str = "", reach = None,
|
comment: str = "", reach=None,
|
||||||
kp:float = 0.0, discharge:float = 0.0,
|
kp: float = 0.0, discharge: float = 0.0,
|
||||||
height:float = 0.0,
|
height: float = 0.0,
|
||||||
status = None):
|
status=None):
|
||||||
super(Data, self).__init__()
|
super(Data, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -73,7 +74,7 @@ class Data(SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
id = data["reach"].id
|
id = data["reach"].id
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT ind, name, comment, kp, discharge, height " +
|
"SELECT ind, name, comment, kp, discharge, height " +
|
||||||
@@ -95,25 +96,26 @@ class Data(SQLSubModel):
|
|||||||
height = row[5]
|
height = row[5]
|
||||||
|
|
||||||
d = cls(
|
d = cls(
|
||||||
reach = data["reach"],
|
reach=data["reach"],
|
||||||
status = data["status"],
|
status=data["status"],
|
||||||
name = name,
|
name=name,
|
||||||
comment = comment,
|
comment=comment,
|
||||||
kp = kp,
|
kp=kp,
|
||||||
discharge = discharge,
|
discharge=discharge,
|
||||||
height = height,
|
height=height,
|
||||||
)
|
)
|
||||||
|
|
||||||
new[ind] = d
|
new[ind] = d
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"initial_conditions(ind, name, comment, kp, discharge, height, reach) " +
|
"initial_conditions(ind, name, comment, kp, " +
|
||||||
|
"discharge, height, reach) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{ind}, '{self._sql_format(self.name)}', " +
|
f"{ind}, '{self._sql_format(self.name)}', " +
|
||||||
f"'{self._sql_format(self._comment)}', " +
|
f"'{self._sql_format(self._comment)}', " +
|
||||||
@@ -124,16 +126,15 @@ class Data(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
new = Data(
|
new = Data(
|
||||||
name = self.name,
|
name=self.name,
|
||||||
comment = self._comment,
|
comment=self._comment,
|
||||||
kp = self._kp,
|
kp=self._kp,
|
||||||
discharge = self._discharge,
|
discharge=self._discharge,
|
||||||
height = self._height,
|
height=self._height,
|
||||||
reach = self._reach,
|
reach=self._reach,
|
||||||
status = self._status,
|
status=self._status,
|
||||||
)
|
)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
@@ -173,7 +174,7 @@ class Data(SQLSubModel):
|
|||||||
|
|
||||||
def _update_from_kp(self):
|
def _update_from_kp(self):
|
||||||
min = self._update_get_min()
|
min = self._update_get_min()
|
||||||
self._elevation = min - self._height
|
self._elevation = min + self._height
|
||||||
|
|
||||||
def _update_from_elevation(self):
|
def _update_from_elevation(self):
|
||||||
min = self._update_get_min()
|
min = self._update_get_min()
|
||||||
@@ -216,7 +217,7 @@ class InitialConditions(SQLSubModel):
|
|||||||
Data
|
Data
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, reach = None, status = None):
|
def __init__(self, reach=None, status=None):
|
||||||
super(InitialConditions, self).__init__()
|
super(InitialConditions, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -233,23 +234,21 @@ class InitialConditions(SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = cls(
|
new = cls(
|
||||||
reach = data["reach"],
|
reach=data["reach"],
|
||||||
status = data["status"]
|
status=data["status"]
|
||||||
)
|
)
|
||||||
|
|
||||||
new._data = Data._sql_load(
|
new._data = Data._sql_load(
|
||||||
execute,
|
execute,
|
||||||
data = data
|
data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
if new._data is None:
|
if new._data is not None:
|
||||||
return None
|
yield new
|
||||||
|
|
||||||
return new
|
def _sql_save(self, execute, data=None):
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
|
||||||
ok = True
|
ok = True
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
@@ -288,7 +287,7 @@ class InitialConditions(SQLSubModel):
|
|||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = Data(reach = self._reach, status = self._status)
|
n = Data(reach=self._reach, status=self._status)
|
||||||
self._data.insert(index, n)
|
self._data.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -321,7 +320,6 @@ class InitialConditions(SQLSubModel):
|
|||||||
self._data.sort(reverse=reverse, key=key)
|
self._data.sort(reverse=reverse, key=key)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
def _data_get(self, key):
|
def _data_get(self, key):
|
||||||
return list(
|
return list(
|
||||||
map(
|
map(
|
||||||
@@ -341,8 +339,8 @@ class InitialConditions(SQLSubModel):
|
|||||||
|
|
||||||
def _sort_by_z_and_kp(self, profiles):
|
def _sort_by_z_and_kp(self, profiles):
|
||||||
profiles.sort(
|
profiles.sort(
|
||||||
reverse = False,
|
reverse=False,
|
||||||
key = lambda p: p.kp
|
key=lambda p: p.kp
|
||||||
)
|
)
|
||||||
|
|
||||||
first_z = profiles[0].z()
|
first_z = profiles[0].z()
|
||||||
@@ -350,11 +348,11 @@ class InitialConditions(SQLSubModel):
|
|||||||
|
|
||||||
if first_z > last_z:
|
if first_z > last_z:
|
||||||
profiles.sort(
|
profiles.sort(
|
||||||
reverse = True,
|
reverse=True,
|
||||||
key = lambda p: p.kp
|
key=lambda p: p.kp
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_growing_constante_height(self, height:float):
|
def generate_growing_constante_height(self, height: float):
|
||||||
self._data = []
|
self._data = []
|
||||||
|
|
||||||
profiles = self._reach.reach.profiles
|
profiles = self._reach.reach.profiles
|
||||||
@@ -362,7 +360,7 @@ class InitialConditions(SQLSubModel):
|
|||||||
|
|
||||||
prev = None
|
prev = None
|
||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
new = Data(reach = self._reach, status = self._status)
|
new = Data(reach=self._reach, status=self._status)
|
||||||
new["kp"] = profile.kp
|
new["kp"] = profile.kp
|
||||||
|
|
||||||
if prev is None:
|
if prev is None:
|
||||||
@@ -381,11 +379,11 @@ class InitialConditions(SQLSubModel):
|
|||||||
is_reverse = True
|
is_reverse = True
|
||||||
|
|
||||||
self._data.sort(
|
self._data.sort(
|
||||||
reverse = not is_reverse,
|
reverse=not is_reverse,
|
||||||
key = lambda d: d['kp']
|
key=lambda d: d['kp']
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_discharge(self, discharge:float):
|
def generate_discharge(self, discharge: float):
|
||||||
self._new = []
|
self._new = []
|
||||||
|
|
||||||
for d in self._data:
|
for d in self._data:
|
||||||
|
|||||||
@@ -16,81 +16,62 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import types
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDict import PamhyrModelDict
|
||||||
from Model.InitialConditions.InitialConditions import InitialConditions
|
from Model.InitialConditions.InitialConditions import InitialConditions
|
||||||
|
|
||||||
class InitialConditionsDict(SQLSubModel):
|
|
||||||
|
class InitialConditionsDict(PamhyrModelDict):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
InitialConditions,
|
InitialConditions,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(InitialConditionsDict, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._reach = {}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_load(cls, execute, data=None):
|
||||||
return cls._create_submodel(execute)
|
new = cls(status=data["status"])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return cls._update_submodel(execute, version)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_load(cls, execute, data = None):
|
|
||||||
new = cls(status = data["status"])
|
|
||||||
|
|
||||||
for reach in data["edges"]:
|
for reach in data["edges"]:
|
||||||
data["reach"] = reach
|
data["reach"] = reach
|
||||||
|
|
||||||
ic = InitialConditions._sql_load(
|
ic = InitialConditions._sql_load(
|
||||||
execute,
|
execute,
|
||||||
data = data
|
data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
if ic is not None:
|
if ic is not None:
|
||||||
new._reach[reach] = ic
|
new._dict[reach] = ic
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
ok = True
|
ok = True
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
execute("DELETE FROM initial_conditions")
|
execute("DELETE FROM initial_conditions")
|
||||||
|
|
||||||
for reach in self._reach:
|
for reach in self._dict:
|
||||||
data["reach"] = reach
|
data["reach"] = reach
|
||||||
ok &= self._reach[reach]._sql_save(execute, data)
|
ok &= self._dict[reach]._sql_save(execute, data)
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def __len__(self):
|
def get(self, key):
|
||||||
return len(self._reach)
|
if key in self._dict:
|
||||||
|
v = self._dict[key]
|
||||||
|
if isinstance(v, types.GeneratorType):
|
||||||
|
self._dict[key] = list(v)[0]
|
||||||
|
|
||||||
def is_defined(self, reach):
|
return self._dict[key]
|
||||||
return reach in self._reach
|
|
||||||
|
|
||||||
def get(self, reach):
|
new = self.new(key)
|
||||||
if reach in self._reach:
|
self.set(key, new)
|
||||||
return self._reach[reach]
|
|
||||||
|
|
||||||
new = self.new(reach)
|
|
||||||
self.set(reach, new)
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def set(self, reach, new):
|
|
||||||
self._reach[reach] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, reach):
|
def new(self, reach):
|
||||||
new = InitialConditions(reach = reach, status = self._status)
|
new = InitialConditions(reach=reach, status=self._status)
|
||||||
self.set(reach, new)
|
self.set(reach, new)
|
||||||
return new
|
return new
|
||||||
@@ -20,16 +20,17 @@ import logging
|
|||||||
|
|
||||||
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
from tools import trace, timer, old_pamhyr_date_to_timestamp
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class LateralContribution(SQLSubModel):
|
class LateralContribution(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, id:int = -1, name:str = "", status = None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(LateralContribution, self).__init__()
|
super(LateralContribution, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -39,7 +40,6 @@ class LateralContribution(SQLSubModel):
|
|||||||
else:
|
else:
|
||||||
self.id = id
|
self.id = id
|
||||||
|
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._type = ""
|
self._type = ""
|
||||||
self._edge = None
|
self._edge = None
|
||||||
@@ -49,7 +49,8 @@ class LateralContribution(SQLSubModel):
|
|||||||
self._header = []
|
self._header = []
|
||||||
self._types = [float, float]
|
self._types = [float, float]
|
||||||
|
|
||||||
LateralContribution._id_cnt = max(LateralContribution._id_cnt + 1, self.id)
|
LateralContribution._id_cnt = max(
|
||||||
|
LateralContribution._id_cnt + 1, self.id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_create(cls, execute):
|
||||||
@@ -99,7 +100,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
|
||||||
@@ -112,9 +113,9 @@ class LateralContribution(SQLSubModel):
|
|||||||
t = row[2]
|
t = row[2]
|
||||||
ctor = cls._get_ctor_from_type(t)
|
ctor = cls._get_ctor_from_type(t)
|
||||||
lc = ctor(
|
lc = ctor(
|
||||||
id = row[0],
|
id=row[0],
|
||||||
name = row[1],
|
name=row[1],
|
||||||
status = data['status']
|
status=data['status']
|
||||||
)
|
)
|
||||||
lc.edge = None
|
lc.edge = None
|
||||||
if row[3] != -1:
|
if row[3] != -1:
|
||||||
@@ -141,7 +142,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
tab = data["tab"]
|
tab = data["tab"]
|
||||||
|
|
||||||
execute(f"DELETE FROM lateral_contribution WHERE id = {self.id}")
|
execute(f"DELETE FROM lateral_contribution WHERE id = {self.id}")
|
||||||
@@ -153,7 +154,8 @@ class LateralContribution(SQLSubModel):
|
|||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"lateral_contribution(id, name, type, tab, edge, begin_kp, end_kp) "+
|
"lateral_contribution(id, name, type, tab, " +
|
||||||
|
"edge, begin_kp, end_kp) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._sql_format(self._name)}', " +
|
f"{self.id}, '{self._sql_format(self._name)}', " +
|
||||||
f"'{self._sql_format(self._type)}', '{tab}', {edge}, " +
|
f"'{self._sql_format(self._type)}', '{tab}', {edge}, " +
|
||||||
@@ -169,7 +171,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"lateral_contribution_data(ind, data0, data1, lc) "+
|
"lateral_contribution_data(ind, data0, data1, lc) " +
|
||||||
f"VALUES ({ind}, '{data0}', {data1}, {self.id})"
|
f"VALUES ({ind}, '{data0}', {data1}, {self.id})"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
@@ -186,7 +188,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def time_convert(cls, data):
|
def time_convert(cls, data):
|
||||||
if type(data) == str and data.count(":") == 3:
|
if data is str and data.count(":") == 3:
|
||||||
return old_pamhyr_date_to_timestamp(data)
|
return old_pamhyr_date_to_timestamp(data)
|
||||||
|
|
||||||
return int(data)
|
return int(data)
|
||||||
@@ -282,7 +284,7 @@ class LateralContribution(SQLSubModel):
|
|||||||
new_1 = self._default_1
|
new_1 = self._default_1
|
||||||
|
|
||||||
if len(header) != 0:
|
if len(header) != 0:
|
||||||
for i in [0,1]:
|
for i in [0, 1]:
|
||||||
for j in range(len(header)):
|
for j in range(len(header)):
|
||||||
if self._header[i] == header[j]:
|
if self._header[i] == header[j]:
|
||||||
if i == 0:
|
if i == 0:
|
||||||
@@ -295,13 +297,13 @@ class LateralContribution(SQLSubModel):
|
|||||||
|
|
||||||
return (new_0, new_1)
|
return (new_0, new_1)
|
||||||
|
|
||||||
def add(self, index:int):
|
def add(self, index: int):
|
||||||
value = (self._default_0, self._default_1)
|
value = (self._default_0, self._default_1)
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def insert(self, index:int, value):
|
def insert(self, index: int, value):
|
||||||
self._data.insert(index, value)
|
self._data.insert(index, value)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -337,11 +339,10 @@ class LateralContribution(SQLSubModel):
|
|||||||
return self.data[index]
|
return self.data[index]
|
||||||
|
|
||||||
def get_range(self, _range):
|
def get_range(self, _range):
|
||||||
l = []
|
lst = []
|
||||||
for r in _range:
|
for r in _range:
|
||||||
l.append(r)
|
lst.append(r)
|
||||||
return l
|
return lst
|
||||||
|
|
||||||
|
|
||||||
def _set_i_c_v(self, index, column, value):
|
def _set_i_c_v(self, index, column, value):
|
||||||
v = list(self._data[index])
|
v = list(self._data[index])
|
||||||
@@ -349,15 +350,15 @@ class LateralContribution(SQLSubModel):
|
|||||||
self._data[index] = tuple(v)
|
self._data[index] = tuple(v)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def set_i_0(self, index:int, value):
|
def set_i_0(self, index: int, value):
|
||||||
self._set_i_c_v(index, 0, value)
|
self._set_i_c_v(index, 0, value)
|
||||||
|
|
||||||
def set_i_1(self, index:int, value):
|
def set_i_1(self, index: int, value):
|
||||||
self._set_i_c_v(index, 1, value)
|
self._set_i_c_v(index, 1, value)
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def convert(self, cls):
|
def convert(self, cls):
|
||||||
new = cls(name = self.name, status = self._status)
|
new = cls(name=self.name, status=self._status)
|
||||||
new.edge = self.edge
|
new.edge = self.edge
|
||||||
new.begin_kp = self.begin_kp
|
new.begin_kp = self.begin_kp
|
||||||
new.end_kp = self.end_kp
|
new.end_kp = self.end_kp
|
||||||
@@ -365,8 +366,8 @@ class LateralContribution(SQLSubModel):
|
|||||||
for i, _ in enumerate(self.data):
|
for i, _ in enumerate(self.data):
|
||||||
new.add(i)
|
new.add(i)
|
||||||
|
|
||||||
for i in [0,1]:
|
for i in [0, 1]:
|
||||||
for j in [0,1]:
|
for j in [0, 1]:
|
||||||
if self._header[i] == new.header[j]:
|
if self._header[i] == new.header[j]:
|
||||||
for ind, v in self.data:
|
for ind, v in self.data:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrList import PamhyrModelListWithTab
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
from Model.LateralContribution.LateralContribution import LateralContribution
|
from Model.LateralContribution.LateralContribution import LateralContribution
|
||||||
@@ -27,33 +27,16 @@ from Model.LateralContribution.LateralContributionTypes import (
|
|||||||
NotDefined, LateralContrib, Rain, Evaporation,
|
NotDefined, LateralContrib, Rain, Evaporation,
|
||||||
)
|
)
|
||||||
|
|
||||||
class LateralContributionList(SQLSubModel):
|
|
||||||
|
class LateralContributionList(PamhyrModelListWithTab):
|
||||||
|
_tabs_list = ["liquid", "solid", "suspenssion"]
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
LateralContribution,
|
LateralContribution,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(LateralContributionList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._tabs = {
|
|
||||||
"liquid" : [],
|
|
||||||
"solid" : [],
|
|
||||||
"suspenssion" : []
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_load(cls, execute, data=None):
|
||||||
return cls._create_submodel(execute)
|
new = cls(status=data['status'])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return True
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_load(cls, execute, data = None):
|
|
||||||
new = cls(status = data['status'])
|
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
@@ -66,7 +49,7 @@ class LateralContributionList(SQLSubModel):
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
execute("DELETE FROM lateral_contribution")
|
execute("DELETE FROM lateral_contribution")
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
@@ -75,83 +58,29 @@ class LateralContributionList(SQLSubModel):
|
|||||||
for tab in self._tabs:
|
for tab in self._tabs:
|
||||||
data["tab"] = tab
|
data["tab"] = tab
|
||||||
for lc in self._tabs[tab]:
|
for lc in self._tabs[tab]:
|
||||||
lc._sql_save(execute, data = data)
|
lc._sql_save(execute, data=data)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def len(self, lst):
|
|
||||||
return len(self._tabs[lst])
|
|
||||||
|
|
||||||
def get_tab(self, lst):
|
|
||||||
return self._tabs[lst].copy()
|
|
||||||
|
|
||||||
def get(self, lst, row):
|
|
||||||
return self._tabs[lst][row]
|
|
||||||
|
|
||||||
def set(self, lst, row, new):
|
|
||||||
self._tabs[lst][row] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, lst, index):
|
def new(self, lst, index):
|
||||||
n = NotDefined(status=self._status)
|
n = NotDefined(status=self._status)
|
||||||
self._tabs[lst].insert(index, n)
|
self._tabs[lst].insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, lst, index, new):
|
|
||||||
self._tabs[lst].insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, lst, bcs):
|
|
||||||
for bc in bcs:
|
|
||||||
self._tabs[lst].remove(bc)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, lst, indexes):
|
|
||||||
bcs = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._tabs[lst])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(lst, bcs)
|
|
||||||
|
|
||||||
def sort(self, lst, reverse=False, key=None):
|
|
||||||
self._tabs[lst].sort(reverse=reverse, key=key)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_up(self, lst, index):
|
|
||||||
if index < len(self._tabs[lst]):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, lst, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._tabs[lst]
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def __copy__(self):
|
def __copy__(self):
|
||||||
new = LateralContributionList()
|
new = LateralContributionList()
|
||||||
|
|
||||||
for l in self._tabs:
|
for lst in self._tabs:
|
||||||
new.tabs[l] = self._tabs[l].copy()
|
new.tabs[lst] = self._tabs[lst].copy()
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def __deepcopy__(self):
|
def __deepcopy__(self):
|
||||||
new = LateralContributionList()
|
new = LateralContributionList()
|
||||||
|
|
||||||
for l in self._tabs:
|
for lst in self._tabs:
|
||||||
new.tabs[l] = self._tabs[l].deepcopy()
|
new.tabs[lst] = self._tabs[lst].deepcopy()
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from Model.LateralContribution.LateralContribution import LateralContribution
|
|||||||
|
|
||||||
|
|
||||||
class NotDefined(LateralContribution):
|
class NotDefined(LateralContribution):
|
||||||
def __init__(self, id:int = -1, name:str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(NotDefined, self).__init__(id=id, name=name, status=status)
|
super(NotDefined, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "ND"
|
self._type = "ND"
|
||||||
@@ -32,8 +32,9 @@ class NotDefined(LateralContribution):
|
|||||||
def _default_0(self):
|
def _default_0(self):
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
class LateralContrib(LateralContribution):
|
class LateralContrib(LateralContribution):
|
||||||
def __init__(self, id:int = -1, name:str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(LateralContrib, self).__init__(id=id, name=name, status=status)
|
super(LateralContrib, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "LC"
|
self._type = "LC"
|
||||||
@@ -44,8 +45,9 @@ class LateralContrib(LateralContribution):
|
|||||||
def compatibility(cls):
|
def compatibility(cls):
|
||||||
return ["liquid"]
|
return ["liquid"]
|
||||||
|
|
||||||
|
|
||||||
class Rain(LateralContribution):
|
class Rain(LateralContribution):
|
||||||
def __init__(self, id:int = -1, name:str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(Rain, self).__init__(id=id, name=name, status=status)
|
super(Rain, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "RA"
|
self._type = "RA"
|
||||||
@@ -56,8 +58,9 @@ class Rain(LateralContribution):
|
|||||||
def compatibility(cls):
|
def compatibility(cls):
|
||||||
return ["liquid"]
|
return ["liquid"]
|
||||||
|
|
||||||
|
|
||||||
class Evaporation(LateralContribution):
|
class Evaporation(LateralContribution):
|
||||||
def __init__(self, id:int = -1, name:str = "", status=None):
|
def __init__(self, id: int = -1, name: str = "", status=None):
|
||||||
super(Evaporation, self).__init__(id=id, name=name, status=status)
|
super(Evaporation, self).__init__(id=id, name=name, status=status)
|
||||||
|
|
||||||
self._type = "EV"
|
self._type = "EV"
|
||||||
|
|||||||
@@ -18,13 +18,14 @@
|
|||||||
|
|
||||||
from Model.Network.Node import Node
|
from Model.Network.Node import Node
|
||||||
|
|
||||||
|
|
||||||
class Edge(object):
|
class Edge(object):
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, id:int, name:str,
|
def __init__(self, id: int, name: str,
|
||||||
node1:Node = None,
|
node1: Node = None,
|
||||||
node2:Node = None,
|
node2: Node = None,
|
||||||
status = None):
|
status=None):
|
||||||
super(Edge, self).__init__()
|
super(Edge, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -74,7 +75,10 @@ class Edge(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._name if self._name != "" else f"{self.node1.name} -> {self.node2.name}"
|
name = self._name
|
||||||
|
if self._name == "":
|
||||||
|
name = f"{self.node1.name} -> {self.node2.name}"
|
||||||
|
return name
|
||||||
|
|
||||||
def is_enable(self):
|
def is_enable(self):
|
||||||
return self._enable
|
return self._enable
|
||||||
|
|||||||
+15
-15
@@ -21,8 +21,9 @@ from functools import reduce
|
|||||||
from Model.Network.Node import Node
|
from Model.Network.Node import Node
|
||||||
from Model.Network.Edge import Edge
|
from Model.Network.Edge import Edge
|
||||||
|
|
||||||
|
|
||||||
class Graph(object):
|
class Graph(object):
|
||||||
def __init__(self, status = None):
|
def __init__(self, status=None):
|
||||||
super(Graph, self).__init__()
|
super(Graph, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -83,7 +84,7 @@ class Graph(object):
|
|||||||
False
|
False
|
||||||
)
|
)
|
||||||
|
|
||||||
def node(self, node_name:str):
|
def node(self, node_name: str):
|
||||||
node = list(
|
node = list(
|
||||||
filter(
|
filter(
|
||||||
lambda n: n.name == node_name,
|
lambda n: n.name == node_name,
|
||||||
@@ -96,7 +97,7 @@ class Graph(object):
|
|||||||
|
|
||||||
return node[0]
|
return node[0]
|
||||||
|
|
||||||
def edge(self, edge_name:str):
|
def edge(self, edge_name: str):
|
||||||
edge = list(
|
edge = list(
|
||||||
filter(
|
filter(
|
||||||
lambda e: e.name == edge_name,
|
lambda e: e.name == edge_name,
|
||||||
@@ -109,12 +110,12 @@ class Graph(object):
|
|||||||
|
|
||||||
return edge[0]
|
return edge[0]
|
||||||
|
|
||||||
def _create_node(self, x:float, y:float):
|
def _create_node(self, x: float, y: float):
|
||||||
node = self._node_ctor(
|
node = self._node_ctor(
|
||||||
-1,
|
-1,
|
||||||
"",
|
"",
|
||||||
x = x, y = y,
|
x=x, y=y,
|
||||||
status = self._status
|
status=self._status
|
||||||
)
|
)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
@@ -123,14 +124,14 @@ class Graph(object):
|
|||||||
self._status.modified()
|
self._status.modified()
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def add_node(self, x:float = 0.0, y:float = 0.0):
|
def add_node(self, x: float = 0.0, y: float = 0.0):
|
||||||
node = self._create_node(x, y)
|
node = self._create_node(x, y)
|
||||||
return self._add_node(node)
|
return self._add_node(node)
|
||||||
|
|
||||||
def insert_node(self, node):
|
def insert_node(self, node):
|
||||||
return self._add_node(node)
|
return self._add_node(node)
|
||||||
|
|
||||||
def remove_node(self, node_name:str):
|
def remove_node(self, node_name: str):
|
||||||
self._nodes = list(
|
self._nodes = list(
|
||||||
filter(
|
filter(
|
||||||
lambda n: n.name != node_name,
|
lambda n: n.name != node_name,
|
||||||
@@ -139,19 +140,18 @@ class Graph(object):
|
|||||||
)
|
)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def create_node(self, x:float = 0.0, y:float = 0.0):
|
def create_node(self, x: float = 0.0, y: float = 0.0):
|
||||||
node = self._create_node(x, y)
|
node = self._create_node(x, y)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def _create_edge(self, n1:Node, n2:Node):
|
def _create_edge(self, n1: Node, n2: Node):
|
||||||
edge = self._edge_ctor(
|
edge = self._edge_ctor(
|
||||||
-1,
|
-1,
|
||||||
"", n1, n2,
|
"", n1, n2,
|
||||||
status = self._status
|
status=self._status
|
||||||
)
|
)
|
||||||
return edge
|
return edge
|
||||||
|
|
||||||
|
|
||||||
def _add_edge(self, edge):
|
def _add_edge(self, edge):
|
||||||
# This edge already exists ?
|
# This edge already exists ?
|
||||||
if any(filter(lambda e: (e.node1 == edge.node1 and
|
if any(filter(lambda e: (e.node1 == edge.node1 and
|
||||||
@@ -164,17 +164,17 @@ class Graph(object):
|
|||||||
self._status.modified()
|
self._status.modified()
|
||||||
return edge
|
return edge
|
||||||
|
|
||||||
def add_edge(self, n1:Node, n2:Node):
|
def add_edge(self, n1: Node, n2: Node):
|
||||||
edge = self._create_edge(n1, n2)
|
edge = self._create_edge(n1, n2)
|
||||||
return self._add_edge(edge)
|
return self._add_edge(edge)
|
||||||
|
|
||||||
def insert_edge(self, edge):
|
def insert_edge(self, edge):
|
||||||
return self._add_edge(edge)
|
return self._add_edge(edge)
|
||||||
|
|
||||||
def create_edge(self, n1:Node, n2:Node):
|
def create_edge(self, n1: Node, n2: Node):
|
||||||
return self._create_edge(n1, n2)
|
return self._create_edge(n1, n2)
|
||||||
|
|
||||||
def remove_edge(self, edge_name:str):
|
def remove_edge(self, edge_name: str):
|
||||||
self._edges = list(
|
self._edges = list(
|
||||||
filter(
|
filter(
|
||||||
lambda e: e.name != edge_name,
|
lambda e: e.name != edge_name,
|
||||||
|
|||||||
@@ -18,12 +18,13 @@
|
|||||||
|
|
||||||
from Model.Network.Point import Point
|
from Model.Network.Point import Point
|
||||||
|
|
||||||
|
|
||||||
class Node(object):
|
class Node(object):
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, id:int, name:str,
|
def __init__(self, id: int, name: str,
|
||||||
x:float = 0.0, y:float = 0.0,
|
x: float = 0.0, y: float = 0.0,
|
||||||
status = None):
|
status=None):
|
||||||
super(Node, self).__init__()
|
super(Node, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -73,7 +74,6 @@ class Node(object):
|
|||||||
def y(self):
|
def y(self):
|
||||||
return self.pos.y
|
return self.pos.y
|
||||||
|
|
||||||
|
|
||||||
def setPos(self, x, y):
|
def setPos(self, x, y):
|
||||||
self.pos.x = x
|
self.pos.x = x
|
||||||
self.pos.y = y
|
self.pos.y = y
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
class Point(object):
|
class Point(object):
|
||||||
def __init__(self, x:float, y:float):
|
def __init__(self, x: float, y: float):
|
||||||
super(Point, self).__init__()
|
super(Point, self).__init__()
|
||||||
|
|
||||||
self.x = x
|
self.x = x
|
||||||
|
|||||||
@@ -24,9 +24,15 @@ from Model.Results.River.River import River
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Results(object):
|
class Results(object):
|
||||||
def __init__(self, study = None):
|
def __init__(self, study=None, solver=None,
|
||||||
|
repertory="", name="0"):
|
||||||
self._study = study
|
self._study = study
|
||||||
|
self._solver = solver
|
||||||
|
self._repertory = repertory
|
||||||
|
self._name = name
|
||||||
|
|
||||||
self._river = River(self._study)
|
self._river = River(self._study)
|
||||||
|
|
||||||
self._meta_data = {
|
self._meta_data = {
|
||||||
@@ -43,8 +49,19 @@ class Results(object):
|
|||||||
def river(self):
|
def river(self):
|
||||||
return self._river
|
return self._river
|
||||||
|
|
||||||
|
@property
|
||||||
|
def study(self):
|
||||||
|
return self._study
|
||||||
|
|
||||||
def set(self, key, value):
|
def set(self, key, value):
|
||||||
self._meta_data[key] = value
|
self._meta_data[key] = value
|
||||||
|
|
||||||
def get(self, key):
|
def get(self, key):
|
||||||
return self._meta_data[key]
|
return self._meta_data[key]
|
||||||
|
|
||||||
|
def reload(self):
|
||||||
|
return self._solver.results(
|
||||||
|
self._study,
|
||||||
|
self._repertory,
|
||||||
|
qlog=None,
|
||||||
|
)
|
||||||
@@ -20,11 +20,15 @@ from datetime import datetime
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Profile(object):
|
class Profile(object):
|
||||||
def __init__(self, profile, study):
|
def __init__(self, profile, study):
|
||||||
self._study = study
|
self._study = study
|
||||||
self._profile = profile # Source profile in the study
|
self._profile = profile # Source profile in the study
|
||||||
self._data = {} # Dict of dict {<ts>: {<key>: <value>, ...}, ...}
|
self._data = {} # Dict of dict {<ts>: {<key>: <value>, ...}, ...}
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -55,10 +59,11 @@ class Profile(object):
|
|||||||
def get_ts_key(self, timestamp, key):
|
def get_ts_key(self, timestamp, key):
|
||||||
return self._data[timestamp][key]
|
return self._data[timestamp][key]
|
||||||
|
|
||||||
|
|
||||||
class Reach(object):
|
class Reach(object):
|
||||||
def __init__(self, reach, study):
|
def __init__(self, reach, study):
|
||||||
self._study = study
|
self._study = study
|
||||||
self._reach = reach # Source reach in the study
|
self._reach = reach # Source reach in the study
|
||||||
self._profiles = list(
|
self._profiles = list(
|
||||||
map(
|
map(
|
||||||
lambda p: Profile(p, self._study),
|
lambda p: Profile(p, self._study),
|
||||||
@@ -66,6 +71,9 @@ class Reach(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._profiles)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._reach.name
|
return self._reach.name
|
||||||
@@ -84,6 +92,7 @@ class Reach(object):
|
|||||||
def set(self, profile_id, timestamp, key, data):
|
def set(self, profile_id, timestamp, key, data):
|
||||||
self._profiles[profile_id].set(timestamp, key, data)
|
self._profiles[profile_id].set(timestamp, key, data)
|
||||||
|
|
||||||
|
|
||||||
class River(object):
|
class River(object):
|
||||||
def __init__(self, study):
|
def __init__(self, study):
|
||||||
self._study = study
|
self._study = study
|
||||||
@@ -91,6 +100,9 @@ class River(object):
|
|||||||
# Dict with timestamps as key
|
# Dict with timestamps as key
|
||||||
self._reachs = []
|
self._reachs = []
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._reachs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reachs(self):
|
def reachs(self):
|
||||||
return self._reachs.copy()
|
return self._reachs.copy()
|
||||||
|
|||||||
+34
-34
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
from tools import flatten
|
from tools import flatten
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
from Model.Network.Node import Node
|
from Model.Network.Node import Node
|
||||||
from Model.Network.Edge import Edge
|
from Model.Network.Edge import Edge
|
||||||
@@ -28,7 +28,9 @@ from Model.Geometry.Profile import Profile
|
|||||||
from Model.Geometry.Reach import Reach
|
from Model.Geometry.Reach import Reach
|
||||||
|
|
||||||
from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList
|
from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList
|
||||||
from Model.LateralContribution.LateralContributionList import LateralContributionList
|
from Model.LateralContribution.LateralContributionList import (
|
||||||
|
LateralContributionList
|
||||||
|
)
|
||||||
from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict
|
from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict
|
||||||
from Model.Stricklers.StricklersList import StricklersList
|
from Model.Stricklers.StricklersList import StricklersList
|
||||||
from Model.Friction.FrictionList import FrictionList
|
from Model.Friction.FrictionList import FrictionList
|
||||||
@@ -37,16 +39,17 @@ from Model.SedimentLayer.SedimentLayerList import SedimentLayerList
|
|||||||
|
|
||||||
from Solver.Solvers import solver_type_list
|
from Solver.Solvers import solver_type_list
|
||||||
|
|
||||||
|
|
||||||
class RiverNode(Node, SQLSubModel):
|
class RiverNode(Node, SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
|
|
||||||
def __init__(self, id:str, name:str,
|
def __init__(self, id: str, name: str,
|
||||||
x:float, y:float,
|
x: float, y: float,
|
||||||
status = None):
|
status=None):
|
||||||
super(RiverNode, self).__init__(
|
super(RiverNode, self).__init__(
|
||||||
id, name,
|
id, name,
|
||||||
x, y,
|
x, y,
|
||||||
status = status
|
status=status
|
||||||
)
|
)
|
||||||
|
|
||||||
self._locker = None
|
self._locker = None
|
||||||
@@ -70,7 +73,7 @@ class RiverNode(Node, SQLSubModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|
||||||
table = execute("SELECT id, name, x, y FROM river_node")
|
table = execute("SELECT id, name, x, y FROM river_node")
|
||||||
@@ -82,11 +85,11 @@ class RiverNode(Node, SQLSubModel):
|
|||||||
|
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT OR REPLACE INTO river_node(id, name, x, y) VALUES (" +
|
"INSERT OR REPLACE INTO river_node(id, name, x, y) VALUES (" +
|
||||||
f"{self.id}, '{self._sql_format(self.name)}', " +
|
f"{self.id}, '{self._sql_format(self.name)}', " +
|
||||||
f"{self.x}, {self.y}"+
|
f"{self.x}, {self.y}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
@@ -108,18 +111,18 @@ class RiverReach(Edge, SQLSubModel):
|
|||||||
FrictionList,
|
FrictionList,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, id:str, name:str,
|
def __init__(self, id: str, name: str,
|
||||||
node1:RiverNode = None,
|
node1: RiverNode = None,
|
||||||
node2:RiverNode = None,
|
node2: RiverNode = None,
|
||||||
status = None):
|
status=None):
|
||||||
super(RiverReach, self).__init__(
|
super(RiverReach, self).__init__(
|
||||||
id, name,
|
id, name,
|
||||||
node1, node2,
|
node1, node2,
|
||||||
status = status
|
status=status
|
||||||
)
|
)
|
||||||
|
|
||||||
self._reach = Reach(status=self._status, parent=self)
|
self._reach = Reach(status=self._status, parent=self)
|
||||||
self._frictions = FrictionList(status = self._status)
|
self._frictions = FrictionList(status=self._status)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_create(cls, execute):
|
||||||
@@ -143,13 +146,14 @@ class RiverReach(Edge, SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
reachs = []
|
reachs = []
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
table = execute("SELECT id, name, enable, node1, node2 FROM river_reach")
|
table = execute(
|
||||||
|
"SELECT id, name, enable, node1, node2 FROM river_reach")
|
||||||
for row in table:
|
for row in table:
|
||||||
# Update id counter
|
# Update id counter
|
||||||
cls._id_cnt = max(cls._id_cnt, row[0])
|
cls._id_cnt = max(cls._id_cnt, row[0])
|
||||||
@@ -161,8 +165,8 @@ class RiverReach(Edge, SQLSubModel):
|
|||||||
node1 = next(filter(lambda n: n.id == row[3], data["nodes"]))
|
node1 = next(filter(lambda n: n.id == row[3], data["nodes"]))
|
||||||
node2 = next(filter(lambda n: n.id == row[4], data["nodes"]))
|
node2 = next(filter(lambda n: n.id == row[4], data["nodes"]))
|
||||||
|
|
||||||
new = cls(id, name, node1, node2, status = data["status"])
|
new = cls(id, name, node1, node2, status=data["status"])
|
||||||
new.enable(enable = enable)
|
new.enable(enable=enable)
|
||||||
|
|
||||||
data["reach"] = id
|
data["reach"] = id
|
||||||
data["parent"] = new
|
data["parent"] = new
|
||||||
@@ -174,14 +178,14 @@ class RiverReach(Edge, SQLSubModel):
|
|||||||
|
|
||||||
return reachs
|
return reachs
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT OR REPLACE INTO " +
|
"INSERT OR REPLACE INTO " +
|
||||||
"river_reach(id, name, enable, node1, node2) "+
|
"river_reach(id, name, enable, node1, node2) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, '{self._sql_format(self._name)}', " +
|
f"{self.id}, '{self._sql_format(self._name)}', " +
|
||||||
f"{self._sql_format(self.is_enable())},"
|
f"{self._sql_format(self.is_enable())},"
|
||||||
f"{self.node1.id}, {self.node2.id}"+
|
f"{self.node1.id}, {self.node2.id}" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
execute(sql)
|
execute(sql)
|
||||||
@@ -202,6 +206,7 @@ class RiverReach(Edge, SQLSubModel):
|
|||||||
def frictions(self):
|
def frictions(self):
|
||||||
return self._frictions
|
return self._frictions
|
||||||
|
|
||||||
|
|
||||||
class River(Graph, SQLSubModel):
|
class River(Graph, SQLSubModel):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
RiverNode,
|
RiverNode,
|
||||||
@@ -223,7 +228,8 @@ class River(Graph, SQLSubModel):
|
|||||||
|
|
||||||
self._current_reach = None
|
self._current_reach = None
|
||||||
self._boundary_condition = BoundaryConditionList(status=self._status)
|
self._boundary_condition = BoundaryConditionList(status=self._status)
|
||||||
self._lateral_contribution = LateralContributionList(status=self._status)
|
self._lateral_contribution = LateralContributionList(
|
||||||
|
status=self._status)
|
||||||
self._initial_conditions = InitialConditionsDict(status=self._status)
|
self._initial_conditions = InitialConditionsDict(status=self._status)
|
||||||
self._stricklers = StricklersList(status=self._status)
|
self._stricklers = StricklersList(status=self._status)
|
||||||
self._parameters = {}
|
self._parameters = {}
|
||||||
@@ -240,7 +246,7 @@ class River(Graph, SQLSubModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = cls(data["status"])
|
new = cls(data["status"])
|
||||||
|
|
||||||
# Stricklers (Stricklers is load in first because it's needed
|
# Stricklers (Stricklers is load in first because it's needed
|
||||||
@@ -251,7 +257,6 @@ class River(Graph, SQLSubModel):
|
|||||||
)
|
)
|
||||||
data["stricklers"] = new._stricklers
|
data["stricklers"] = new._stricklers
|
||||||
|
|
||||||
|
|
||||||
# Initial conditions
|
# Initial conditions
|
||||||
new._sediment_layers = SedimentLayerList._sql_load(
|
new._sediment_layers = SedimentLayerList._sql_load(
|
||||||
execute,
|
execute,
|
||||||
@@ -297,7 +302,7 @@ class River(Graph, SQLSubModel):
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
objs = (self._nodes + self._edges)
|
objs = (self._nodes + self._edges)
|
||||||
objs.append(self._boundary_condition)
|
objs.append(self._boundary_condition)
|
||||||
objs.append(self._initial_conditions)
|
objs.append(self._initial_conditions)
|
||||||
@@ -311,10 +316,6 @@ class River(Graph, SQLSubModel):
|
|||||||
self._save_submodel(execute, objs, data)
|
self._save_submodel(execute, objs, data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
|
||||||
def frictions(self):
|
|
||||||
return self._frictions
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def boundary_condition(self):
|
def boundary_condition(self):
|
||||||
return self._boundary_condition
|
return self._boundary_condition
|
||||||
@@ -348,7 +349,6 @@ class River(Graph, SQLSubModel):
|
|||||||
|
|
||||||
return ret[0]
|
return ret[0]
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parameters(self):
|
def parameters(self):
|
||||||
return self._parameters
|
return self._parameters
|
||||||
@@ -358,8 +358,8 @@ class River(Graph, SQLSubModel):
|
|||||||
return self._parameters[solver]
|
return self._parameters[solver]
|
||||||
|
|
||||||
new = SolverParametersList(
|
new = SolverParametersList(
|
||||||
solver_type = solver_type_list[solver],
|
solver_type=solver_type_list[solver],
|
||||||
status = self._status
|
status=self._status
|
||||||
)
|
)
|
||||||
self._parameters[solver] = new
|
self._parameters[solver] = new
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
@@ -385,7 +385,7 @@ class River(Graph, SQLSubModel):
|
|||||||
has = len(self._sediment_layers) != 0
|
has = len(self._sediment_layers) != 0
|
||||||
has &= any(
|
has &= any(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p.sl != None,
|
lambda p: p.sl is not None,
|
||||||
flatten(
|
flatten(
|
||||||
map(lambda e: e.reach.profiles, self.edges())
|
map(lambda e: e.reach.profiles, self.edges())
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import logging
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class SavedStatus(object):
|
class SavedStatus(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SavedStatus, self).__init__()
|
super(SavedStatus, self).__init__()
|
||||||
|
|||||||
@@ -2,19 +2,20 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
|
||||||
class Layer(SQLSubModel):
|
class Layer(SQLSubModel):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
id:int = -1, name:str = "",
|
id: int = -1, name: str = "",
|
||||||
type = "",
|
type="",
|
||||||
height = 0.0, d50 = 0.0, sigma = 0.0,
|
height=0.0, d50=0.0, sigma=0.0,
|
||||||
critical_constraint = 0.0,
|
critical_constraint=0.0,
|
||||||
sl = None, status = None):
|
sl=None, status=None):
|
||||||
super(Layer, self).__init__()
|
super(Layer, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -111,12 +112,13 @@ class Layer(SQLSubModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
sl = data["sl"]
|
sl = data["sl"]
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT id, ind, name, type, height, d50, sigma, critical_constraint " +
|
"SELECT id, ind, name, type, height, " +
|
||||||
|
"d50, sigma, critical_constraint " +
|
||||||
"FROM sedimentary_layer_layer " +
|
"FROM sedimentary_layer_layer " +
|
||||||
f"WHERE sl = {sl}"
|
f"WHERE sl = {sl}"
|
||||||
)
|
)
|
||||||
@@ -128,24 +130,25 @@ class Layer(SQLSubModel):
|
|||||||
ind = row[1]
|
ind = row[1]
|
||||||
|
|
||||||
layer = cls(
|
layer = cls(
|
||||||
id = row[0], name = row[2],
|
id=row[0], name=row[2],
|
||||||
type = row[3], height = row[4],
|
type=row[3], height=row[4],
|
||||||
d50 = row[5], sigma = row[6],
|
d50=row[5], sigma=row[6],
|
||||||
critical_constraint = row[7],
|
critical_constraint=row[7],
|
||||||
sl = sl, status = data['status']
|
sl=sl, status=data['status']
|
||||||
)
|
)
|
||||||
|
|
||||||
new[ind] = layer
|
new[ind] = layer
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
ind = data["ind"]
|
ind = data["ind"]
|
||||||
sl = data["sl"]
|
sl = data["sl"]
|
||||||
|
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"sedimentary_layer_layer(id, ind, name, type, height, d50, sigma, critical_constraint, sl) "+
|
"sedimentary_layer_layer(id, ind, name, type, height, " +
|
||||||
|
"d50, sigma, critical_constraint, sl) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
|
f"{self.id}, {ind}, '{self._sql_format(self._name)}', " +
|
||||||
f"'{self._sql_format(self._type)}', {self._height}, " +
|
f"'{self._sql_format(self._type)}', {self._height}, " +
|
||||||
@@ -162,9 +165,9 @@ class SedimentLayer(SQLSubModel):
|
|||||||
_sub_classes = [Layer]
|
_sub_classes = [Layer]
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
|
|
||||||
def __init__(self, id:int = -1,
|
def __init__(self, id: int = -1,
|
||||||
name:str = "", comment:str = "",
|
name: str = "", comment: str = "",
|
||||||
status = None):
|
status=None):
|
||||||
super(SedimentLayer, self).__init__()
|
super(SedimentLayer, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
@@ -196,7 +199,7 @@ class SedimentLayer(SQLSubModel):
|
|||||||
|
|
||||||
def height(self):
|
def height(self):
|
||||||
return list(
|
return list(
|
||||||
map(lambda l: l.height, self._layers)
|
map(lambda layer: layer.height, self._layers)
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -209,7 +212,7 @@ class SedimentLayer(SQLSubModel):
|
|||||||
|
|
||||||
def names(self):
|
def names(self):
|
||||||
return list(
|
return list(
|
||||||
map(lambda l: l.name, self._layers)
|
map(lambda layer: layer.name, self._layers)
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -242,7 +245,7 @@ class SedimentLayer(SQLSubModel):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = []
|
new = []
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
@@ -252,10 +255,10 @@ class SedimentLayer(SQLSubModel):
|
|||||||
|
|
||||||
for row in table:
|
for row in table:
|
||||||
sl = cls(
|
sl = cls(
|
||||||
id = row[0],
|
id=row[0],
|
||||||
name = row[1],
|
name=row[1],
|
||||||
comment = row[2],
|
comment=row[2],
|
||||||
status = data['status']
|
status=data['status']
|
||||||
)
|
)
|
||||||
|
|
||||||
data["sl"] = sl.id
|
data["sl"] = sl.id
|
||||||
@@ -265,7 +268,7 @@ class SedimentLayer(SQLSubModel):
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
if data is None:
|
if data is None:
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
@@ -279,9 +282,9 @@ class SedimentLayer(SQLSubModel):
|
|||||||
data["sl"] = self
|
data["sl"] = self
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for l in self._layers:
|
for layer in self._layers:
|
||||||
data["ind"] = ind
|
data["ind"] = ind
|
||||||
l._sql_save(execute, data)
|
layer._sql_save(execute, data)
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -298,7 +301,7 @@ class SedimentLayer(SQLSubModel):
|
|||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = Layer(sl=self, status = self._status)
|
n = Layer(sl=self, status=self._status)
|
||||||
self.insert(index, n)
|
self.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
@@ -324,8 +327,8 @@ class SedimentLayer(SQLSubModel):
|
|||||||
if index >= 0:
|
if index >= 0:
|
||||||
next = index - 1
|
next = index - 1
|
||||||
|
|
||||||
l = self._layers
|
lst = self._layers
|
||||||
l[index], l[next] = l[next], l[index]
|
lst[index], lst[next] = lst[next], lst[index]
|
||||||
|
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
@@ -333,7 +336,7 @@ class SedimentLayer(SQLSubModel):
|
|||||||
if index + 1 < len(self._layers):
|
if index + 1 < len(self._layers):
|
||||||
prev = index + 1
|
prev = index + 1
|
||||||
|
|
||||||
l = self._layers
|
lst = self._layers
|
||||||
l[index], l[prev] = l[prev], l[index]
|
lst[index], lst[prev] = lst[prev], lst[index]
|
||||||
|
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
@@ -2,100 +2,40 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
from Model.SedimentLayer.SedimentLayer import SedimentLayer
|
||||||
|
|
||||||
class SedimentLayerList(SQLSubModel):
|
|
||||||
|
class SedimentLayerList(PamhyrModelList):
|
||||||
_sub_classes = [SedimentLayer]
|
_sub_classes = [SedimentLayer]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
super(SedimentLayerList, self).__init__()
|
|
||||||
|
|
||||||
self._status = status
|
|
||||||
self._sl = []
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._sl)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_load(cls, execute, data=None):
|
||||||
return cls._create_submodel(execute)
|
new = cls(status=data["status"])
|
||||||
|
|
||||||
@classmethod
|
new._lst = SedimentLayer._sql_load(execute, data)
|
||||||
def _sql_update(cls, execute, version):
|
|
||||||
return cls._update_submodel(execute, version)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _sql_load(cls, execute, data = None):
|
|
||||||
new = cls(status = data["status"])
|
|
||||||
|
|
||||||
new._sl = SedimentLayer._sql_load(execute, data)
|
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
ok = True
|
ok = True
|
||||||
|
|
||||||
# Delete previous data
|
# Delete previous data
|
||||||
execute("DELETE FROM sedimentary_layer")
|
execute("DELETE FROM sedimentary_layer")
|
||||||
execute("DELETE FROM sedimentary_layer_layer")
|
execute("DELETE FROM sedimentary_layer_layer")
|
||||||
|
|
||||||
for sl in self._sl:
|
for sl in self._lst:
|
||||||
ok &= sl._sql_save(execute, data)
|
ok &= sl._sql_save(execute, data)
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sediment_layers(self):
|
def sediment_layers(self):
|
||||||
return self._sl.copy()
|
return self.lst
|
||||||
|
|
||||||
def get(self, index):
|
|
||||||
return self._sl[index]
|
|
||||||
|
|
||||||
def set(self, index, new):
|
|
||||||
self._sl[index] = new
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def insert(self, index, new):
|
|
||||||
self._sl.insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = SedimentLayer(status = self._status)
|
n = SedimentLayer(status=self._status)
|
||||||
self.insert(index, n)
|
self.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def delete(self, els):
|
|
||||||
for el in els:
|
|
||||||
self._sl.remove(el)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
els = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._sl)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(els)
|
|
||||||
|
|
||||||
def move_up(self, index):
|
|
||||||
if index < len(self._sl):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._sl
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._sl
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
class Serializable():
|
class Serializable():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ from copy import copy
|
|||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
from Solver.Solvers import solver_type_list
|
from Solver.Solvers import solver_type_list
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
|
|
||||||
|
|
||||||
class Parameter():
|
class Parameter():
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name = "", value = "",
|
name="", value="",
|
||||||
status = None):
|
status=None):
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
@@ -57,26 +58,26 @@ class Parameter():
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_tuple(cls, data, status):
|
def from_tuple(cls, data, status):
|
||||||
new = cls(status = status)
|
new = cls(status=status)
|
||||||
new["name"] = data[0]
|
new["name"] = data[0]
|
||||||
new["value"] = data[1]
|
new["value"] = data[1]
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
class SolverParametersList(SQLSubModel):
|
|
||||||
def __init__(self, solver_type = None, status = None):
|
class SolverParametersList(PamhyrModelList):
|
||||||
|
def __init__(self, solver_type=None, status=None):
|
||||||
super(SolverParametersList, self).__init__()
|
super(SolverParametersList, self).__init__()
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
self._solver = solver_type
|
self._solver = solver_type
|
||||||
self._parameters = list(
|
self._lst = list(
|
||||||
map(
|
map(
|
||||||
lambda t: Parameter.from_tuple(t, self._status),
|
lambda t: Parameter.from_tuple(t, self._status),
|
||||||
solver_type.default_parameters()
|
solver_type.default_parameters()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_create(cls, execute):
|
||||||
execute("""
|
execute("""
|
||||||
@@ -97,35 +98,42 @@ class SolverParametersList(SQLSubModel):
|
|||||||
|
|
||||||
if major == minor == "0":
|
if major == minor == "0":
|
||||||
if int(release) < 3:
|
if int(release) < 3:
|
||||||
execute(f"UPDATE solver_parameter SET name='mage_implicitation' WHERE name='mage_implication'")
|
execute(
|
||||||
execute(f"UPDATE solver_parameter SET name='mage_iteration_type' WHERE name='mage_iter_type'")
|
"UPDATE solver_parameter SET name='mage_implicitation' " +
|
||||||
|
"WHERE name='mage_implication'"
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
"UPDATE solver_parameter SET name='mage_iteration_type' " +
|
||||||
|
"WHERE name='mage_iter_type'"
|
||||||
|
)
|
||||||
|
|
||||||
if int(release) < 4:
|
if int(release) < 4:
|
||||||
solvers = execute("SELECT DISTINCT solver FROM solver_parameter")
|
solvers = execute(
|
||||||
|
"SELECT DISTINCT solver FROM solver_parameter")
|
||||||
|
|
||||||
for solver in solvers:
|
for solver in solvers:
|
||||||
if solver != "mage8":
|
if solver != "mage8":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
data = execute("SELECT ind, name, value " +
|
data = execute("SELECT ind, name, value " +
|
||||||
"FROM solver_parameter "+
|
"FROM solver_parameter " +
|
||||||
f"WHERE solver = '{solver}' " +
|
f"WHERE solver = '{solver}' " +
|
||||||
"ORDER BY ind ACS")
|
"ORDER BY ind ACS")
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM solver_parameter " +
|
"DELETE FROM solver_parameter " +
|
||||||
f"WHERE solver = '{solver}'"
|
f"WHERE solver = '{solver}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
insert = lambda name, value, ind: execute(
|
def insert(name, value, ind): return execute(
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"solver_parameter(ind, name, value, solver) "+
|
"solver_parameter(ind, name, value, solver) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{ind}, " +
|
f"{ind}, " +
|
||||||
f"'{cls._sql_format(name)}', " +
|
f"'{cls._sql_format(name)}', " +
|
||||||
f"'{cls._sql_format(value)}', " +
|
f"'{cls._sql_format(value)}', " +
|
||||||
f"'{cls._sql_format(solver)}'" +
|
f"'{cls._sql_format(solver)}'" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
@@ -156,7 +164,7 @@ class SolverParametersList(SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
solvers = execute("SELECT DISTINCT solver FROM solver_parameter")
|
solvers = execute("SELECT DISTINCT solver FROM solver_parameter")
|
||||||
new = {}
|
new = {}
|
||||||
@@ -167,7 +175,7 @@ class SolverParametersList(SQLSubModel):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
st = solver_type_list[solver]
|
st = solver_type_list[solver]
|
||||||
n = cls(solver_type = st, status = status)
|
n = cls(solver_type=st, status=status)
|
||||||
|
|
||||||
table = execute(
|
table = execute(
|
||||||
"SELECT ind, name, value " +
|
"SELECT ind, name, value " +
|
||||||
@@ -186,7 +194,7 @@ class SolverParametersList(SQLSubModel):
|
|||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
t = self._solver._type
|
t = self._solver._type
|
||||||
execute(
|
execute(
|
||||||
"DELETE FROM solver_parameter " +
|
"DELETE FROM solver_parameter " +
|
||||||
@@ -194,10 +202,10 @@ class SolverParametersList(SQLSubModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
ind = 0
|
ind = 0
|
||||||
for param in self._parameters:
|
for param in self._lst:
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"solver_parameter(ind, name, value, solver) "+
|
"solver_parameter(ind, name, value, solver) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{ind}, " +
|
f"{ind}, " +
|
||||||
f"'{self._sql_format(param.name)}', " +
|
f"'{self._sql_format(param.name)}', " +
|
||||||
@@ -210,90 +218,46 @@ class SolverParametersList(SQLSubModel):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._parameters)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parameters(self):
|
def parameters(self):
|
||||||
return self._parameters.copy()
|
return self.lst
|
||||||
|
|
||||||
def get(self, index):
|
def get(self, index):
|
||||||
return self._parameters[index]
|
return self._lst[index]
|
||||||
|
|
||||||
def get_by_key(self, key):
|
def get_by_key(self, key):
|
||||||
try:
|
try:
|
||||||
return next(
|
return next(
|
||||||
filter(
|
filter(
|
||||||
lambda p: p["name"] == key,
|
lambda p: p["name"] == key,
|
||||||
self._parameters
|
self._lst
|
||||||
)
|
)
|
||||||
)["value"]
|
)["value"]
|
||||||
except:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set(self, index, new):
|
def set(self, index, new):
|
||||||
self._parameters[index] = new
|
self._lst[index] = new
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def set_value(self, key, value):
|
def set_value(self, key, value):
|
||||||
for p in self._parameters:
|
for p in self._lst:
|
||||||
if p["name"] == key:
|
if p["name"] == key:
|
||||||
p["value"] = value
|
p["value"] = value
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return
|
return
|
||||||
|
|
||||||
self._parameters.append(
|
self._lst.append(
|
||||||
Parameter(
|
Parameter(
|
||||||
name = key,
|
name=key,
|
||||||
value = value,
|
value=value,
|
||||||
status = self._status
|
status=self._status
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
|
|
||||||
def new(self, index):
|
def new(self, index):
|
||||||
n = Parameter(status = self._status)
|
n = Parameter(status=self._status)
|
||||||
self._parameters.insert(index, n)
|
self._lst.insert(index, n)
|
||||||
self._status.modified()
|
self._status.modified()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def insert(self, index, new):
|
|
||||||
self._parameters.insert(index, new)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete(self, parameters):
|
|
||||||
for parameter in parameters:
|
|
||||||
self._parameters.remove(parameter)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
parameters = list(
|
|
||||||
map(
|
|
||||||
lambda x: x[1],
|
|
||||||
filter(
|
|
||||||
lambda x: x[0] in indexes,
|
|
||||||
enumerate(self._parameters)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(parameters)
|
|
||||||
|
|
||||||
def sort(self, reverse=False, key=None):
|
|
||||||
self._parameters.sort(reverse=reverse, key=key)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_up(self, index):
|
|
||||||
if index < len(self._parameters):
|
|
||||||
next = index - 1
|
|
||||||
|
|
||||||
l = self._parameters
|
|
||||||
l[index], l[next] = l[next], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def move_down(self, index):
|
|
||||||
if index >= 0:
|
|
||||||
prev = index + 1
|
|
||||||
|
|
||||||
l = self._parameters
|
|
||||||
l[index], l[prev] = l[prev], l[index]
|
|
||||||
self._status.modified()
|
|
||||||
@@ -18,18 +18,19 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
|
||||||
|
|
||||||
class Stricklers(SQLSubModel):
|
class Stricklers(SQLSubModel):
|
||||||
_id_cnt = 0
|
_id_cnt = 0
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
|
|
||||||
def __init__(self, id:int = -1,
|
def __init__(self, id: int = -1,
|
||||||
name:str = "",
|
name: str = "",
|
||||||
comment:str = "",
|
comment: str = "",
|
||||||
minor:float = 35.0,
|
minor: float = 35.0,
|
||||||
medium:float = 15.0,
|
medium: float = 15.0,
|
||||||
status = None):
|
status=None):
|
||||||
super(Stricklers, self).__init__()
|
super(Stricklers, self).__init__()
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
@@ -46,7 +47,6 @@ class Stricklers(SQLSubModel):
|
|||||||
self._minor = minor
|
self._minor = minor
|
||||||
self._medium = medium
|
self._medium = medium
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_create(cls, execute):
|
||||||
execute("""
|
execute("""
|
||||||
@@ -66,7 +66,7 @@ class Stricklers(SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
stricklers = []
|
stricklers = []
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
|
|
||||||
@@ -86,21 +86,21 @@ class Stricklers(SQLSubModel):
|
|||||||
medium = row[4]
|
medium = row[4]
|
||||||
|
|
||||||
new = cls(
|
new = cls(
|
||||||
id = id,
|
id=id,
|
||||||
name = name,
|
name=name,
|
||||||
comment = comment,
|
comment=comment,
|
||||||
minor = minor, medium = medium,
|
minor=minor, medium=medium,
|
||||||
status = status
|
status=status
|
||||||
)
|
)
|
||||||
|
|
||||||
stricklers.append(new)
|
stricklers.append(new)
|
||||||
|
|
||||||
return stricklers
|
return stricklers
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
sql = (
|
sql = (
|
||||||
"INSERT INTO " +
|
"INSERT INTO " +
|
||||||
"stricklers(id, name, comment, minor, medium) "+
|
"stricklers(id, name, comment, minor, medium) " +
|
||||||
"VALUES (" +
|
"VALUES (" +
|
||||||
f"{self.id}, " +
|
f"{self.id}, " +
|
||||||
f"'{self._sql_format(self.name)}', " +
|
f"'{self._sql_format(self.name)}', " +
|
||||||
|
|||||||
@@ -18,22 +18,16 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from Model.DB import SQLSubModel
|
|
||||||
from Model.Saved import SavedStatus
|
from Model.Saved import SavedStatus
|
||||||
|
from Model.Tools.PamhyrList import PamhyrModelList
|
||||||
from Model.Stricklers.Stricklers import Stricklers
|
from Model.Stricklers.Stricklers import Stricklers
|
||||||
|
|
||||||
class StricklersList(SQLSubModel):
|
|
||||||
|
class StricklersList(PamhyrModelList):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
Stricklers,
|
Stricklers,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, status = None):
|
|
||||||
if status is None:
|
|
||||||
status = SavedStatus()
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self._stricks = []
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_create(cls, execute):
|
def _sql_create(cls, execute):
|
||||||
return cls._create_submodel(execute)
|
return cls._create_submodel(execute)
|
||||||
@@ -43,74 +37,42 @@ class StricklersList(SQLSubModel):
|
|||||||
return cls._update_submodel(execute, version)
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
new = cls(status = data["status"])
|
new = cls(status=data["status"])
|
||||||
|
|
||||||
new._stricks = Stricklers._sql_load(
|
new._lst = Stricklers._sql_load(
|
||||||
execute,
|
execute,
|
||||||
data = data
|
data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
execute("DELETE FROM stricklers")
|
execute("DELETE FROM stricklers")
|
||||||
|
|
||||||
objs = self._stricks
|
objs = self._lst
|
||||||
return self._save_submodel(execute, objs, data)
|
return self._save_submodel(execute, objs, data)
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self._stricks)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stricklers(self):
|
def stricklers(self):
|
||||||
return self._stricks.copy()
|
return self.lst
|
||||||
|
|
||||||
def get(self, index):
|
def new(self, index):
|
||||||
if 0 <= index < len(self._stricks):
|
s = Stricklers(status=self._status)
|
||||||
return self._stricks[index]
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def insert(self, index, strick):
|
|
||||||
self._stricks.insert(index, strick)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def add(self, index):
|
|
||||||
s = Stricklers(status = self._status)
|
|
||||||
self.insert(index, s)
|
self.insert(index, s)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def delete(self, stricks):
|
|
||||||
self._stricks = list(
|
|
||||||
filter(
|
|
||||||
lambda s: s not in stricks,
|
|
||||||
self._stricks
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self._status.modified()
|
|
||||||
|
|
||||||
def delete_i(self, indexes):
|
|
||||||
stricks = set(
|
|
||||||
map(
|
|
||||||
lambda e: e[1],
|
|
||||||
filter(
|
|
||||||
lambda e: e[0] in indexes,
|
|
||||||
enumerate(self._stricks)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.delete(stricks)
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def sort(self, reverse:bool = False, key=None):
|
def sort(self, reverse: bool = False, key=None):
|
||||||
f = lambda st: st.name
|
def f(st): return st.name
|
||||||
if key is not None:
|
if key is not None:
|
||||||
f = key
|
f = key
|
||||||
|
|
||||||
self._stricks = sorted(
|
self._lst = sorted(
|
||||||
self._stricks,
|
self._lst,
|
||||||
key = f,
|
key=f,
|
||||||
reverse = reverse,
|
reverse=reverse,
|
||||||
)
|
)
|
||||||
self._status.modified()
|
|
||||||
|
if self._status is not None:
|
||||||
|
self._status.modified()
|
||||||
+65
-27
@@ -23,7 +23,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
from tools import timer, timestamp
|
from tools import timer, timestamp
|
||||||
|
|
||||||
from Model.DB import SQLModel
|
from Model.Tools.PamhyrDB import SQLModel
|
||||||
from Model.Saved import SavedStatus
|
from Model.Saved import SavedStatus
|
||||||
from Model.Serializable import Serializable
|
from Model.Serializable import Serializable
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
@@ -33,12 +33,13 @@ from Checker.Study import *
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class Study(SQLModel):
|
class Study(SQLModel):
|
||||||
_sub_classes = [
|
_sub_classes = [
|
||||||
River,
|
River,
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, filename = None, init_new = True):
|
def __init__(self, filename=None, init_new=True):
|
||||||
# Metadata
|
# Metadata
|
||||||
self._version = "0.0.4"
|
self._version = "0.0.4"
|
||||||
self.creation_date = datetime.now()
|
self.creation_date = datetime.now()
|
||||||
@@ -46,7 +47,7 @@ class Study(SQLModel):
|
|||||||
self.last_save_date = datetime.now()
|
self.last_save_date = datetime.now()
|
||||||
|
|
||||||
self._filename = filename
|
self._filename = filename
|
||||||
super(Study, self).__init__(filename = filename)
|
super(Study, self).__init__(filename=filename)
|
||||||
|
|
||||||
self.status = SavedStatus()
|
self.status = SavedStatus()
|
||||||
|
|
||||||
@@ -59,9 +60,9 @@ class Study(SQLModel):
|
|||||||
|
|
||||||
if init_new:
|
if init_new:
|
||||||
# Study data
|
# Study data
|
||||||
self._river = River(status = self.status)
|
self._river = River(status=self.status)
|
||||||
else:
|
else:
|
||||||
self._init_db_file(filename, is_new = False)
|
self._init_db_file(filename, is_new=False)
|
||||||
|
|
||||||
self._old_save_id = 0
|
self._old_save_id = 0
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ class Study(SQLModel):
|
|||||||
@filename.setter
|
@filename.setter
|
||||||
def filename(self, filename):
|
def filename(self, filename):
|
||||||
self._filename = str(filename)
|
self._filename = str(filename)
|
||||||
self._init_db_file(filename, is_new = True)
|
self._init_db_file(filename, is_new=True)
|
||||||
self.status.modified()
|
self.status.modified()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -139,7 +140,7 @@ class Study(SQLModel):
|
|||||||
self._time_system = "time"
|
self._time_system = "time"
|
||||||
self.status.modified()
|
self.status.modified()
|
||||||
|
|
||||||
def use_date(self, date:datetime):
|
def use_date(self, date: datetime):
|
||||||
self._time_system = "date"
|
self._time_system = "date"
|
||||||
self._date = date
|
self._date = date
|
||||||
self.status.modified()
|
self.status.modified()
|
||||||
@@ -158,7 +159,7 @@ class Study(SQLModel):
|
|||||||
# return cls()
|
# return cls()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls, name, description, date = None):
|
def new(cls, name, description, date=None):
|
||||||
me = cls()
|
me = cls()
|
||||||
me.name = name
|
me.name = name
|
||||||
me.description = description
|
me.description = description
|
||||||
@@ -178,14 +179,17 @@ class Study(SQLModel):
|
|||||||
|
|
||||||
def _create(self):
|
def _create(self):
|
||||||
# Info (metadata)
|
# Info (metadata)
|
||||||
self.execute("CREATE TABLE info(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)")
|
|
||||||
self.execute(
|
self.execute(
|
||||||
f"INSERT INTO info VALUES ('version', '{self._sql_format(self._version)}')",
|
"CREATE TABLE info(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)")
|
||||||
commit = True
|
self.execute(
|
||||||
|
"INSERT INTO info VALUES ('version', " +
|
||||||
|
f"'{self._sql_format(self._version)}')",
|
||||||
|
commit=True
|
||||||
)
|
)
|
||||||
self.execute("INSERT INTO info VALUES ('name', '')")
|
self.execute("INSERT INTO info VALUES ('name', '')")
|
||||||
self.execute("INSERT INTO info VALUES ('description', '')")
|
self.execute("INSERT INTO info VALUES ('description', '')")
|
||||||
self.execute(f"INSERT INTO info VALUES ('time_system', '{self._time_system}')")
|
self.execute(
|
||||||
|
f"INSERT INTO info VALUES ('time_system', '{self._time_system}')")
|
||||||
self.execute(
|
self.execute(
|
||||||
f"INSERT INTO info VALUES ('date', " +
|
f"INSERT INTO info VALUES ('date', " +
|
||||||
"'{self._date.timestamp()}')"
|
"'{self._date.timestamp()}')"
|
||||||
@@ -213,7 +217,8 @@ class Study(SQLModel):
|
|||||||
logger.info("Update database")
|
logger.info("Update database")
|
||||||
|
|
||||||
if self._update_submodel(version[0]):
|
if self._update_submodel(version[0]):
|
||||||
self.execute(f"UPDATE info SET value='{self._version}' WHERE key='version'")
|
self.execute(
|
||||||
|
f"UPDATE info SET value='{self._version}' WHERE key='version'")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
logger.info("TODO: update failed")
|
logger.info("TODO: update failed")
|
||||||
@@ -221,42 +226,75 @@ class Study(SQLModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _load(cls, filename):
|
def _load(cls, filename):
|
||||||
new = cls(init_new = False, filename = filename)
|
new = cls(init_new=False, filename=filename)
|
||||||
|
|
||||||
# TODO: Load metadata
|
# TODO: Load metadata
|
||||||
new.name = new.execute("SELECT value FROM info WHERE key='name'")[0]
|
new.name = new.execute("SELECT value FROM info WHERE key='name'")[0]
|
||||||
new.description = new.execute("SELECT value FROM info WHERE key='description'")[0]
|
new.description = new.execute(
|
||||||
new._time_system = new.execute("SELECT value FROM info WHERE key='time_system'")[0]
|
"SELECT value FROM info WHERE key='description'")[0]
|
||||||
|
new._time_system = new.execute(
|
||||||
|
"SELECT value FROM info WHERE key='time_system'")[0]
|
||||||
new._date = datetime.fromtimestamp(
|
new._date = datetime.fromtimestamp(
|
||||||
float(new.execute("SELECT value FROM info WHERE key='date'")[0])
|
float(new.execute("SELECT value FROM info WHERE key='date'")[0])
|
||||||
)
|
)
|
||||||
|
|
||||||
new.creation_date = datetime.fromtimestamp(
|
new.creation_date = datetime.fromtimestamp(
|
||||||
float(new.execute("SELECT value FROM info WHERE key='creation_date'")[0])
|
float(new.execute(
|
||||||
|
"SELECT value FROM info WHERE key='creation_date'")[0])
|
||||||
)
|
)
|
||||||
new.last_save_date = datetime.fromtimestamp(
|
new.last_save_date = datetime.fromtimestamp(
|
||||||
float(new.execute("SELECT value FROM info WHERE key='last_save_date'")[0])
|
float(new.execute(
|
||||||
|
"SELECT value FROM info WHERE key='last_save_date'")[0])
|
||||||
)
|
)
|
||||||
|
|
||||||
# Load river data
|
# Load river data
|
||||||
new._river = River._sql_load(
|
new._river = River._sql_load(
|
||||||
lambda sql: new.execute(
|
lambda sql: new.execute(
|
||||||
sql,
|
sql,
|
||||||
fetch_one = False,
|
fetch_one=False,
|
||||||
commit = True
|
commit=True
|
||||||
),
|
),
|
||||||
data = {"status": new.status}
|
data={"status": new.status}
|
||||||
)
|
)
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def _save(self):
|
def _save(self):
|
||||||
self.execute(f"UPDATE info SET value='{self._sql_format(self.name)}' WHERE key='name'")
|
self.execute(
|
||||||
self.execute(f"UPDATE info SET value='{self._sql_format(self.description)}' WHERE key='description'")
|
f"UPDATE info SET " +
|
||||||
self.execute(f"UPDATE info SET value='{self._time_system}' WHERE key='time_system'")
|
f"value='{self._sql_format(self.name)}' WHERE key='name'"
|
||||||
self.execute(f"UPDATE info SET value='{timestamp(self._date)}' WHERE key='date'")
|
)
|
||||||
self.execute(f"UPDATE info SET value='{timestamp(self.creation_date)}' WHERE key='creation_date'")
|
self.execute(
|
||||||
self.execute(f"UPDATE info SET value='{timestamp(self.last_save_date)}' WHERE key='last_save_date'")
|
f"UPDATE info SET " +
|
||||||
|
f"value='{self._sql_format(self.description)}' " +
|
||||||
|
"WHERE key='description'"
|
||||||
|
)
|
||||||
|
self.execute(
|
||||||
|
f"UPDATE info SET " +
|
||||||
|
f"value='{self._time_system}' WHERE key='time_system'"
|
||||||
|
)
|
||||||
|
self.execute(
|
||||||
|
f"UPDATE info SET " +
|
||||||
|
f"value='{timestamp(self._date)}' WHERE key='date'"
|
||||||
|
)
|
||||||
|
self.execute(
|
||||||
|
f"UPDATE info SET " +
|
||||||
|
f"value='{timestamp(self.creation_date)}' " +
|
||||||
|
"WHERE key='creation_date'"
|
||||||
|
)
|
||||||
|
self.execute(
|
||||||
|
f"UPDATE info SET " +
|
||||||
|
f"value='{timestamp(self.last_save_date)}' " +
|
||||||
|
"WHERE key='last_save_date'"
|
||||||
|
)
|
||||||
|
|
||||||
self._save_submodel([self._river])
|
self._save_submodel([self._river])
|
||||||
self.commit()
|
self.commit()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Close db connection
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Nothing.
|
||||||
|
"""
|
||||||
|
self._close()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# DB.py -- Pamhyr abstract model database classes
|
# PamhyrDB.py -- Pamhyr abstract model database classes
|
||||||
# Copyright (C) 2023 INRAE
|
# Copyright (C) 2023 INRAE
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
@@ -28,10 +28,12 @@ from Model.Except import NotImplementedMethodeError
|
|||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
# Top level model class
|
# Top level model class
|
||||||
|
|
||||||
|
|
||||||
class SQLModel(SQL):
|
class SQLModel(SQL):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
|
|
||||||
def _init_db_file(self, db, is_new = True):
|
def _init_db_file(self, db, is_new=True):
|
||||||
exists = Path(db).exists()
|
exists = Path(db).exists()
|
||||||
|
|
||||||
if exists and is_new:
|
if exists and is_new:
|
||||||
@@ -48,15 +50,14 @@ class SQLModel(SQL):
|
|||||||
self._update() # Update db scheme if necessary
|
self._update() # Update db scheme if necessary
|
||||||
# self._load() # Load data
|
# self._load() # Load data
|
||||||
|
|
||||||
|
def __init__(self, filename=None):
|
||||||
def __init__(self, filename = None):
|
|
||||||
self._db = None
|
self._db = None
|
||||||
|
|
||||||
def _create_submodel(self):
|
def _create_submodel(self):
|
||||||
fn = lambda sql: self.execute(
|
def fn(sql): return self.execute(
|
||||||
sql,
|
sql,
|
||||||
fetch_one = False,
|
fetch_one=False,
|
||||||
commit = False
|
commit=False
|
||||||
)
|
)
|
||||||
|
|
||||||
for cls in self._sub_classes:
|
for cls in self._sub_classes:
|
||||||
@@ -69,10 +70,10 @@ class SQLModel(SQL):
|
|||||||
raise NotImplementedMethodeError(self, self._create)
|
raise NotImplementedMethodeError(self, self._create)
|
||||||
|
|
||||||
def _update_submodel(self, version):
|
def _update_submodel(self, version):
|
||||||
fn = lambda sql: self.execute(
|
def fn(sql): return self.execute(
|
||||||
sql,
|
sql,
|
||||||
fetch_one = False,
|
fetch_one=False,
|
||||||
commit = False
|
commit=False
|
||||||
)
|
)
|
||||||
|
|
||||||
ok = True
|
ok = True
|
||||||
@@ -85,11 +86,11 @@ class SQLModel(SQL):
|
|||||||
def _update(self):
|
def _update(self):
|
||||||
raise NotImplementedMethodeError(self, self._update)
|
raise NotImplementedMethodeError(self, self._update)
|
||||||
|
|
||||||
def _save_submodel(self, objs, data = None):
|
def _save_submodel(self, objs, data=None):
|
||||||
fn = lambda sql: self.execute(
|
def fn(sql): return self.execute(
|
||||||
sql,
|
sql,
|
||||||
fetch_one = False,
|
fetch_one=False,
|
||||||
commit = False
|
commit=False
|
||||||
)
|
)
|
||||||
|
|
||||||
ok = True
|
ok = True
|
||||||
@@ -103,18 +104,20 @@ class SQLModel(SQL):
|
|||||||
raise NotImplementedMethodeError(self, self._save)
|
raise NotImplementedMethodeError(self, self._save)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _load(cls, filename = None):
|
def _load(cls, filename=None):
|
||||||
raise NotImplementedMethodeError(cls, cls._load)
|
raise NotImplementedMethodeError(cls, cls._load)
|
||||||
|
|
||||||
# Sub model class
|
# Sub model class
|
||||||
|
|
||||||
|
|
||||||
class SQLSubModel(object):
|
class SQLSubModel(object):
|
||||||
_sub_classes = []
|
_sub_classes = []
|
||||||
|
|
||||||
def _sql_format(self, value):
|
def _sql_format(self, value):
|
||||||
# Replace ''' by ''' to preserve SQL injection
|
# Replace ''' by ''' to preserve SQL injection
|
||||||
if type(value) == str:
|
if value is str:
|
||||||
value = value.replace("'", "'")
|
value = value.replace("'", "'")
|
||||||
elif type(value) == bool:
|
elif value is bool:
|
||||||
value = 'TRUE' if value else 'FALSE'
|
value = 'TRUE' if value else 'FALSE'
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -154,7 +157,7 @@ class SQLSubModel(object):
|
|||||||
raise NotImplementedMethodeError(cls, cls._sql_update)
|
raise NotImplementedMethodeError(cls, cls._sql_update)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _sql_load(cls, execute, data = None):
|
def _sql_load(cls, execute, data=None):
|
||||||
"""Load instance of this class from SQL data base
|
"""Load instance of this class from SQL data base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -166,11 +169,11 @@ class SQLSubModel(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedMethodeError(cls, cls._sql_load)
|
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||||
|
|
||||||
def _save_submodel(self, execute, objs, data = None):
|
def _save_submodel(self, execute, objs, data=None):
|
||||||
for o in objs:
|
for o in objs:
|
||||||
o._sql_save(execute, data = data)
|
o._sql_save(execute, data=data)
|
||||||
|
|
||||||
def _sql_save(self, execute, data = None):
|
def _sql_save(self, execute, data=None):
|
||||||
"""Save class data to data base
|
"""Save class data to data base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# PamhyrDict.py -- Pamhyr abstract dict for model classes
|
||||||
|
# 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 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class PamhyrModelDict(SQLSubModel):
|
||||||
|
_sub_classes = []
|
||||||
|
|
||||||
|
def __init__(self, status=None):
|
||||||
|
super(PamhyrModelDict, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
self._dict = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data=None):
|
||||||
|
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data=None):
|
||||||
|
raise NotImplementedMethodeError(self, self._sql_save)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._dict)
|
||||||
|
|
||||||
|
def is_defined(self, key):
|
||||||
|
return key in self._dict
|
||||||
|
|
||||||
|
def set(self, key, new):
|
||||||
|
self._dict[key] = new
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def get(self, key):
|
||||||
|
if key in self._dict:
|
||||||
|
return self._dict[key]
|
||||||
|
|
||||||
|
new = self.new(key)
|
||||||
|
self.set(key, new)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def new(self, key):
|
||||||
|
raise NotImplementedMethodeError(self, self.new)
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
# PamhyrList.py -- Pamhyr Abstract List object for the Model
|
||||||
|
# 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 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
from tools import trace, timer
|
||||||
|
|
||||||
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class PamhyrModelList(SQLSubModel):
|
||||||
|
_sub_classes = [
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, status=None):
|
||||||
|
super(PamhyrModelList, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
self._lst = []
|
||||||
|
|
||||||
|
#######
|
||||||
|
# SQL #
|
||||||
|
#######
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data=None):
|
||||||
|
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data=None):
|
||||||
|
raise NotImplementedMethodeError(self, self._sql_save)
|
||||||
|
|
||||||
|
################
|
||||||
|
# MODEL METHOD #
|
||||||
|
################
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lst(self):
|
||||||
|
return self._lst
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.lst)
|
||||||
|
|
||||||
|
def get(self, row):
|
||||||
|
return self._lst[row]
|
||||||
|
|
||||||
|
def set(self, row, new):
|
||||||
|
self._lst[row] = new
|
||||||
|
if self._status is not None:
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, index):
|
||||||
|
"""Create new elements and add it to list
|
||||||
|
|
||||||
|
Args:
|
||||||
|
index: The index of new elements
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The new elements
|
||||||
|
"""
|
||||||
|
raise NotImplementedMethodeError(self, self.new)
|
||||||
|
|
||||||
|
def insert(self, index, new):
|
||||||
|
self._lst.insert(index, new)
|
||||||
|
|
||||||
|
if self._status is not None:
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete(self, lst):
|
||||||
|
for el in lst:
|
||||||
|
self._lst.remove(el)
|
||||||
|
|
||||||
|
if self._status is not None:
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, indexes):
|
||||||
|
lst = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] in indexes,
|
||||||
|
enumerate(self._lst)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.delete(lst)
|
||||||
|
|
||||||
|
def sort(self, reverse=False, key=None):
|
||||||
|
self._lst.sort(reverse=reverse, key=key)
|
||||||
|
|
||||||
|
if self._status is not None:
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_up(self, index):
|
||||||
|
if index < len(self._lst):
|
||||||
|
next = index - 1
|
||||||
|
|
||||||
|
lst = self._lst
|
||||||
|
lst[index], lst[next] = lst[next], lst[index]
|
||||||
|
|
||||||
|
if self._status is not None:
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_down(self, index):
|
||||||
|
if index >= 0:
|
||||||
|
prev = index + 1
|
||||||
|
|
||||||
|
lst = self._lst
|
||||||
|
lst[index], lst[prev] = lst[prev], lst[index]
|
||||||
|
|
||||||
|
if self._status is not None:
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
|
||||||
|
class PamhyrModelListWithTab(SQLSubModel):
|
||||||
|
_tabs_list = []
|
||||||
|
_sub_classes = [
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, status=None):
|
||||||
|
super(PamhyrModelListWithTab, self).__init__()
|
||||||
|
|
||||||
|
self._status = status
|
||||||
|
self._tabs = {}
|
||||||
|
for tab in self._tabs_list:
|
||||||
|
self._tabs[tab] = []
|
||||||
|
|
||||||
|
#######
|
||||||
|
# SQL #
|
||||||
|
#######
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_create(cls, execute):
|
||||||
|
return cls._create_submodel(execute)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_update(cls, execute, version):
|
||||||
|
return cls._update_submodel(execute, version)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _sql_load(cls, execute, data=None):
|
||||||
|
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||||
|
|
||||||
|
def _sql_save(self, execute, data=None):
|
||||||
|
raise NotImplementedMethodeError(self, self._sql_save)
|
||||||
|
|
||||||
|
################
|
||||||
|
# MODEL METHOD #
|
||||||
|
################
|
||||||
|
|
||||||
|
def len(self, lst):
|
||||||
|
return len(self._tabs[lst])
|
||||||
|
|
||||||
|
def get_tab(self, lst):
|
||||||
|
return self._tabs[lst].copy()
|
||||||
|
|
||||||
|
def get(self, lst, row):
|
||||||
|
return self._tabs[lst][row]
|
||||||
|
|
||||||
|
def set(self, lst, row, new):
|
||||||
|
self._tabs[lst][row] = new
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def new(self, lst, index):
|
||||||
|
"""Create new elements and add it to list
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lst: The tab name
|
||||||
|
index: The index of new elements
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The new elements
|
||||||
|
"""
|
||||||
|
raise NotImplementedMethodeError(self, self.new)
|
||||||
|
|
||||||
|
def insert(self, lst, index, new):
|
||||||
|
self._tabs[lst].insert(index, new)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete(self, lst, els):
|
||||||
|
for el in els:
|
||||||
|
self._tabs[lst].remove(el)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def delete_i(self, lst, indexes):
|
||||||
|
els = list(
|
||||||
|
map(
|
||||||
|
lambda x: x[1],
|
||||||
|
filter(
|
||||||
|
lambda x: x[0] in indexes,
|
||||||
|
enumerate(self._tabs[lst])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.delete(lst, els)
|
||||||
|
|
||||||
|
def sort(self, lst, reverse=False, key=None):
|
||||||
|
self._tabs[lst].sort(reverse=reverse, key=key)
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_up(self, lst, index):
|
||||||
|
if index < len(self._tabs[lst]):
|
||||||
|
next = index - 1
|
||||||
|
|
||||||
|
lst = self._tabs[lst]
|
||||||
|
lst[index], lst[next] = lst[next], lst[index]
|
||||||
|
self._status.modified()
|
||||||
|
|
||||||
|
def move_down(self, lst, index):
|
||||||
|
if index >= 0:
|
||||||
|
prev = index + 1
|
||||||
|
|
||||||
|
lst = self._tabs[lst]
|
||||||
|
lst[index], lst[prev] = lst[prev], lst[index]
|
||||||
|
self._status.modified()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# __init__.py -- 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 -*-
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
# test_Model.py -- 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 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from Model.Saved import SavedStatus
|
||||||
|
from Model.Study import Study
|
||||||
|
from Model.River import River
|
||||||
|
|
||||||
|
|
||||||
|
class StudyTestCase(unittest.TestCase):
|
||||||
|
def test_create_study(self):
|
||||||
|
study = Study.new("foo", "bar")
|
||||||
|
self.assertEqual(study.name, "foo")
|
||||||
|
self.assertEqual(study.description, "bar")
|
||||||
|
|
||||||
|
def test_open_study(self):
|
||||||
|
study = Study.open("../tests_cases/Enlargement/Enlargement.pamhyr")
|
||||||
|
self.assertNotEqual(study, None)
|
||||||
|
self.assertEqual(study.name, "Enlargement")
|
||||||
|
|
||||||
|
def test_save_open_study(self):
|
||||||
|
study = Study.new("foo", "bar")
|
||||||
|
dir = tempfile.mkdtemp()
|
||||||
|
f = os.path.join(dir, "foo.pamhyr")
|
||||||
|
|
||||||
|
# Save study
|
||||||
|
study.filename = f
|
||||||
|
study.save()
|
||||||
|
study.close()
|
||||||
|
|
||||||
|
# Reopen study
|
||||||
|
study = Study.open(f)
|
||||||
|
|
||||||
|
# Check
|
||||||
|
self.assertNotEqual(study, None)
|
||||||
|
self.assertEqual(study.name, "foo")
|
||||||
|
self.assertEqual(study.description, "bar")
|
||||||
|
|
||||||
|
def test_create_study_river(self):
|
||||||
|
study = Study.new("foo", "bar")
|
||||||
|
self.assertNotEqual(study.river, None)
|
||||||
|
|
||||||
|
|
||||||
|
class RiverTestCase(unittest.TestCase):
|
||||||
|
def test_create_river(self):
|
||||||
|
status = SavedStatus()
|
||||||
|
river = River(status=status)
|
||||||
|
|
||||||
|
self.assertNotEqual(river, None)
|
||||||
|
|
||||||
|
def test_create_river_nodes(self):
|
||||||
|
status = SavedStatus()
|
||||||
|
river = River(status=status)
|
||||||
|
|
||||||
|
self.assertNotEqual(river, None)
|
||||||
|
|
||||||
|
# Add nodes
|
||||||
|
n0 = river.add_node()
|
||||||
|
n1 = river.add_node(x=1.0, y=0.0)
|
||||||
|
n2 = river.add_node(x=0.0, y=1.0)
|
||||||
|
|
||||||
|
# Checks
|
||||||
|
self.assertEqual(river.nodes_counts(), 3)
|
||||||
|
|
||||||
|
nodes = river.nodes()
|
||||||
|
self.assertEqual(nodes[0], n0)
|
||||||
|
self.assertEqual(nodes[1], n1)
|
||||||
|
self.assertEqual(nodes[2], n2)
|
||||||
|
|
||||||
|
def test_create_river_edges(self):
|
||||||
|
status = SavedStatus()
|
||||||
|
river = River(status=status)
|
||||||
|
|
||||||
|
self.assertNotEqual(river, None)
|
||||||
|
|
||||||
|
# Add nodes
|
||||||
|
n0 = river.add_node()
|
||||||
|
n1 = river.add_node(x=1.0, y=0.0)
|
||||||
|
n2 = river.add_node(x=0.0, y=1.0)
|
||||||
|
|
||||||
|
self.assertEqual(river.nodes_counts(), 3)
|
||||||
|
|
||||||
|
# Add edges
|
||||||
|
e0 = river.add_edge(n0, n1)
|
||||||
|
e1 = river.add_edge(n1, n2)
|
||||||
|
|
||||||
|
# Checks
|
||||||
|
self.assertEqual(river.edges_counts(), 2)
|
||||||
|
|
||||||
|
edges = river.edges()
|
||||||
|
self.assertEqual(edges[0], e0)
|
||||||
|
self.assertEqual(edges[1], e1)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# AScript.py -- Pamhyr abstract script class
|
||||||
|
# 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 -*-
|
||||||
|
|
||||||
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
||||||
|
|
||||||
|
class AScript(object):
|
||||||
|
name = ""
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
def __init__(self, app, conf, args):
|
||||||
|
super(AScript, self).__init__()
|
||||||
|
|
||||||
|
self._app = app
|
||||||
|
self._conf = conf
|
||||||
|
self._args = args.copy()
|
||||||
|
|
||||||
|
def usage(self):
|
||||||
|
raise NotImplementedMethodeError(self, self.usage)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
raise NotImplementedMethodeError(self, self.run)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Hello.py -- 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 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from Scripts.AScript import AScript
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptHello(AScript):
|
||||||
|
name = "Hello"
|
||||||
|
description = "Display hello"
|
||||||
|
|
||||||
|
def usage(self):
|
||||||
|
logger.info(f"Usage : {self._args[0]} hello")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
logger.info("Hello from Pamhyr2 script !")
|
||||||
|
return 0
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# ListSolver.py -- 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 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from Scripts.AScript import AScript
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptListSolver(AScript):
|
||||||
|
name = "ListSolver"
|
||||||
|
description = "List configured solver(s) for Pamhyr2"
|
||||||
|
|
||||||
|
def usage(self):
|
||||||
|
logger.info(f"Usage : {self._args[0]} {self._args[1]}")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
for solver in self._conf.solvers:
|
||||||
|
print(f"{solver.name:<16} ({solver.type}): {solver.description}")
|
||||||
|
|
||||||
|
return 0
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# P3DST.py -- 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 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
from numpy import mean
|
||||||
|
|
||||||
|
from Scripts.AScript import AScript
|
||||||
|
|
||||||
|
from Model.Saved import SavedStatus
|
||||||
|
from Model.Geometry.Reach import Reach
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class Script3DST(AScript):
|
||||||
|
name = "3DST"
|
||||||
|
description = "Display a 3D plot of a river reach from ST file"
|
||||||
|
|
||||||
|
def usage(self):
|
||||||
|
logger.info(f"Usage : {self._args[0]} 3DST <INPUT_ST_FILE>")
|
||||||
|
|
||||||
|
def set_axes_equal(self, ax):
|
||||||
|
"""Make axes of 3D plot have equal scale
|
||||||
|
|
||||||
|
Make axes of 3D plot have equal scale so that spheres appear
|
||||||
|
as spheres, cubes as cubes, etc.. This is one possible
|
||||||
|
solution to Matplotlib's ax.set_aspect('equal') and
|
||||||
|
ax.axis('equal') not working for 3D.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ax: a matplotlib axis, e.g., as output from plt.gca()
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The input axis
|
||||||
|
"""
|
||||||
|
x_limits = ax.get_xlim3d()
|
||||||
|
y_limits = ax.get_ylim3d()
|
||||||
|
z_limits = ax.get_zlim3d()
|
||||||
|
|
||||||
|
x_range = abs(x_limits[1] - x_limits[0])
|
||||||
|
x_middle = mean(x_limits)
|
||||||
|
y_range = abs(y_limits[1] - y_limits[0])
|
||||||
|
y_middle = mean(y_limits)
|
||||||
|
z_range = abs(z_limits[1] - z_limits[0])
|
||||||
|
z_middle = mean(z_limits)
|
||||||
|
|
||||||
|
# The plot bounding box is a sphere in the sense of the infinity
|
||||||
|
# norm, hence I call half the max range the plot radius.
|
||||||
|
plot_radius = 0.5*max([x_range, y_range, z_range])
|
||||||
|
|
||||||
|
ax.set_xlim3d([x_middle - plot_radius, x_middle + plot_radius])
|
||||||
|
ax.set_ylim3d([y_middle - plot_radius, y_middle + plot_radius])
|
||||||
|
ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])
|
||||||
|
|
||||||
|
return ax
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
st_file = self._args[2]
|
||||||
|
logger.info(f"Use ST file: {st_file}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Arguments parcing: {str(e)}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
status = SavedStatus()
|
||||||
|
|
||||||
|
my_reach = Reach(status=status)
|
||||||
|
my_reach.import_geometry(st_file)
|
||||||
|
my_reach.compute_guidelines()
|
||||||
|
|
||||||
|
ax = plt.figure().add_subplot(projection="3d")
|
||||||
|
logger.info(my_reach.get_x())
|
||||||
|
for x, y, z in zip(
|
||||||
|
my_reach.get_x(),
|
||||||
|
my_reach.get_y(),
|
||||||
|
my_reach.get_z()
|
||||||
|
):
|
||||||
|
ax.plot(x, y, z, color='r', lw=1.)
|
||||||
|
|
||||||
|
for x, y, z in zip(
|
||||||
|
my_reach.get_guidelines_x(),
|
||||||
|
my_reach.get_guidelines_y(),
|
||||||
|
my_reach.get_guidelines_z()
|
||||||
|
):
|
||||||
|
ax.plot(x, y, z, color='b', lw=1.)
|
||||||
|
|
||||||
|
ax.set_xlabel('X')
|
||||||
|
ax.set_ylabel('Y')
|
||||||
|
ax.set_zlabel('Z')
|
||||||
|
plt.tight_layout()
|
||||||
|
self.set_axes_equal(ax)
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(str(e))
|
||||||
|
return 1
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
# Run.py -- 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 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QProcess
|
||||||
|
|
||||||
|
from Scripts.AScript import AScript
|
||||||
|
from Model.Study import Study
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptRun(AScript):
|
||||||
|
name = "Run"
|
||||||
|
description = "Run solver on Pamhyr2 a study"
|
||||||
|
|
||||||
|
def usage(self):
|
||||||
|
logger.info(
|
||||||
|
f"Usage : {self._args[0]} {self._args[1]} " +
|
||||||
|
"<SOLVER> <STUDY>"
|
||||||
|
)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if len(self._args) < 4:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
command = self._args[1]
|
||||||
|
solver_name = self._args[2]
|
||||||
|
study_file = os.path.abspath(
|
||||||
|
self._args[3]
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
solver = next(
|
||||||
|
filter(
|
||||||
|
lambda solver: solver.name == solver_name,
|
||||||
|
self._conf.solvers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"No solver found: {e}")
|
||||||
|
return 2
|
||||||
|
|
||||||
|
study = Study.open(study_file)
|
||||||
|
|
||||||
|
self._solver = solver
|
||||||
|
self._study = study
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Run {solver.name} ({solver.type}) " +
|
||||||
|
"on study '{study.name}' ({study_file})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Workdir
|
||||||
|
workdir = os.path.join(
|
||||||
|
os.path.dirname(study.filename),
|
||||||
|
"_PAMHYR_",
|
||||||
|
study.name.replace(" ", "_"),
|
||||||
|
solver.name.replace(" ", "_")
|
||||||
|
)
|
||||||
|
os.makedirs(workdir, exist_ok=True)
|
||||||
|
logger.info(f"Set working dir to {workdir}")
|
||||||
|
|
||||||
|
# Preparate process
|
||||||
|
p = QProcess(None)
|
||||||
|
p.setWorkingDirectory(workdir)
|
||||||
|
|
||||||
|
self._q = Queue()
|
||||||
|
|
||||||
|
# Export and Run
|
||||||
|
logger.info(f"~Export~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||||
|
solver.export(study, workdir, qlog=self._q)
|
||||||
|
|
||||||
|
while self._q.qsize() != 0:
|
||||||
|
s = self._q.get()
|
||||||
|
logger.info(s)
|
||||||
|
|
||||||
|
if command == "run":
|
||||||
|
logger.info(f"~Run~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||||
|
solver.run(
|
||||||
|
study,
|
||||||
|
process=p,
|
||||||
|
output_queue=self._q
|
||||||
|
)
|
||||||
|
p.waitForFinished()
|
||||||
|
|
||||||
|
logger.info(f"~End~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
class ScriptExport(ScriptRun):
|
||||||
|
name = "Export"
|
||||||
|
description = "Export Pamhyr2 study for solver"
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
# plot_3DST.py -- 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 -*-
|
|
||||||
|
|
||||||
# a lancer depuis src
|
|
||||||
import sys
|
|
||||||
from matplotlib import pyplot as plt
|
|
||||||
from Model.Geometry.Reach import Reach
|
|
||||||
from numpy import mean
|
|
||||||
|
|
||||||
def set_axes_equal(ax):
|
|
||||||
'''Make axes of 3D plot have equal scale so that spheres appear as spheres,
|
|
||||||
cubes as cubes, etc.. This is one possible solution to Matplotlib's
|
|
||||||
ax.set_aspect('equal') and ax.axis('equal') not working for 3D.
|
|
||||||
|
|
||||||
Input
|
|
||||||
ax: a matplotlib axis, e.g., as output from plt.gca().
|
|
||||||
'''
|
|
||||||
|
|
||||||
x_limits = ax.get_xlim3d()
|
|
||||||
y_limits = ax.get_ylim3d()
|
|
||||||
z_limits = ax.get_zlim3d()
|
|
||||||
|
|
||||||
x_range = abs(x_limits[1] - x_limits[0])
|
|
||||||
x_middle = mean(x_limits)
|
|
||||||
y_range = abs(y_limits[1] - y_limits[0])
|
|
||||||
y_middle = mean(y_limits)
|
|
||||||
z_range = abs(z_limits[1] - z_limits[0])
|
|
||||||
z_middle = mean(z_limits)
|
|
||||||
|
|
||||||
# The plot bounding box is a sphere in the sense of the infinity
|
|
||||||
# norm, hence I call half the max range the plot radius.
|
|
||||||
plot_radius = 0.5*max([x_range, y_range, z_range])
|
|
||||||
|
|
||||||
ax.set_xlim3d([x_middle - plot_radius, x_middle + plot_radius])
|
|
||||||
ax.set_ylim3d([y_middle - plot_radius, y_middle + plot_radius])
|
|
||||||
ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])
|
|
||||||
|
|
||||||
st_file = sys.argv[1]
|
|
||||||
my_reach = Reach(None)
|
|
||||||
my_reach.import_geometry(st_file)
|
|
||||||
my_reach.compute_guidelines()
|
|
||||||
|
|
||||||
ax = plt.figure().add_subplot(projection="3d")
|
|
||||||
for x, y, z in zip(my_reach.get_x(), my_reach.get_y(), my_reach.get_z()):
|
|
||||||
ax.plot(x, y, z, color='r', lw=1.)
|
|
||||||
for x, y, z in zip(my_reach.get_guidelines_x(), my_reach.get_guidelines_y(), my_reach.get_guidelines_z()):
|
|
||||||
ax.plot(x, y, z, color='b', lw=1.)
|
|
||||||
ax.set_xlabel('X')
|
|
||||||
ax.set_ylabel('Y')
|
|
||||||
ax.set_zlabel('Z')
|
|
||||||
plt.tight_layout()
|
|
||||||
set_axes_equal(ax)
|
|
||||||
plt.show()
|
|
||||||
+31
-14
@@ -22,9 +22,10 @@ import logging
|
|||||||
from tools import timer
|
from tools import timer
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Installation allow Unix-like signal
|
||||||
from signal import SIGTERM, SIGSTOP, SIGCONT
|
from signal import SIGTERM, SIGSTOP, SIGCONT
|
||||||
_signal = True
|
_signal = True
|
||||||
except:
|
except Exception:
|
||||||
_signal = False
|
_signal = False
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
@@ -36,12 +37,14 @@ from Model.Results.River.River import River, Reach, Profile
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class STATUS(Enum):
|
class STATUS(Enum):
|
||||||
NOT_LAUNCHED = -1
|
NOT_LAUNCHED = -1
|
||||||
STOPED = 0
|
STOPED = 0
|
||||||
RUNNING = 1
|
RUNNING = 1
|
||||||
PAUSED = 5
|
PAUSED = 5
|
||||||
|
|
||||||
|
|
||||||
class AbstractSolver(object):
|
class AbstractSolver(object):
|
||||||
_type = ""
|
_type = ""
|
||||||
|
|
||||||
@@ -154,7 +157,7 @@ class AbstractSolver(object):
|
|||||||
# Export #
|
# Export #
|
||||||
##########
|
##########
|
||||||
|
|
||||||
def export(self, study, repertory, qlog = None):
|
def export(self, study, repertory, qlog=None):
|
||||||
raise NotImplementedMethodeError(self, self.export)
|
raise NotImplementedMethodeError(self, self.export)
|
||||||
|
|
||||||
def cmd_args(self, study):
|
def cmd_args(self, study):
|
||||||
@@ -176,6 +179,14 @@ class AbstractSolver(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedMethodeError(self, self.input_param)
|
raise NotImplementedMethodeError(self, self.input_param)
|
||||||
|
|
||||||
|
def output_param(self):
|
||||||
|
"""Return output command line parameter(s)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Returns output parameter(s) string
|
||||||
|
"""
|
||||||
|
raise NotImplementedMethodeError(self, self.output_param)
|
||||||
|
|
||||||
def log_file(self):
|
def log_file(self):
|
||||||
"""Return log file name
|
"""Return log file name
|
||||||
|
|
||||||
@@ -189,8 +200,8 @@ class AbstractSolver(object):
|
|||||||
###########
|
###########
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def results(self, study, repertory, qlog = None):
|
def results(self, study, repertory, qlog=None):
|
||||||
results = Results(study = study)
|
results = Results(study=study)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
#######
|
#######
|
||||||
@@ -201,11 +212,11 @@ class AbstractSolver(object):
|
|||||||
return os.path.abspath(
|
return os.path.abspath(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
os.path.dirname(__file__),
|
os.path.dirname(__file__),
|
||||||
".."
|
"..", ".."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _format_command(self, study, cmd, path = ""):
|
def _format_command(self, study, cmd, path=""):
|
||||||
"""Format command line
|
"""Format command line
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -216,10 +227,10 @@ class AbstractSolver(object):
|
|||||||
The executable and list of arguments
|
The executable and list of arguments
|
||||||
"""
|
"""
|
||||||
# HACK: Works in most case... Trust me i'm an engineer
|
# HACK: Works in most case... Trust me i'm an engineer
|
||||||
|
|
||||||
cmd = cmd.replace("@install_dir", self._install_dir())
|
cmd = cmd.replace("@install_dir", self._install_dir())
|
||||||
cmd = cmd.replace("@path", path.replace(" ", "\ "))
|
cmd = cmd.replace("@path", path.replace(" ", "%20"))
|
||||||
cmd = cmd.replace("@input", self.input_param())
|
cmd = cmd.replace("@input", self.input_param())
|
||||||
|
cmd = cmd.replace("@output", self.output_param())
|
||||||
cmd = cmd.replace("@dir", self._process.workingDirectory())
|
cmd = cmd.replace("@dir", self._process.workingDirectory())
|
||||||
cmd = cmd.replace("@args", " ".join(self.cmd_args(study)))
|
cmd = cmd.replace("@args", " ".join(self.cmd_args(study)))
|
||||||
|
|
||||||
@@ -228,7 +239,7 @@ class AbstractSolver(object):
|
|||||||
if cmd[0] == "\"":
|
if cmd[0] == "\"":
|
||||||
# Command line executable path is between " char
|
# Command line executable path is between " char
|
||||||
cmd = cmd.split("\"")
|
cmd = cmd.split("\"")
|
||||||
exe = cmd[1].replace("\ ", " ")
|
exe = cmd[1].replace("%20", " ")
|
||||||
args = list(
|
args = list(
|
||||||
filter(
|
filter(
|
||||||
lambda s: s != "",
|
lambda s: s != "",
|
||||||
@@ -237,12 +248,12 @@ class AbstractSolver(object):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# We suppose the command line executable path as no space char
|
# We suppose the command line executable path as no space char
|
||||||
cmd = cmd.replace("\ ", "&_&").split(" ")
|
cmd = cmd.replace("\\ ", "&_&").split(" ")
|
||||||
exe = cmd[0].replace("&_&", " ")
|
exe = cmd[0].replace("&_&", " ")
|
||||||
args = list(
|
args = list(
|
||||||
filter(
|
filter(
|
||||||
lambda s: s != "",
|
lambda s: s != "",
|
||||||
map(lambda s: s.replace("&_&", "\ "), cmd[1:])
|
map(lambda s: s.replace("&_&", " "), cmd[1:])
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -284,6 +295,7 @@ class AbstractSolver(object):
|
|||||||
self._process.start(
|
self._process.start(
|
||||||
exe, args,
|
exe, args,
|
||||||
)
|
)
|
||||||
|
self._process.waitForStarted()
|
||||||
|
|
||||||
self._status = STATUS.RUNNING
|
self._status = STATUS.RUNNING
|
||||||
return True
|
return True
|
||||||
@@ -328,14 +340,17 @@ class AbstractSolver(object):
|
|||||||
|
|
||||||
self._run_next(study)
|
self._run_next(study)
|
||||||
|
|
||||||
def run(self, study, process = None, output_queue = None):
|
def run(self, study, process=None, output_queue=None):
|
||||||
|
self._study = study
|
||||||
|
|
||||||
if process is not None:
|
if process is not None:
|
||||||
self._process = process
|
self._process = process
|
||||||
if output_queue is not None:
|
if output_queue is not None:
|
||||||
self._output = output_queue
|
self._output = output_queue
|
||||||
|
|
||||||
self._process.readyRead.connect(self._data_ready)
|
self._process.readyRead.connect(self._data_ready)
|
||||||
self._process.finished.connect(lambda c, s: self._finished(study, c, s))
|
self._process.finished.connect(
|
||||||
|
lambda c, s: self._finished(study, c, s))
|
||||||
|
|
||||||
self._runs = [
|
self._runs = [
|
||||||
self.run_input_data_fomater,
|
self.run_input_data_fomater,
|
||||||
@@ -356,8 +371,9 @@ class AbstractSolver(object):
|
|||||||
self._status = STATUS.STOPED
|
self._status = STATUS.STOPED
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def start(self, study, process = None):
|
def start(self, study, process=None):
|
||||||
if _signal:
|
if _signal:
|
||||||
|
# Solver is PAUSED, so continue execution
|
||||||
if self._status == STATUS.PAUSED:
|
if self._status == STATUS.PAUSED:
|
||||||
os.kill(self._process.pid(), SIGCONT)
|
os.kill(self._process.pid(), SIGCONT)
|
||||||
self._status = STATUS.RUNNING
|
self._status = STATUS.RUNNING
|
||||||
@@ -371,6 +387,7 @@ class AbstractSolver(object):
|
|||||||
if self._process is None:
|
if self._process is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Send SIGSTOP to PAUSED solver
|
||||||
os.kill(self._process.pid(), SIGSTOP)
|
os.kill(self._process.pid(), SIGSTOP)
|
||||||
self._status = STATUS.PAUSED
|
self._status = STATUS.PAUSED
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ from Solver.ASolver import (
|
|||||||
AbstractSolver, STATUS
|
AbstractSolver, STATUS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class GenericSolver(AbstractSolver):
|
class GenericSolver(AbstractSolver):
|
||||||
_type = "generic"
|
_type = "generic"
|
||||||
|
|
||||||
|
|||||||
+107
-58
@@ -30,6 +30,7 @@ from Model.Results.River.River import River, Reach, Profile
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
def mage_file_open(filepath, mode):
|
def mage_file_open(filepath, mode):
|
||||||
f = open(filepath, mode)
|
f = open(filepath, mode)
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ def mage_file_open(filepath, mode):
|
|||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
class Mage(AbstractSolver):
|
class Mage(AbstractSolver):
|
||||||
_type = "mage"
|
_type = "mage"
|
||||||
|
|
||||||
@@ -51,7 +53,6 @@ class Mage(AbstractSolver):
|
|||||||
self._cmd_solver = "@path @input -o @output"
|
self._cmd_solver = "@path @input -o @output"
|
||||||
self._cmd_output = ""
|
self._cmd_output = ""
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default_parameters(cls):
|
def default_parameters(cls):
|
||||||
lst = super(Mage, cls).default_parameters()
|
lst = super(Mage, cls).default_parameters()
|
||||||
@@ -87,8 +88,8 @@ class Mage(AbstractSolver):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def checkers(cls):
|
def checkers(cls):
|
||||||
lst = [
|
lst = [
|
||||||
MageNetworkGraphChecker(connectivity = True),
|
MageNetworkGraphChecker(connectivity=True),
|
||||||
MageNetworkGraphChecker(connectivity = False)
|
MageNetworkGraphChecker(connectivity=False)
|
||||||
]
|
]
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
@@ -98,16 +99,20 @@ class Mage(AbstractSolver):
|
|||||||
##########
|
##########
|
||||||
|
|
||||||
def cmd_args(self, study):
|
def cmd_args(self, study):
|
||||||
l = super(Mage, self).cmd_args(study)
|
lst = super(Mage, self).cmd_args(study)
|
||||||
|
|
||||||
l.append("-r")
|
lst.append("-r")
|
||||||
|
|
||||||
return l
|
return lst
|
||||||
|
|
||||||
def input_param(self):
|
def input_param(self):
|
||||||
name = self._study.name
|
name = self._study.name
|
||||||
return f"{name}.REP"
|
return f"{name}.REP"
|
||||||
|
|
||||||
|
def output_param(self):
|
||||||
|
name = self._study.name
|
||||||
|
return f"{name}.BIN"
|
||||||
|
|
||||||
def log_file(self):
|
def log_file(self):
|
||||||
name = self._study.name
|
name = self._study.name
|
||||||
return f"{name}.TRA"
|
return f"{name}.TRA"
|
||||||
@@ -136,7 +141,10 @@ class Mage(AbstractSolver):
|
|||||||
if edge._name == "":
|
if edge._name == "":
|
||||||
name = f"Reach_{edge.id}"
|
name = f"Reach_{edge.id}"
|
||||||
|
|
||||||
with mage_file_open(os.path.join(repertory, "net", f"{name}.ST"), "w+") as f:
|
with mage_file_open(
|
||||||
|
os.path.join(repertory, "net", f"{name}.ST"),
|
||||||
|
"w+"
|
||||||
|
) as f:
|
||||||
files.append(str(os.path.join("net", f"{name}.ST")))
|
files.append(str(os.path.join("net", f"{name}.ST")))
|
||||||
|
|
||||||
cnt_num = 1
|
cnt_num = 1
|
||||||
@@ -145,42 +153,64 @@ class Mage(AbstractSolver):
|
|||||||
c1 = f"{profile.code1:>6}"
|
c1 = f"{profile.code1:>6}"
|
||||||
c2 = f"{profile.code2:>6}"
|
c2 = f"{profile.code2:>6}"
|
||||||
t = f"{len(profile.points):>6}"
|
t = f"{len(profile.points):>6}"
|
||||||
kp = f"{profile.kp:>13.4f}"
|
kp = f"{profile.kp:>12f}"[0:12]
|
||||||
pname = profile.name
|
pname = profile.name
|
||||||
if profile.name == "":
|
if profile.name == "":
|
||||||
pname = f"p{profile.id:>3}".replace(" ", "p")
|
# Generate name from profile id prefixed with
|
||||||
name = f"{pname}"
|
# 'p' (and replace space char with '0' char)
|
||||||
|
pname = f"p{profile.id:>3}".replace(" ", "0")
|
||||||
|
name = f"{pname:<19}"
|
||||||
|
|
||||||
|
# Generate sediment additional data if available
|
||||||
sediment = ""
|
sediment = ""
|
||||||
if profile.sl is not None:
|
if profile.sl is not None:
|
||||||
if not any(filter(lambda f: ".GRA" in f, files)):
|
if not any(filter(lambda f: ".GRA" in f, files)):
|
||||||
files.append(gra_file)
|
files.append(gra_file)
|
||||||
|
|
||||||
|
# Number of layers
|
||||||
nl = len(profile.sl)
|
nl = len(profile.sl)
|
||||||
sediment = f" {nl:>3}"
|
sediment = f" {nl:>3}"
|
||||||
for l in profile.sl.layers:
|
|
||||||
sediment += f" {l.height:>10} {l.d50:>10} {l.sigma:>10} {l.critical_constraint:>10}"
|
|
||||||
|
|
||||||
f.write(f"{num}{c1}{c2}{t}{kp} {name} {sediment}\n")
|
# Layers data
|
||||||
|
for layer in profile.sl.layers:
|
||||||
|
sediment += (
|
||||||
|
f" {layer.height:>10} {layer.d50:>10} " +
|
||||||
|
f"{layer.sigma:>10} " +
|
||||||
|
f"{layer.critical_constraint:>10}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Profile header line
|
||||||
|
f.write(f"{num}{c1}{c2}{t} {kp} {name} {sediment}\n")
|
||||||
cnt_num += 1
|
cnt_num += 1
|
||||||
|
|
||||||
|
# Points
|
||||||
for point in profile.points:
|
for point in profile.points:
|
||||||
x = f"{point.x:>13.4f}"
|
x = f"{point.x:<12f}"[0:12]
|
||||||
y = f"{point.y:>13.4f}"
|
y = f"{point.y:<12f}"[0:12]
|
||||||
z = f"{point.z:>13.4f}"
|
z = f"{point.z:<12f}"[0:12]
|
||||||
n = f"{point.name:<3}"
|
n = f"{point.name:<3}"
|
||||||
|
|
||||||
|
# Generate sediment additional data if available
|
||||||
sediment = ""
|
sediment = ""
|
||||||
prev = point.z
|
prev = point.z
|
||||||
if point.sl is not None:
|
if point.sl is not None:
|
||||||
|
# Number of layers
|
||||||
nl = len(point.sl)
|
nl = len(point.sl)
|
||||||
sediment = f"{nl:>3}"
|
sediment = f"{nl:>3}"
|
||||||
for l in point.sl.layers:
|
|
||||||
prev = round(prev - l.height, 5)
|
|
||||||
sediment += f" {prev:>10} {l.d50:>10} {l.sigma:>10} {l.critical_constraint:>10}"
|
|
||||||
|
|
||||||
f.write(f"{x}{y}{z} {n} {sediment}\n")
|
# Layers data
|
||||||
|
for layer in point.sl.layers:
|
||||||
|
prev = round(prev - layer.height, 5)
|
||||||
|
sediment += (
|
||||||
|
f" {prev:>10} {layer.d50:>10} " +
|
||||||
|
f"{layer.sigma:>10} " +
|
||||||
|
f"{layer.critical_constraint:>10}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Point line
|
||||||
|
f.write(f"{x} {y} {z} {n} {sediment}\n")
|
||||||
|
|
||||||
|
# Profile last line
|
||||||
f.write(f" 999.9990 999.9990 999.9990\n")
|
f.write(f" 999.9990 999.9990 999.9990\n")
|
||||||
|
|
||||||
return files
|
return files
|
||||||
@@ -210,7 +240,7 @@ class Mage(AbstractSolver):
|
|||||||
v1 = d[1]
|
v1 = d[1]
|
||||||
|
|
||||||
if t in ["HYD", "QSO", "LIM"]:
|
if t in ["HYD", "QSO", "LIM"]:
|
||||||
v0 /= 60 # Convert first column to minute
|
v0 /= 60 # Convert first column to minute
|
||||||
|
|
||||||
f.write(f"{v0:10}{v1:10}\n")
|
f.write(f"{v0:10}{v1:10}\n")
|
||||||
|
|
||||||
@@ -251,7 +281,10 @@ class Mage(AbstractSolver):
|
|||||||
# if qlog is not None:
|
# if qlog is not None:
|
||||||
# qlog.put(f"Export LAT file")
|
# qlog.put(f"Export LAT file")
|
||||||
|
|
||||||
# with mage_file_open(os.path.join(repertory, f"{name}.LAT"), "w+") as f:
|
# with mage_file_open(
|
||||||
|
# os.path.join(repertory, f"{name}.LAT"),
|
||||||
|
# "w+"
|
||||||
|
# ) as f:
|
||||||
# files.append(f"{name}.LAT")
|
# files.append(f"{name}.LAT")
|
||||||
|
|
||||||
# name = f"{lateral.node.id:3}".replace(" ", "x")
|
# name = f"{lateral.node.id:3}".replace(" ", "x")
|
||||||
@@ -391,13 +424,12 @@ class Mage(AbstractSolver):
|
|||||||
if EXT in ["GRA"]:
|
if EXT in ["GRA"]:
|
||||||
f.write(f"{EXT} {file}\n")
|
f.write(f"{EXT} {file}\n")
|
||||||
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def export(self, study, repertory, qlog = None):
|
def export(self, study, repertory, qlog=None):
|
||||||
self._study = study
|
self._study = study
|
||||||
name = study.name.replace(" ", "_")
|
name = study.name.replace(" ", "_")
|
||||||
|
|
||||||
self._export_ST(study, repertory, qlog, name = name)
|
self._export_ST(study, repertory, qlog, name=name)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -405,13 +437,17 @@ class Mage(AbstractSolver):
|
|||||||
# RESULTS #
|
# RESULTS #
|
||||||
###########
|
###########
|
||||||
|
|
||||||
def read_bin(self, study, repertory, results, qlog = None, name="0"):
|
def read_bin(self, study, repertory, results, qlog=None, name="0"):
|
||||||
return
|
return
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def results(self, study, repertory, qlog = None, name="0"):
|
def results(self, study, repertory, qlog=None, name="0"):
|
||||||
results = Results(study = study)
|
results = Results(
|
||||||
|
study=study,
|
||||||
|
solver=self,
|
||||||
|
repertory=repertory,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
self.read_bin(study, repertory, results, qlog, name=name)
|
self.read_bin(study, repertory, results, qlog, name=name)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -420,6 +456,7 @@ class Mage(AbstractSolver):
|
|||||||
# MAGE 7 #
|
# MAGE 7 #
|
||||||
##########
|
##########
|
||||||
|
|
||||||
|
|
||||||
class Mage7(Mage):
|
class Mage7(Mage):
|
||||||
_type = "mage7"
|
_type = "mage7"
|
||||||
|
|
||||||
@@ -438,6 +475,7 @@ class Mage7(Mage):
|
|||||||
# MAGE 8 #
|
# MAGE 8 #
|
||||||
##########
|
##########
|
||||||
|
|
||||||
|
|
||||||
class Mage8(Mage):
|
class Mage8(Mage):
|
||||||
_type = "mage8"
|
_type = "mage8"
|
||||||
|
|
||||||
@@ -476,15 +514,15 @@ class Mage8(Mage):
|
|||||||
##########
|
##########
|
||||||
|
|
||||||
def cmd_args(self, study):
|
def cmd_args(self, study):
|
||||||
l = super(Mage8, self).cmd_args(study)
|
lst = super(Mage8, self).cmd_args(study)
|
||||||
|
|
||||||
if study.river.has_sediment():
|
if study.river.has_sediment():
|
||||||
l.append("-c=3")
|
lst.append("-c=3")
|
||||||
|
|
||||||
return l
|
return lst
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def _export_PAR(self, study, repertory, qlog = None, name = "0"):
|
def _export_PAR(self, study, repertory, qlog=None, name="0"):
|
||||||
files = []
|
files = []
|
||||||
|
|
||||||
if qlog is not None:
|
if qlog is not None:
|
||||||
@@ -503,7 +541,7 @@ class Mage8(Mage):
|
|||||||
if name in ["command_line_arguments"]:
|
if name in ["command_line_arguments"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if name is "mage_compute_reach_volume_balance":
|
if name == "mage_compute_reach_volume_balance":
|
||||||
value = "O" if value == "y" else "N"
|
value = "O" if value == "y" else "N"
|
||||||
|
|
||||||
f.write(f"{name} {value}\n")
|
f.write(f"{name} {value}\n")
|
||||||
@@ -511,7 +549,7 @@ class Mage8(Mage):
|
|||||||
return files
|
return files
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def _export_NET(self, study, repertory, qlog = None, name="0"):
|
def _export_NET(self, study, repertory, qlog=None, name="0"):
|
||||||
files = []
|
files = []
|
||||||
|
|
||||||
if qlog is not None:
|
if qlog is not None:
|
||||||
@@ -579,9 +617,8 @@ class Mage8(Mage):
|
|||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def export(self, study, repertory, qlog = None, name="0"):
|
def export(self, study, repertory, qlog=None, name="0"):
|
||||||
self._study = study
|
self._study = study
|
||||||
name = study.name.replace(" ", "_")
|
name = study.name.replace(" ", "_")
|
||||||
|
|
||||||
@@ -590,7 +627,8 @@ class Mage8(Mage):
|
|||||||
files = self._export_ST(study, repertory, qlog, name=name)
|
files = self._export_ST(study, repertory, qlog, name=name)
|
||||||
files = files + self._export_PAR(study, repertory, qlog, name=name)
|
files = files + self._export_PAR(study, repertory, qlog, name=name)
|
||||||
files = files + self._export_NET(study, repertory, qlog, name=name)
|
files = files + self._export_NET(study, repertory, qlog, name=name)
|
||||||
files = files + self._export_bound_cond(study, repertory, qlog, name=name)
|
files = files + \
|
||||||
|
self._export_bound_cond(study, repertory, qlog, name=name)
|
||||||
files = files + self._export_RUG(study, repertory, qlog, name=name)
|
files = files + self._export_RUG(study, repertory, qlog, name=name)
|
||||||
files = files + self._export_INI(study, repertory, qlog, name=name)
|
files = files + self._export_INI(study, repertory, qlog, name=name)
|
||||||
self._export_REP(study, repertory, files, qlog, name=name)
|
self._export_REP(study, repertory, files, qlog, name=name)
|
||||||
@@ -602,17 +640,22 @@ class Mage8(Mage):
|
|||||||
###########
|
###########
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def read_bin(self, study, repertory, results, qlog = None, name="0"):
|
def read_bin(self, study, repertory, results, qlog=None, name="0"):
|
||||||
fname = os.path.join(repertory, f"{name}.BIN")
|
fname = os.path.join(repertory, f"{name}.BIN")
|
||||||
logger.info(f"read_bin: Start reading '{fname}' ...")
|
logger.info(f"read_bin: Start reading '{fname}' ...")
|
||||||
|
|
||||||
with mage_file_open(fname, "r") as f:
|
with mage_file_open(fname, "r") as f:
|
||||||
newline = lambda: np.fromfile(f, dtype=np.int32, count=1)
|
def newline(): return np.fromfile(f, dtype=np.int32, count=1)
|
||||||
endline = lambda: np.fromfile(f, dtype=np.int32, count=1)
|
def endline(): return np.fromfile(f, dtype=np.int32, count=1)
|
||||||
|
|
||||||
read_int = lambda size: np.fromfile(f, dtype=np.int32, count=size)
|
def read_int(size): return np.fromfile(
|
||||||
read_float = lambda size: np.fromfile(f, dtype=np.float32, count=size)
|
f, dtype=np.int32, count=size)
|
||||||
read_float64 = lambda size: np.fromfile(f, dtype=np.float64, count=size)
|
|
||||||
|
def read_float(size): return np.fromfile(
|
||||||
|
f, dtype=np.float32, count=size)
|
||||||
|
|
||||||
|
def read_float64(size): return np.fromfile(
|
||||||
|
f, dtype=np.float64, count=size)
|
||||||
|
|
||||||
# Meta data (1st line)
|
# Meta data (1st line)
|
||||||
newline()
|
newline()
|
||||||
@@ -686,7 +729,7 @@ class Mage8(Mage):
|
|||||||
# Data
|
# Data
|
||||||
newline()
|
newline()
|
||||||
|
|
||||||
ip_to_r = lambda i: iprofiles[
|
def ip_to_r(i): return iprofiles[
|
||||||
next(
|
next(
|
||||||
filter(
|
filter(
|
||||||
lambda k: k[0] <= i <= k[1],
|
lambda k: k[0] <= i <= k[1],
|
||||||
@@ -694,14 +737,15 @@ class Mage8(Mage):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
ip_to_ri = lambda r, i: i - reach_offset[r]
|
def ip_to_ri(r, i): return i - reach_offset[r]
|
||||||
|
|
||||||
ts = set()
|
ts = set()
|
||||||
end = False
|
end = False
|
||||||
while not end:
|
while not end:
|
||||||
n = read_int(1)[0]
|
n = read_int(1)[0]
|
||||||
timestamp = read_float64(1)[0]
|
timestamp = read_float64(1)[0]
|
||||||
key = bytearray(np.fromfile(f, dtype=np.byte, count=1)).decode()
|
key = bytearray(np.fromfile(
|
||||||
|
f, dtype=np.byte, count=1)).decode()
|
||||||
data = read_float(n)
|
data = read_float(n)
|
||||||
|
|
||||||
logger.debug(f"read_bin: timestamp = {timestamp} sec")
|
logger.debug(f"read_bin: timestamp = {timestamp} sec")
|
||||||
@@ -725,7 +769,7 @@ class Mage8(Mage):
|
|||||||
logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
|
logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def read_gra(self, study, repertory, results, qlog = None, name="0"):
|
def read_gra(self, study, repertory, results, qlog=None, name="0"):
|
||||||
if not study.river.has_sediment():
|
if not study.river.has_sediment():
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -733,12 +777,17 @@ class Mage8(Mage):
|
|||||||
logger.info(f"read_gra: Start reading '{fname}' ...")
|
logger.info(f"read_gra: Start reading '{fname}' ...")
|
||||||
|
|
||||||
with mage_file_open(fname, "r") as f:
|
with mage_file_open(fname, "r") as f:
|
||||||
newline = lambda: np.fromfile(f, dtype=np.int32, count=1)
|
def newline(): return np.fromfile(f, dtype=np.int32, count=1)
|
||||||
endline = lambda: np.fromfile(f, dtype=np.int32, count=1)
|
def endline(): return np.fromfile(f, dtype=np.int32, count=1)
|
||||||
|
|
||||||
read_int = lambda size: np.fromfile(f, dtype=np.int32, count=size)
|
def read_int(size): return np.fromfile(
|
||||||
read_float = lambda size: np.fromfile(f, dtype=np.float32, count=size)
|
f, dtype=np.int32, count=size)
|
||||||
read_float64 = lambda size: np.fromfile(f, dtype=np.float64, count=size)
|
|
||||||
|
def read_float(size): return np.fromfile(
|
||||||
|
f, dtype=np.float32, count=size)
|
||||||
|
|
||||||
|
def read_float64(size): return np.fromfile(
|
||||||
|
f, dtype=np.float64, count=size)
|
||||||
|
|
||||||
# Meta data (1st line)
|
# Meta data (1st line)
|
||||||
newline()
|
newline()
|
||||||
@@ -810,7 +859,7 @@ class Mage8(Mage):
|
|||||||
endline()
|
endline()
|
||||||
|
|
||||||
# Data
|
# Data
|
||||||
ip_to_r = lambda i: iprofiles[
|
def ip_to_r(i): return iprofiles[
|
||||||
next(
|
next(
|
||||||
filter(
|
filter(
|
||||||
lambda k: k[0] <= i <= k[1],
|
lambda k: k[0] <= i <= k[1],
|
||||||
@@ -818,7 +867,7 @@ class Mage8(Mage):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
ip_to_ri = lambda r, i: i - reach_offset[r]
|
def ip_to_ri(r, i): return i - reach_offset[r]
|
||||||
|
|
||||||
ts = set()
|
ts = set()
|
||||||
ind = 0
|
ind = 0
|
||||||
@@ -878,11 +927,11 @@ class Mage8(Mage):
|
|||||||
logger.info(f"read_gra: ... end with {len(ts)} timestamp read")
|
logger.info(f"read_gra: ... end with {len(ts)} timestamp read")
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def results(self, study, repertory, qlog = None):
|
def results(self, study, repertory, qlog=None):
|
||||||
self._study = study
|
self._study = study
|
||||||
name = study.name.replace(" ", "_")
|
name = study.name.replace(" ", "_")
|
||||||
|
|
||||||
results = super(Mage8, self).results(study, repertory, qlog, name = name)
|
results = super(Mage8, self).results(study, repertory, qlog, name=name)
|
||||||
self.read_gra(study, repertory, results, qlog, name = name)
|
self.read_gra(study, repertory, results, qlog, name=name)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -24,9 +24,9 @@ from Solver.Mage import Mage7, Mage8
|
|||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
solver_long_name = {
|
solver_long_name = {
|
||||||
"generic": _translate("Solvers", "Generic"),
|
"generic": "Generic",
|
||||||
# "mage7": _translate("Solvers", "Mage version 7"),
|
# "mage7": "Mage v7",
|
||||||
"mage8": _translate("Solvers", "Mage version 8"),
|
"mage8": "Mage v8",
|
||||||
}
|
}
|
||||||
|
|
||||||
solver_type_list = {
|
solver_type_list = {
|
||||||
|
|||||||
@@ -19,14 +19,18 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from View.ASubWindow import ASubWindow
|
from View.Tools.PamhyrWindow import PamhyrDialog
|
||||||
|
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class AboutWindow(ASubWindow):
|
|
||||||
|
class AboutWindow(PamhyrDialog):
|
||||||
|
_pamhyr_ui = "about"
|
||||||
|
_pamhyr_name = "About"
|
||||||
|
|
||||||
def _path_file(self, filename):
|
def _path_file(self, filename):
|
||||||
return os.path.abspath(
|
return os.path.abspath(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
@@ -35,10 +39,14 @@ class AboutWindow(ASubWindow):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __init__(self, study=None, config=None, parent=None):
|
||||||
def __init__(self, title="About", parent=None):
|
super(AboutWindow, self).__init__(
|
||||||
super(AboutWindow, self).__init__(name=title, ui="about", parent=parent)
|
title=_translate("About", "About"),
|
||||||
self.ui.setWindowTitle(title)
|
study=study,
|
||||||
|
config=config,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
with open(self._path_file("VERSION"), "r") as f:
|
with open(self._path_file("VERSION"), "r") as f:
|
||||||
|
|||||||
@@ -21,27 +21,32 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from tools import timer, trace
|
from tools import timer, trace
|
||||||
from View.Plot.APlot import APlot
|
from View.Tools.PamhyrPlot import PamhyrPlot
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
QCoreApplication
|
QCoreApplication
|
||||||
)
|
)
|
||||||
|
|
||||||
from View.BoundaryCondition.Edit.translate import *
|
from View.BoundaryCondition.Edit.translate import BCETranslate
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class Plot(APlot):
|
|
||||||
def __init__(self, canvas=None, data=None,
|
class Plot(PamhyrPlot):
|
||||||
mode = "time", toolbar=None):
|
def __init__(self, mode="time", data=None,
|
||||||
|
trad=None, canvas=None, toolbar=None,
|
||||||
|
parent=None):
|
||||||
super(Plot, self).__init__(
|
super(Plot, self).__init__(
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
|
trad=trad,
|
||||||
data=data,
|
data=data,
|
||||||
toolbar=toolbar
|
toolbar=toolbar,
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._table_headers = self._trad.get_dict("table_headers")
|
||||||
self._mode = mode
|
self._mode = mode
|
||||||
|
|
||||||
def custom_ticks(self):
|
def custom_ticks(self):
|
||||||
@@ -68,8 +73,8 @@ class Plot(APlot):
|
|||||||
map(
|
map(
|
||||||
lambda v: str(
|
lambda v: str(
|
||||||
datetime.fromtimestamp(v[0]) - t0
|
datetime.fromtimestamp(v[0]) - t0
|
||||||
).split(",")[0]\
|
).split(",")[0]
|
||||||
.replace("days", _translate("BoundaryCondition", "days"))\
|
.replace("days", _translate("BoundaryCondition", "days"))
|
||||||
.replace("day", _translate("BoundaryCondition", "day")),
|
.replace("day", _translate("BoundaryCondition", "day")),
|
||||||
fx
|
fx
|
||||||
)
|
)
|
||||||
@@ -84,7 +89,6 @@ class Plot(APlot):
|
|||||||
|
|
||||||
self.canvas.axes.set_xticks(ticks=xx, labels=xt, rotation=45)
|
self.canvas.axes.set_xticks(ticks=xx, labels=xt, rotation=45)
|
||||||
|
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def draw(self):
|
def draw(self):
|
||||||
self.canvas.axes.cla()
|
self.canvas.axes.cla()
|
||||||
@@ -109,22 +113,22 @@ class Plot(APlot):
|
|||||||
# Plot label
|
# Plot label
|
||||||
header = self.data.header
|
header = self.data.header
|
||||||
self.canvas.axes.set_xlabel(
|
self.canvas.axes.set_xlabel(
|
||||||
table_headers[header[0]], color='black', fontsize=10
|
self._table_headers[header[0]], color='black', fontsize=10
|
||||||
)
|
)
|
||||||
self.canvas.axes.set_ylabel(
|
self.canvas.axes.set_ylabel(
|
||||||
table_headers[header[1]], color='black', fontsize=10
|
self._table_headers[header[1]], color='black', fontsize=10
|
||||||
)
|
)
|
||||||
|
|
||||||
self.canvas.axes.autoscale_view(True, True, True)
|
self.canvas.axes.autoscale_view(True, True, True)
|
||||||
self.canvas.figure.tight_layout()
|
self.canvas.figure.tight_layout()
|
||||||
self.canvas.figure.canvas.draw_idle()
|
self.canvas.figure.canvas.draw_idle()
|
||||||
#self.toolbar.update()
|
# self.toolbar.update()
|
||||||
|
|
||||||
self._init = True
|
self._init = True
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def update(self, ind=None):
|
def update(self, ind=None):
|
||||||
if self._init == False:
|
if not self._init:
|
||||||
self.draw()
|
self.draw()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ from datetime import date, time, datetime, timedelta
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow, AWidget
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
|
||||||
|
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
Qt, QVariant, QAbstractTableModel,
|
Qt, QVariant, QAbstractTableModel,
|
||||||
@@ -47,131 +46,13 @@ from View.BoundaryCondition.Edit.UndoCommand import (
|
|||||||
SortCommand, MoveCommand, PasteCommand,
|
SortCommand, MoveCommand, PasteCommand,
|
||||||
DuplicateCommand,
|
DuplicateCommand,
|
||||||
)
|
)
|
||||||
from View.BoundaryCondition.Edit.translate import *
|
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class ExtendedTimeEdit(AWidget):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(ExtendedTimeEdit, self).__init__(
|
|
||||||
ui="extendedTimeEdit",
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.spinBox_days = self.find(QSpinBox, "spinBox_days")
|
|
||||||
self.timeEdit = self.find(QTimeEdit, "timeEdit")
|
|
||||||
|
|
||||||
def set_time(self, time):
|
|
||||||
days = 0
|
|
||||||
stime = time
|
|
||||||
|
|
||||||
# if ',' in time, time format is 'DD days, HH:MM:SS',
|
|
||||||
# otherelse is 'HH:MM:SS'
|
|
||||||
if "," in time:
|
|
||||||
s = time.strip().split(" ")
|
|
||||||
days = int(s[0])
|
|
||||||
stime = s[-1]
|
|
||||||
|
|
||||||
qtime = QTime.fromString(
|
|
||||||
stime,
|
|
||||||
"h:mm:ss"
|
|
||||||
)
|
|
||||||
self.spinBox_days.setValue(days)
|
|
||||||
self.timeEdit.setTime(qtime)
|
|
||||||
|
|
||||||
def get_time(self):
|
|
||||||
days = self.spinBox_days.value()
|
|
||||||
time = self.timeEdit.time().toPyTime()
|
|
||||||
secs = (
|
|
||||||
(time.hour * 3600) +
|
|
||||||
(time.minute * 60) +
|
|
||||||
time.second
|
|
||||||
)
|
|
||||||
|
|
||||||
return timedelta(days=days, seconds=secs)
|
|
||||||
|
|
||||||
class ExtendedDateTimeEdit(AWidget):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(ExtendedDateTimeEdit, self).__init__(
|
|
||||||
ui="extendedDateTimeEdit",
|
|
||||||
parent=parent
|
|
||||||
)
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.dateTimeEdit = self.find(QDateTimeEdit, "dateTimeEdit")
|
|
||||||
|
|
||||||
def set_time(self, time):
|
|
||||||
qdatetime = QDateTime.fromString(
|
|
||||||
time,
|
|
||||||
"yyyy-MM-dd hh:mm:ss"
|
|
||||||
)
|
|
||||||
self.dateTimeEdit.setDateTime(qdatetime)
|
|
||||||
|
|
||||||
def get_time(self):
|
|
||||||
time = self.dateTimeEdit.dateTime().toPyDateTime()
|
|
||||||
return time
|
|
||||||
|
|
||||||
class ExTimeDelegate(QItemDelegate):
|
|
||||||
def __init__(self, data=None, mode="time", parent=None):
|
|
||||||
super(ExTimeDelegate, self).__init__(parent)
|
|
||||||
|
|
||||||
self._data = data
|
|
||||||
self._mode = mode
|
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
|
||||||
if self._mode == "time":
|
|
||||||
self.editor = ExtendedTimeEdit(parent=parent)
|
|
||||||
else:
|
|
||||||
self.editor = ExtendedDateTimeEdit(parent=parent)
|
|
||||||
value = index.data(Qt.DisplayRole)
|
|
||||||
self.editor.set_time(value)
|
|
||||||
logger.debug(str(value))
|
|
||||||
return self.editor
|
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
|
||||||
time = editor.get_time()
|
|
||||||
if self._mode == "time":
|
|
||||||
model.setData(index, int(time.total_seconds()))
|
|
||||||
else:
|
|
||||||
logger.debug(str(time.timestamp()))
|
|
||||||
model.setData(index, int(time.timestamp()))
|
|
||||||
editor.close()
|
|
||||||
editor.deleteLater()
|
|
||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
|
||||||
r = QRect(option.rect)
|
|
||||||
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
|
||||||
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
|
||||||
editor.setGeometry(r)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def currentItemChanged(self):
|
|
||||||
self.commitData.emit(self.sender())
|
|
||||||
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
|
||||||
def __init__(self, data=None, mode="time", undo=None):
|
|
||||||
super(QAbstractTableModel, self).__init__()
|
|
||||||
self._headers = data.header
|
|
||||||
self._data = data
|
|
||||||
self._mode = mode
|
|
||||||
self._undo = undo
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
options |= Qt.ItemIsEditable
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self._data)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
|
class TableModel(PamhyrTableModel):
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role == Qt.TextAlignmentRole:
|
if role == Qt.TextAlignmentRole:
|
||||||
return Qt.AlignHCenter | Qt.AlignVCenter
|
return Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
@@ -189,7 +70,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
if self._data.get_type_column(column) == float:
|
if self._data.get_type_column(column) == float:
|
||||||
value = f"{v:.4f}"
|
value = f"{v:.4f}"
|
||||||
elif self._data.header[column] == "time":
|
elif self._data.header[column] == "time":
|
||||||
if self._mode == "time":
|
if self._opt_data == "time":
|
||||||
t0 = datetime.fromtimestamp(0)
|
t0 = datetime.fromtimestamp(0)
|
||||||
t = datetime.fromtimestamp(v)
|
t = datetime.fromtimestamp(v)
|
||||||
value = str(t - t0)
|
value = str(t - t0)
|
||||||
@@ -200,12 +81,6 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return table_headers[self._headers[section]]
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if not index.isValid() or role != Qt.EditRole:
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
return False
|
return False
|
||||||
@@ -315,12 +190,3 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
def undo(self):
|
|
||||||
self._undo.undo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
|
|
||||||
def redo(self):
|
|
||||||
self._undo.redo()
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
@@ -29,6 +29,7 @@ from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class SetDataCommand(QUndoCommand):
|
class SetDataCommand(QUndoCommand):
|
||||||
def __init__(self, data, index, column, new_value):
|
def __init__(self, data, index, column, new_value):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -46,6 +47,7 @@ class SetDataCommand(QUndoCommand):
|
|||||||
def redo(self):
|
def redo(self):
|
||||||
self._data._set_i_c_v(self._index, self._column, self._new)
|
self._data._set_i_c_v(self._index, self._column, self._new)
|
||||||
|
|
||||||
|
|
||||||
class SetMetaDataCommand(QUndoCommand):
|
class SetMetaDataCommand(QUndoCommand):
|
||||||
def __init__(self, data, column, new_value):
|
def __init__(self, data, column, new_value):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -89,6 +91,7 @@ class AddCommand(QUndoCommand):
|
|||||||
else:
|
else:
|
||||||
self._data.insert(self._index, self._new)
|
self._data.insert(self._index, self._new)
|
||||||
|
|
||||||
|
|
||||||
class DelCommand(QUndoCommand):
|
class DelCommand(QUndoCommand):
|
||||||
def __init__(self, data, rows):
|
def __init__(self, data, rows):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -108,6 +111,7 @@ class DelCommand(QUndoCommand):
|
|||||||
def redo(self):
|
def redo(self):
|
||||||
self._data.delete_i(self._rows)
|
self._data.delete_i(self._rows)
|
||||||
|
|
||||||
|
|
||||||
class SortCommand(QUndoCommand):
|
class SortCommand(QUndoCommand):
|
||||||
def __init__(self, data, _reverse):
|
def __init__(self, data, _reverse):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|||||||
@@ -16,10 +16,13 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from tools import timer, trace
|
from tools import timer, trace
|
||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow, AWidget
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
from View.Tools.PamhyrWidget import PamhyrWidget
|
||||||
|
from View.Tools.PamhyrDelegate import PamhyrExTimeDelegate
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
@@ -38,26 +41,29 @@ from PyQt5.QtWidgets import (
|
|||||||
QHeaderView, QDoubleSpinBox, QVBoxLayout,
|
QHeaderView, QDoubleSpinBox, QVBoxLayout,
|
||||||
)
|
)
|
||||||
|
|
||||||
from View.Plot.MplCanvas import MplCanvas
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
from View.Plot.navigation_toolbar_2qt import PamHyrNavigationToolbar2QT
|
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
|
||||||
from View.BoundaryCondition.translate import long_types
|
from View.BoundaryCondition.Edit.translate import BCETranslate
|
||||||
from View.BoundaryCondition.Edit.UndoCommand import SetMetaDataCommand
|
from View.BoundaryCondition.Edit.UndoCommand import SetMetaDataCommand
|
||||||
from View.BoundaryCondition.Edit.Table import TableModel, ExTimeDelegate
|
from View.BoundaryCondition.Edit.Table import TableModel
|
||||||
from View.BoundaryCondition.Edit.Plot import Plot
|
from View.BoundaryCondition.Edit.Plot import Plot
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
class WD50Sigma(AWidget):
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class WD50Sigma(PamhyrWidget):
|
||||||
|
_pamhyr_ui = "d50sigma"
|
||||||
|
|
||||||
d50Changed = pyqtSignal(float)
|
d50Changed = pyqtSignal(float)
|
||||||
sigmaChanged = pyqtSignal(float)
|
sigmaChanged = pyqtSignal(float)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(WD50Sigma, self).__init__(
|
super(WD50Sigma, self).__init__(
|
||||||
ui="d50sigma",
|
|
||||||
parent=parent
|
parent=parent
|
||||||
)
|
)
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.spinBox_d50 = self.find(QDoubleSpinBox, "doubleSpinBox_d50")
|
self.spinBox_d50 = self.find(QDoubleSpinBox, "doubleSpinBox_d50")
|
||||||
self.spinBox_sigma = self.find(QDoubleSpinBox, "doubleSpinBox_sigma")
|
self.spinBox_sigma = self.find(QDoubleSpinBox, "doubleSpinBox_sigma")
|
||||||
@@ -89,75 +95,77 @@ class WD50Sigma(AWidget):
|
|||||||
def valueChangedSigma(self, value):
|
def valueChangedSigma(self, value):
|
||||||
self.sigmaChanged.emit(value)
|
self.sigmaChanged.emit(value)
|
||||||
|
|
||||||
class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|
||||||
def __init__(self, title="Edit boundary condition",
|
|
||||||
data=None, study=None, parent=None):
|
|
||||||
self._data = data
|
|
||||||
self._study = study
|
|
||||||
self._title = title
|
|
||||||
|
|
||||||
self.compute_title()
|
class EditBoundaryConditionWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "EditBoundaryConditions"
|
||||||
|
_pamhyr_name = "Edit Boundary Conditions"
|
||||||
|
|
||||||
|
def __init__(self, data=None, study=None, config=None, parent=None):
|
||||||
|
self._data = data
|
||||||
|
trad = BCETranslate()
|
||||||
|
self._long_types = trad.get_dict("long_types")
|
||||||
|
|
||||||
|
name = self._pamhyr_name
|
||||||
|
if self._data is not None:
|
||||||
|
node_name = (self._data.node.name if self._data.node is not None
|
||||||
|
else _translate("BoundaryCondition", "Not associate"))
|
||||||
|
name = (
|
||||||
|
_translate("Edit boundary condition", self._pamhyr_name) +
|
||||||
|
f" - {study.name} " +
|
||||||
|
f" - {self._data.name} ({self._data.id}) " +
|
||||||
|
f"({self._long_types[self._data.bctype]} - {node_name})"
|
||||||
|
)
|
||||||
|
|
||||||
super(EditBoundaryConditionWindow, self).__init__(
|
super(EditBoundaryConditionWindow, self).__init__(
|
||||||
name=self._title, ui="EditBoundaryConditions", parent=parent
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=trad,
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
self.ui.setWindowTitle(self._title)
|
self._hash_data.append(data)
|
||||||
|
|
||||||
self.setup_sc()
|
|
||||||
self.setup_table()
|
self.setup_table()
|
||||||
self.setup_plot()
|
self.setup_plot()
|
||||||
self.setup_data()
|
self.setup_data()
|
||||||
self.setup_connections()
|
self.setup_connections()
|
||||||
|
|
||||||
def compute_title(self):
|
|
||||||
if self._data is not None:
|
|
||||||
node_name = (self._data.node.name if self._data.node is not None
|
|
||||||
else _translate("BoundaryCondition", "Not associate"))
|
|
||||||
self._title = (
|
|
||||||
_translate("Edit boundary condition", self._title) +
|
|
||||||
f" - {self._study.name} " +
|
|
||||||
f" - {self._data.name} ({self._data.id}) " +
|
|
||||||
f"({long_types[self._data.bctype]} - {node_name})"
|
|
||||||
)
|
|
||||||
|
|
||||||
def setup_sc(self):
|
|
||||||
self._undo_stack = QUndoStack()
|
|
||||||
|
|
||||||
self.undo_sc = QShortcut(QKeySequence.Undo, self)
|
|
||||||
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
|
||||||
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
|
||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
|
||||||
|
|
||||||
def setup_data(self):
|
def setup_data(self):
|
||||||
self._is_solid = self._data.bctype == "SL"
|
self._is_solid = self._data.bctype == "SL"
|
||||||
|
|
||||||
if self._is_solid:
|
if self._is_solid:
|
||||||
layout = self.find(QVBoxLayout, "verticalLayout_table")
|
layout = self.find(QVBoxLayout, "verticalLayout_table")
|
||||||
self._d50sigma = WD50Sigma(parent = self)
|
self._d50sigma = WD50Sigma(parent=self)
|
||||||
layout.addWidget(self._d50sigma)
|
layout.addWidget(self._d50sigma)
|
||||||
|
|
||||||
self._d50sigma.set_d50(self._data.d50)
|
self._d50sigma.set_d50(self._data.d50)
|
||||||
self._d50sigma.set_sigma(self._data.sigma)
|
self._d50sigma.set_sigma(self._data.sigma)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
table = self.find(QTableView, "tableView")
|
headers = {}
|
||||||
self._table = TableModel(
|
table_headers = self._trad.get_dict("table_headers")
|
||||||
data = self._data,
|
for h in self._data.header:
|
||||||
undo = self._undo_stack,
|
headers[h] = table_headers[h]
|
||||||
mode = self._study.time_system
|
|
||||||
|
self._delegate_time = PamhyrExTimeDelegate(
|
||||||
|
data=self._data,
|
||||||
|
mode=self._study.time_system,
|
||||||
|
parent=self
|
||||||
)
|
)
|
||||||
|
|
||||||
if self._data.header[0] == "time":
|
table = self.find(QTableView, "tableView")
|
||||||
self._delegate_time = ExTimeDelegate(
|
self._table = TableModel(
|
||||||
data = self._data,
|
table_view=table,
|
||||||
mode = self._study.time_system,
|
table_headers=headers,
|
||||||
parent = self
|
editable_headers=self._data.header,
|
||||||
)
|
delegates={
|
||||||
|
"time": self._delegate_time,
|
||||||
table.setItemDelegateForColumn(
|
},
|
||||||
0, self._delegate_time
|
data=self._data,
|
||||||
)
|
undo=self._undo_stack,
|
||||||
|
opt_data=self._study.time_system
|
||||||
|
)
|
||||||
|
|
||||||
table.setModel(self._table)
|
table.setModel(self._table)
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
@@ -167,31 +175,26 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_plot(self):
|
def setup_plot(self):
|
||||||
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
self.canvas.setObjectName("canvas")
|
self.canvas.setObjectName("canvas")
|
||||||
self.toolbar = PamHyrNavigationToolbar2QT(
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
self.canvas, self
|
self.canvas, self
|
||||||
)
|
)
|
||||||
self.verticalLayout.addWidget(self.toolbar)
|
self.verticalLayout.addWidget(self.toolbar)
|
||||||
self.verticalLayout.addWidget(self.canvas)
|
self.verticalLayout.addWidget(self.canvas)
|
||||||
|
|
||||||
self.plot = Plot(
|
self.plot = Plot(
|
||||||
canvas = self.canvas,
|
canvas=self.canvas,
|
||||||
data = self._data,
|
data=self._data,
|
||||||
mode = self._study.time_system,
|
mode=self._study.time_system,
|
||||||
toolbar = self.toolbar,
|
trad=self._trad,
|
||||||
|
toolbar=self.toolbar,
|
||||||
)
|
)
|
||||||
self.plot.draw()
|
self.plot.draw()
|
||||||
|
|
||||||
|
|
||||||
def setup_connections(self):
|
def setup_connections(self):
|
||||||
self.find(QAction, "action_add").triggered.connect(self.add)
|
self.find(QAction, "action_add").triggered.connect(self.add)
|
||||||
self.find(QAction, "action_del").triggered.connect(self.delete)
|
self.find(QAction, "action_del").triggered.connect(self.delete)
|
||||||
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
||||||
|
|
||||||
self.undo_sc.activated.connect(self.undo)
|
|
||||||
self.redo_sc.activated.connect(self.redo)
|
|
||||||
self.copy_sc.activated.connect(self.copy)
|
|
||||||
self.paste_sc.activated.connect(self.paste)
|
|
||||||
|
|
||||||
self._table.dataChanged.connect(self.update)
|
self._table.dataChanged.connect(self.update)
|
||||||
|
|
||||||
if self._is_solid:
|
if self._is_solid:
|
||||||
@@ -240,7 +243,6 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def add(self):
|
def add(self):
|
||||||
rows = self.index_selected_rows()
|
rows = self.index_selected_rows()
|
||||||
if len(self._data) == 0 or len(rows) == 0:
|
if len(self._data) == 0 or len(rows) == 0:
|
||||||
@@ -272,8 +274,7 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self._table.move_down(row)
|
self._table.move_down(row)
|
||||||
self.plot.update()
|
self.plot.update()
|
||||||
|
|
||||||
|
def _copy(self):
|
||||||
def copy(self):
|
|
||||||
rows = self.index_selected_rows()
|
rows = self.index_selected_rows()
|
||||||
|
|
||||||
table = []
|
table = []
|
||||||
@@ -285,7 +286,7 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.copyTableIntoClipboard(table)
|
self.copyTableIntoClipboard(table)
|
||||||
|
|
||||||
def paste(self):
|
def _paste(self):
|
||||||
header, data = self.parseClipboardTable()
|
header, data = self.parseClipboardTable()
|
||||||
|
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
@@ -299,12 +300,12 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self._table.paste(row, header, data)
|
self._table.paste(row, header, data)
|
||||||
self.plot.update()
|
self.plot.update()
|
||||||
|
|
||||||
def undo(self):
|
def _undo(self):
|
||||||
self._table.undo()
|
self._table.undo()
|
||||||
self.plot.update()
|
self.plot.update()
|
||||||
self.widget_update()
|
self.widget_update()
|
||||||
|
|
||||||
def redo(self):
|
def _redo(self):
|
||||||
self._table.redo()
|
self._table.redo()
|
||||||
self.plot.update()
|
self.plot.update()
|
||||||
self.widget_update()
|
self.widget_update()
|
||||||
@@ -18,14 +18,23 @@
|
|||||||
|
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||||
|
|
||||||
|
from View.BoundaryCondition.translate import BCTranslate
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
table_headers = {
|
|
||||||
"x": _translate("BoundaryCondition", "X"),
|
class BCETranslate(BCTranslate):
|
||||||
"y": _translate("BoundaryCondition", "Y"),
|
def __init__(self):
|
||||||
"time": _translate("BoundaryCondition", "Time"),
|
super(BCETranslate, self).__init__()
|
||||||
"date": _translate("BoundaryCondition", "Date"),
|
|
||||||
"discharge": _translate("BoundaryCondition", "Discharge (m³/s)"),
|
self._sub_dict["table_headers"] = {
|
||||||
"z": _translate("BoundaryCondition", "Z (m)"),
|
"x": _translate("BoundaryCondition", "X"),
|
||||||
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
|
"y": _translate("BoundaryCondition", "Y"),
|
||||||
}
|
"time": _translate("BoundaryCondition", "Time"),
|
||||||
|
"date": _translate("BoundaryCondition", "Date"),
|
||||||
|
"discharge": _translate("BoundaryCondition", "Discharge (m³/s)"),
|
||||||
|
"z": _translate("BoundaryCondition", "Z (m)"),
|
||||||
|
"solid": _translate("BoundaryCondition", "Solid (kg/s)"),
|
||||||
|
}
|
||||||
@@ -39,24 +39,33 @@ from Model.BoundaryCondition.BoundaryConditionTypes import (
|
|||||||
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
TimeOverZ, TimeOverDischarge, ZOverDischarge
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from View.BoundaryCondition.UndoCommand import (
|
from View.BoundaryCondition.UndoCommand import (
|
||||||
SetNameCommand, SetNodeCommand, SetTypeCommand,
|
SetNameCommand, SetNodeCommand, SetTypeCommand,
|
||||||
AddCommand, DelCommand, SortCommand,
|
AddCommand, DelCommand, SortCommand,
|
||||||
MoveCommand, PasteCommand, DuplicateCommand,
|
MoveCommand, PasteCommand, DuplicateCommand,
|
||||||
)
|
)
|
||||||
from View.BoundaryCondition.translate import *
|
from View.BoundaryCondition.translate import BC_types
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class ComboBoxDelegate(QItemDelegate):
|
class ComboBoxDelegate(QItemDelegate):
|
||||||
def __init__(self, data=None, mode="type", tab="", parent=None):
|
def __init__(self, data=None, mode="type", tab="",
|
||||||
|
trad=None, parent=None):
|
||||||
super(ComboBoxDelegate, self).__init__(parent)
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
self._data = data
|
self._data = data
|
||||||
self._mode = mode
|
self._mode = mode
|
||||||
self._tab = tab
|
self._tab = tab
|
||||||
|
self._trad = trad
|
||||||
|
|
||||||
|
self._long_types = {}
|
||||||
|
if self._trad is not None:
|
||||||
|
self._long_types = self._trad.get_dict("long_types")
|
||||||
|
|
||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
self.editor = QComboBox(parent)
|
self.editor = QComboBox(parent)
|
||||||
@@ -64,7 +73,7 @@ class ComboBoxDelegate(QItemDelegate):
|
|||||||
if self._mode == "type":
|
if self._mode == "type":
|
||||||
lst = list(
|
lst = list(
|
||||||
map(
|
map(
|
||||||
lambda k: long_types[k],
|
lambda k: self._long_types[k],
|
||||||
filter(
|
filter(
|
||||||
lambda k: self._tab in BC_types[k].compatibility(),
|
lambda k: self._tab in BC_types[k].compatibility(),
|
||||||
BC_types.keys()
|
BC_types.keys()
|
||||||
@@ -95,8 +104,9 @@ class ComboBoxDelegate(QItemDelegate):
|
|||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
def updateEditorGeometry(self, editor, option, index):
|
||||||
r = QRect(option.rect)
|
r = QRect(option.rect)
|
||||||
if self.editor.windowFlags() & Qt.Popup and editor.parent() is not None:
|
if self.editor.windowFlags() & Qt.Popup:
|
||||||
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
if editor.parent() is not None:
|
||||||
|
r.setTopLeft(self.editor.parent().mapToGlobal(r.topLeft()))
|
||||||
editor.setGeometry(r)
|
editor.setGeometry(r)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@@ -104,26 +114,20 @@ class ComboBoxDelegate(QItemDelegate):
|
|||||||
self.commitData.emit(self.sender())
|
self.commitData.emit(self.sender())
|
||||||
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
class TableModel(PamhyrTableModel):
|
||||||
def __init__(self, data=None, undo=None, tab=""):
|
def __init__(self, **kwargs):
|
||||||
super(QAbstractTableModel, self).__init__()
|
super(TableModel, self).__init__(**kwargs)
|
||||||
self._headers = list(table_headers.keys())
|
|
||||||
self._data = data
|
|
||||||
self._undo = undo
|
|
||||||
self._tab = tab
|
|
||||||
self._bcs = self._data.boundary_condition
|
|
||||||
|
|
||||||
def flags(self, index):
|
self._long_types = {}
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
if self._trad is not None:
|
||||||
options |= Qt.ItemIsEditable
|
self._long_types = self._trad.get_dict("long_types")
|
||||||
|
|
||||||
return options
|
def _setup_lst(self):
|
||||||
|
self._lst = self._data.boundary_condition
|
||||||
|
self._tab = self._opt_data
|
||||||
|
|
||||||
def rowCount(self, parent):
|
def rowCount(self, parent):
|
||||||
return self._bcs.len(self._tab)
|
return self._lst.len(self._tab)
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role != Qt.ItemDataRole.DisplayRole:
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
@@ -133,24 +137,18 @@ class TableModel(QAbstractTableModel):
|
|||||||
column = index.column()
|
column = index.column()
|
||||||
|
|
||||||
if self._headers[column] == "name":
|
if self._headers[column] == "name":
|
||||||
return self._bcs.get(self._tab, row).name
|
return self._lst.get(self._tab, row).name
|
||||||
elif self._headers[column] == "type":
|
elif self._headers[column] == "type":
|
||||||
t = self._bcs.get(self._tab, row).bctype
|
t = self._lst.get(self._tab, row).bctype
|
||||||
return long_types[t]
|
return self._long_types[t]
|
||||||
elif self._headers[column] == "node":
|
elif self._headers[column] == "node":
|
||||||
n = self._bcs.get(self._tab, row).node
|
n = self._lst.get(self._tab, row).node
|
||||||
if n is None:
|
if n is None:
|
||||||
return _translate("BoundaryCondition", "Not associate")
|
return _translate("BoundaryCondition", "Not associate")
|
||||||
return n.name
|
return n.name
|
||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return table_headers[self._headers[section]]
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def setData(self, index, value, role=Qt.EditRole):
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
if not index.isValid() or role != Qt.EditRole:
|
if not index.isValid() or role != Qt.EditRole:
|
||||||
return False
|
return False
|
||||||
@@ -162,20 +160,21 @@ class TableModel(QAbstractTableModel):
|
|||||||
if self._headers[column] == "name":
|
if self._headers[column] == "name":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetNameCommand(
|
SetNameCommand(
|
||||||
self._bcs, self._tab,row, value
|
self._lst, self._tab, row, value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "type":
|
elif self._headers[column] == "type":
|
||||||
key = next(k for k, v in long_types.items() if v == value)
|
key = next(k for k, v in self._long_types.items()
|
||||||
|
if v == value)
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetTypeCommand(
|
SetTypeCommand(
|
||||||
self._bcs, self._tab,row, BC_types[key]
|
self._lst, self._tab, row, BC_types[key]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif self._headers[column] == "node":
|
elif self._headers[column] == "node":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetNodeCommand(
|
SetNodeCommand(
|
||||||
self._bcs, self._tab,row, self._data.node(value)
|
self._lst, self._tab, row, self._data.node(value)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -190,7 +189,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
AddCommand(
|
AddCommand(
|
||||||
self._bcs, self._tab,row
|
self._lst, self._tab, row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -202,7 +201,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
DelCommand(
|
DelCommand(
|
||||||
self._bcs, self._tab,rows
|
self._lst, self._tab, rows
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -214,7 +213,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SortCommand(
|
SortCommand(
|
||||||
self._bcs, self._tab,False
|
self._lst, self._tab, False
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -231,7 +230,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._bcs, self._tab,"up", row
|
self._lst, self._tab, "up", row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -239,7 +238,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def move_down(self, index, parent=QModelIndex()):
|
def move_down(self, index, parent=QModelIndex()):
|
||||||
if row > len(self._bcs):
|
if row > len(self._lst):
|
||||||
return
|
return
|
||||||
|
|
||||||
target = row
|
target = row
|
||||||
@@ -248,7 +247,7 @@ class TableModel(QAbstractTableModel):
|
|||||||
|
|
||||||
self._undo_stack.push(
|
self._undo_stack.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._bcs, self._tab,"down", row
|
self._lst, self._tab, "down", row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from PyQt5.QtWidgets import (
|
|||||||
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
from Model.BoundaryCondition.BoundaryCondition import BoundaryCondition
|
||||||
from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList
|
from Model.BoundaryCondition.BoundaryConditionList import BoundaryConditionList
|
||||||
|
|
||||||
|
|
||||||
class SetNameCommand(QUndoCommand):
|
class SetNameCommand(QUndoCommand):
|
||||||
def __init__(self, bcs, tab, index, new_value):
|
def __init__(self, bcs, tab, index, new_value):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -42,6 +43,7 @@ class SetNameCommand(QUndoCommand):
|
|||||||
def redo(self):
|
def redo(self):
|
||||||
self._bcs.get(self._tab, self._index).name = self._new
|
self._bcs.get(self._tab, self._index).name = self._new
|
||||||
|
|
||||||
|
|
||||||
class SetNodeCommand(QUndoCommand):
|
class SetNodeCommand(QUndoCommand):
|
||||||
def __init__(self, bcs, tab, index, node):
|
def __init__(self, bcs, tab, index, node):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -58,6 +60,7 @@ class SetNodeCommand(QUndoCommand):
|
|||||||
def redo(self):
|
def redo(self):
|
||||||
self._bcs.get(self._tab, self._index).node = self._new
|
self._bcs.get(self._tab, self._index).node = self._new
|
||||||
|
|
||||||
|
|
||||||
class SetTypeCommand(QUndoCommand):
|
class SetTypeCommand(QUndoCommand):
|
||||||
def __init__(self, bcs, tab, index, _type):
|
def __init__(self, bcs, tab, index, _type):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -76,6 +79,7 @@ class SetTypeCommand(QUndoCommand):
|
|||||||
def redo(self):
|
def redo(self):
|
||||||
self._bcs.set(self._tab, self._index, self._new)
|
self._bcs.set(self._tab, self._index, self._new)
|
||||||
|
|
||||||
|
|
||||||
class AddCommand(QUndoCommand):
|
class AddCommand(QUndoCommand):
|
||||||
def __init__(self, bcs, tab, index):
|
def __init__(self, bcs, tab, index):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -94,6 +98,7 @@ class AddCommand(QUndoCommand):
|
|||||||
else:
|
else:
|
||||||
self._bcs.insert(self._tab, self._index, self._new)
|
self._bcs.insert(self._tab, self._index, self._new)
|
||||||
|
|
||||||
|
|
||||||
class DelCommand(QUndoCommand):
|
class DelCommand(QUndoCommand):
|
||||||
def __init__(self, bcs, tab, rows):
|
def __init__(self, bcs, tab, rows):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
@@ -114,6 +119,7 @@ class DelCommand(QUndoCommand):
|
|||||||
def redo(self):
|
def redo(self):
|
||||||
self._bcs.delete_i(self._tab, self._rows)
|
self._bcs.delete_i(self._tab, self._rows)
|
||||||
|
|
||||||
|
|
||||||
class SortCommand(QUndoCommand):
|
class SortCommand(QUndoCommand):
|
||||||
def __init__(self, bcs, tab, _reverse):
|
def __init__(self, bcs, tab, _reverse):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ import logging
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
@@ -56,71 +55,71 @@ from View.BoundaryCondition.Table import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from View.Network.GraphWidget import GraphWidget
|
from View.Network.GraphWidget import GraphWidget
|
||||||
from View.BoundaryCondition.translate import *
|
from View.BoundaryCondition.translate import BCTranslate
|
||||||
from View.BoundaryCondition.Edit.Window import EditBoundaryConditionWindow
|
from View.BoundaryCondition.Edit.Window import EditBoundaryConditionWindow
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|
||||||
def __init__(self, title="Boundary conditions", study=None, parent=None):
|
class BoundaryConditionWindow(PamhyrWindow):
|
||||||
self._title = title + " - " + study.name
|
_pamhyr_ui = "BoundaryConditions"
|
||||||
|
_pamhyr_name = "Boundary conditions"
|
||||||
|
|
||||||
|
def __init__(self, study=None, config=None, parent=None):
|
||||||
|
name = self._pamhyr_name + " - " + study.name
|
||||||
|
|
||||||
super(BoundaryConditionWindow, self).__init__(
|
super(BoundaryConditionWindow, self).__init__(
|
||||||
name=title, ui="BoundaryConditions", parent=parent
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=BCTranslate(),
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
self._study = study
|
|
||||||
self._bcs = self._study.river.boundary_condition
|
self._bcs = self._study.river.boundary_condition
|
||||||
|
|
||||||
self.setup_sc()
|
|
||||||
self.setup_table()
|
self.setup_table()
|
||||||
self.setup_graph()
|
self.setup_graph()
|
||||||
self.setup_connections()
|
self.setup_connections()
|
||||||
|
|
||||||
self.ui.setWindowTitle(self._title)
|
self.ui.setWindowTitle(self._title)
|
||||||
|
|
||||||
def setup_sc(self):
|
|
||||||
self._undo_stack = QUndoStack()
|
|
||||||
|
|
||||||
self.undo_sc = QShortcut(QKeySequence.Undo, self)
|
|
||||||
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
|
||||||
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
|
||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
self._table = {}
|
self._table = {}
|
||||||
|
|
||||||
for t in ["liquid", "solid", "suspenssion"]:
|
for t in ["liquid", "solid", "suspenssion"]:
|
||||||
table = self.find(QTableView, f"tableView_{t}")
|
|
||||||
self._table[t] = TableModel(
|
|
||||||
data = self._study.river,
|
|
||||||
undo = self._undo_stack,
|
|
||||||
tab = t,
|
|
||||||
)
|
|
||||||
table.setModel(self._table[t])
|
|
||||||
|
|
||||||
self._delegate_type = ComboBoxDelegate(
|
self._delegate_type = ComboBoxDelegate(
|
||||||
data = self._study.river,
|
trad=self._trad,
|
||||||
mode = "type",
|
data=self._study.river,
|
||||||
tab = t,
|
mode="type",
|
||||||
|
tab=t,
|
||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
self._delegate_node = ComboBoxDelegate(
|
self._delegate_node = ComboBoxDelegate(
|
||||||
data = self._study.river,
|
trad=self._trad,
|
||||||
mode = "node",
|
data=self._study.river,
|
||||||
tab = t,
|
mode="node",
|
||||||
|
tab=t,
|
||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
|
|
||||||
table.setItemDelegateForColumn(
|
table = self.find(QTableView, f"tableView_{t}")
|
||||||
1, self._delegate_type
|
self._table[t] = TableModel(
|
||||||
|
table_view=table,
|
||||||
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
editable_headers=["name", "type", "node"],
|
||||||
|
delegates={
|
||||||
|
"type": self._delegate_type,
|
||||||
|
"node": self._delegate_node,
|
||||||
|
},
|
||||||
|
trad=self._trad,
|
||||||
|
data=self._study.river,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
opt_data=t,
|
||||||
)
|
)
|
||||||
table.setItemDelegateForColumn(
|
table.setModel(self._table[t])
|
||||||
2, self._delegate_node
|
|
||||||
)
|
|
||||||
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||||
table.setAlternatingRowColors(True)
|
table.setAlternatingRowColors(True)
|
||||||
@@ -128,7 +127,7 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
self.graph_widget = GraphWidget(
|
self.graph_widget = GraphWidget(
|
||||||
self._study.river,
|
self._study.river,
|
||||||
min_size=None, size=(200,200),
|
min_size=None, size=(200, 200),
|
||||||
only_display=True,
|
only_display=True,
|
||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
@@ -141,11 +140,6 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
self.find(QAction, "action_edit").triggered.connect(self.edit)
|
self.find(QAction, "action_edit").triggered.connect(self.edit)
|
||||||
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
self.find(QAction, "action_sort").triggered.connect(self.sort)
|
||||||
|
|
||||||
self.undo_sc.activated.connect(self.undo)
|
|
||||||
self.redo_sc.activated.connect(self.redo)
|
|
||||||
self.copy_sc.activated.connect(self.copy)
|
|
||||||
self.paste_sc.activated.connect(self.paste)
|
|
||||||
|
|
||||||
def current_tab(self):
|
def current_tab(self):
|
||||||
return self.find(QTabWidget, "tabWidget")\
|
return self.find(QTabWidget, "tabWidget")\
|
||||||
.currentWidget()\
|
.currentWidget()\
|
||||||
@@ -202,17 +196,17 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
row = self.index_selected_row()
|
row = self.index_selected_row()
|
||||||
self._table[tab].move_down(row)
|
self._table[tab].move_down(row)
|
||||||
|
|
||||||
def copy(self):
|
def _copy(self):
|
||||||
logger.info("TODO: copy")
|
logger.info("TODO: copy")
|
||||||
|
|
||||||
def paste(self):
|
def _paste(self):
|
||||||
logger.info("TODO: paste")
|
logger.info("TODO: paste")
|
||||||
|
|
||||||
def undo(self):
|
def _undo(self):
|
||||||
tab = self.current_tab()
|
tab = self.current_tab()
|
||||||
self._table[tab].undo()
|
self._table[tab].undo()
|
||||||
|
|
||||||
def redo(self):
|
def _redo(self):
|
||||||
tab = self.current_tab()
|
tab = self.current_tab()
|
||||||
self._table[tab].redo()
|
self._table[tab].redo()
|
||||||
|
|
||||||
@@ -220,17 +214,17 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
tab = self.current_tab()
|
tab = self.current_tab()
|
||||||
rows = self.index_selected_rows()
|
rows = self.index_selected_rows()
|
||||||
for row in rows:
|
for row in rows:
|
||||||
win = self.sub_win_filter_first(
|
data = self._bcs.get(tab, row)
|
||||||
"Edit boundary condition",
|
|
||||||
contain = [f"({self._bcs.get(tab, row).id})"]
|
|
||||||
)
|
|
||||||
|
|
||||||
if win is None:
|
if self.sub_window_exists(
|
||||||
win = EditBoundaryConditionWindow(
|
EditBoundaryConditionWindow,
|
||||||
data=self._bcs.get(tab, row),
|
data=[self._study, None, data]
|
||||||
study=self._study,
|
):
|
||||||
parent=self
|
continue
|
||||||
)
|
|
||||||
win.show()
|
win = EditBoundaryConditionWindow(
|
||||||
else:
|
data=data,
|
||||||
win.activateWindow()
|
study=self._study,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
win.show()
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||||
|
|
||||||
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
from Model.BoundaryCondition.BoundaryConditionTypes import (
|
||||||
NotDefined, PonctualContribution,
|
NotDefined, PonctualContribution,
|
||||||
TimeOverZ, TimeOverDischarge, ZOverDischarge,
|
TimeOverZ, TimeOverDischarge, ZOverDischarge,
|
||||||
@@ -26,21 +28,6 @@ from Model.BoundaryCondition.BoundaryConditionTypes import (
|
|||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
long_types = {
|
|
||||||
"ND": _translate("BoundaryCondition", "Not defined"),
|
|
||||||
"PC": _translate("BoundaryCondition", "Ponctual contribution"),
|
|
||||||
"TZ": _translate("BoundaryCondition", "TimeZ"),
|
|
||||||
"TD": _translate("BoundaryCondition", "TimeDischarge"),
|
|
||||||
"ZD": _translate("BoundaryCondition", "ZDischarge"),
|
|
||||||
"SL": _translate("BoundaryCondition", "Solid"),
|
|
||||||
}
|
|
||||||
|
|
||||||
table_headers = {
|
|
||||||
"name": _translate("BoundaryCondition", "Name"),
|
|
||||||
"type": _translate("BoundaryCondition", "Type"),
|
|
||||||
"node": _translate("BoundaryCondition", "Node")
|
|
||||||
}
|
|
||||||
|
|
||||||
BC_types = {
|
BC_types = {
|
||||||
"ND": NotDefined,
|
"ND": NotDefined,
|
||||||
"PC": PonctualContribution,
|
"PC": PonctualContribution,
|
||||||
@@ -49,3 +36,23 @@ BC_types = {
|
|||||||
"ZD": ZOverDischarge,
|
"ZD": ZOverDischarge,
|
||||||
"SL": Solid,
|
"SL": Solid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BCTranslate(PamhyrTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(BCTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._sub_dict["long_types"] = {
|
||||||
|
"ND": _translate("BoundaryCondition", "Not defined"),
|
||||||
|
"PC": _translate("BoundaryCondition", "Ponctual contribution"),
|
||||||
|
"TZ": _translate("BoundaryCondition", "TimeZ"),
|
||||||
|
"TD": _translate("BoundaryCondition", "TimeDischarge"),
|
||||||
|
"ZD": _translate("BoundaryCondition", "ZDischarge"),
|
||||||
|
"SL": _translate("BoundaryCondition", "Solid"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"name": _translate("BoundaryCondition", "Name"),
|
||||||
|
"type": _translate("BoundaryCondition", "Type"),
|
||||||
|
"node": _translate("BoundaryCondition", "Node")
|
||||||
|
}
|
||||||
@@ -35,25 +35,12 @@ from PyQt5.QtWidgets import (
|
|||||||
QComboBox,
|
QComboBox,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class TableModel(QAbstractTableModel):
|
class TableModel(PamhyrTableModel):
|
||||||
def __init__(self, data=None):
|
|
||||||
super(QAbstractTableModel, self).__init__()
|
|
||||||
self._headers = ["name", "status"]
|
|
||||||
self._data = data
|
|
||||||
|
|
||||||
def flags(self, index):
|
|
||||||
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
||||||
return options
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self._data)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self._headers)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
row = index.row()
|
row = index.row()
|
||||||
column = index.column()
|
column = index.column()
|
||||||
@@ -81,12 +68,3 @@ class TableModel(QAbstractTableModel):
|
|||||||
return self._data[row].summary
|
return self._data[row].summary
|
||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
|
||||||
return self._headers[section]
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
self.layoutChanged.emit()
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Translate.py -- 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 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class CheckListTranslate(PamhyrTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(CheckListTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"name": _translate("CheckList", "Name"),
|
||||||
|
"status": _translate("CheckList", "Status"),
|
||||||
|
}
|
||||||
@@ -18,8 +18,7 @@
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
@@ -41,33 +40,40 @@ from PyQt5.QtWidgets import (
|
|||||||
|
|
||||||
from View.CheckList.Table import TableModel
|
from View.CheckList.Table import TableModel
|
||||||
from View.CheckList.Worker import Worker
|
from View.CheckList.Worker import Worker
|
||||||
|
from View.CheckList.Translate import CheckListTranslate
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
class CheckListWindow(ASubMainWindow, ListedSubWindow):
|
|
||||||
|
class CheckListWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "CheckList"
|
||||||
|
_pamhyr_name = "Check list"
|
||||||
|
|
||||||
signalStatus = pyqtSignal(str)
|
signalStatus = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, title="Check list",
|
def __init__(self, autorun: bool = True,
|
||||||
autorun:bool=True,
|
|
||||||
study=None, config=None,
|
study=None, config=None,
|
||||||
solver=None, parent=None):
|
solver=None, parent=None):
|
||||||
self._title = title + " - " + study.name
|
|
||||||
|
|
||||||
self._autorun = autorun
|
self._autorun = autorun
|
||||||
|
|
||||||
self._study = study
|
|
||||||
self._config = config
|
|
||||||
self._solver = solver
|
self._solver = solver
|
||||||
self._parent = parent
|
|
||||||
|
name = self._pamhyr_name + " - " + study.name
|
||||||
|
|
||||||
super(CheckListWindow, self).__init__(
|
super(CheckListWindow, self).__init__(
|
||||||
name=self._title, ui="CheckList", parent=parent
|
title=name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
trad=CheckListTranslate(),
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
self.ui.setWindowTitle(self._title)
|
|
||||||
|
# Add solver to hash computation data
|
||||||
|
self._hash_data.append(self._solver)
|
||||||
|
|
||||||
self._checker_list = (
|
self._checker_list = (
|
||||||
self._study.checkers() + self._solver.checkers()
|
self._study.checkers() +
|
||||||
|
self._solver.checkers()
|
||||||
)
|
)
|
||||||
|
|
||||||
self.setup_table()
|
self.setup_table()
|
||||||
@@ -78,16 +84,12 @@ class CheckListWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
table = self.find(QTableView, f"tableView")
|
table = self.find(QTableView, f"tableView")
|
||||||
|
|
||||||
self._table = TableModel(
|
self._table = TableModel(
|
||||||
data = self._checker_list,
|
table_view=table,
|
||||||
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
data=self._checker_list,
|
||||||
)
|
)
|
||||||
|
|
||||||
table.setModel(self._table)
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
||||||
table.setAlternatingRowColors(True)
|
|
||||||
|
|
||||||
def setup_progress_bar(self):
|
def setup_progress_bar(self):
|
||||||
self._progress = self.find(QProgressBar, f"progressBar")
|
self._progress = self.find(QProgressBar, f"progressBar")
|
||||||
self._p = 0 # Progress current step
|
self._p = 0 # Progress current step
|
||||||
@@ -98,7 +100,8 @@ class CheckListWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def setup_connections(self):
|
def setup_connections(self):
|
||||||
self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
|
self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
|
||||||
self.find(QPushButton, "pushButton_retry").clicked.connect(self.retry)
|
self.find(QPushButton, "pushButton_retry").clicked.connect(self.retry)
|
||||||
self.find(QPushButton, "pushButton_cancel").clicked.connect(self.reject)
|
self.find(QPushButton, "pushButton_cancel")\
|
||||||
|
.clicked.connect(self.reject)
|
||||||
|
|
||||||
def setup_thread(self):
|
def setup_thread(self):
|
||||||
self._worker = Worker(self._study, self._checker_list)
|
self._worker = Worker(self._study, self._checker_list)
|
||||||
@@ -122,7 +125,8 @@ class CheckListWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
def _compute_status(self):
|
def _compute_status(self):
|
||||||
ok = len(list(filter(lambda c: c.is_ok(), self._checker_list)))
|
ok = len(list(filter(lambda c: c.is_ok(), self._checker_list)))
|
||||||
warning = len(list(filter(lambda c: c.is_warning(), self._checker_list)))
|
warning = len(
|
||||||
|
list(filter(lambda c: c.is_warning(), self._checker_list)))
|
||||||
error = len(list(filter(lambda c: c.is_error(), self._checker_list)))
|
error = len(list(filter(lambda c: c.is_error(), self._checker_list)))
|
||||||
|
|
||||||
return ok, warning, error
|
return ok, warning, error
|
||||||
@@ -166,7 +170,7 @@ class CheckListWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
self.update_statusbar()
|
self.update_statusbar()
|
||||||
|
|
||||||
def update(self, key:str):
|
def update(self, key: str):
|
||||||
if key == "start":
|
if key == "start":
|
||||||
self.start_compute()
|
self.start_compute()
|
||||||
self.info_compute("Starting ...")
|
self.info_compute("Starting ...")
|
||||||
@@ -189,4 +193,4 @@ class CheckListWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
self._parent.solver_log(self._solver)
|
self._parent.solver_log(self._solver)
|
||||||
#self.end()
|
# self.end()
|
||||||
@@ -22,6 +22,7 @@ from PyQt5.QtCore import (
|
|||||||
Qt, QObject, pyqtSlot, pyqtSignal
|
Qt, QObject, pyqtSlot, pyqtSignal
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Worker(QObject):
|
class Worker(QObject):
|
||||||
signalStatus = pyqtSignal(str)
|
signalStatus = pyqtSignal(str)
|
||||||
|
|
||||||
@@ -37,10 +38,11 @@ class Worker(QObject):
|
|||||||
self.signalStatus.emit('end')
|
self.signalStatus.emit('end')
|
||||||
|
|
||||||
def _compute(self):
|
def _compute(self):
|
||||||
|
# The computation loop
|
||||||
for checker in self._checker_list:
|
for checker in self._checker_list:
|
||||||
self.signalStatus.emit(checker.name)
|
self.signalStatus.emit(checker.name)
|
||||||
|
|
||||||
# time.sleep(1)
|
# Run checker
|
||||||
checker.run(self._study)
|
checker._run(self._study)
|
||||||
|
|
||||||
self.signalStatus.emit("progress")
|
self.signalStatus.emit("progress")
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from View.ASubWindow import ASubWindow
|
from View.Tools.PamhyrWindow import PamhyrDialog
|
||||||
from Solver.Solvers import solver_type_list
|
from Solver.Solvers import solver_type_list
|
||||||
from Solver.GenericSolver import GenericSolver
|
from Solver.GenericSolver import GenericSolver
|
||||||
|
|
||||||
@@ -24,12 +24,23 @@ from PyQt5.QtWidgets import (
|
|||||||
QPushButton,
|
QPushButton,
|
||||||
)
|
)
|
||||||
|
|
||||||
class ConfigureSolverWindow(ASubWindow):
|
|
||||||
def __init__(self, data=None, title="Configuration : Add Solver", parent=None):
|
class ConfigureSolverWindow(PamhyrDialog):
|
||||||
|
_pamhyr_ui = "ConfigureAddSolverDialog"
|
||||||
|
_pamhyr_name = "Add/Edit Solver"
|
||||||
|
|
||||||
|
def __init__(self, data=None, config=None, parent=None):
|
||||||
|
if data is not None:
|
||||||
|
name = f"Edit Solver - {data.name}"
|
||||||
|
else:
|
||||||
|
name = "Add a new Solver"
|
||||||
|
|
||||||
super(ConfigureSolverWindow, self).__init__(
|
super(ConfigureSolverWindow, self).__init__(
|
||||||
name=title, ui="ConfigureAddSolverDialog", parent=parent
|
title=name,
|
||||||
|
config=config,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
self.ui.setWindowTitle(title)
|
|
||||||
|
|
||||||
# Combo box item
|
# Combo box item
|
||||||
for solver in solver_type_list:
|
for solver in solver_type_list:
|
||||||
@@ -37,10 +48,10 @@ class ConfigureSolverWindow(ASubWindow):
|
|||||||
|
|
||||||
# Data to return
|
# Data to return
|
||||||
self.data = data
|
self.data = data
|
||||||
if not self.data is None:
|
if self.data is not None:
|
||||||
self.copy_data()
|
self.copy_data()
|
||||||
|
|
||||||
self.connect()
|
self.setup_connection()
|
||||||
|
|
||||||
def copy_data(self):
|
def copy_data(self):
|
||||||
self.set_combobox_text("comboBox_solver", self.data.type)
|
self.set_combobox_text("comboBox_solver", self.data.type)
|
||||||
@@ -53,20 +64,23 @@ class ConfigureSolverWindow(ASubWindow):
|
|||||||
self.set_line_edit_text("lineEdit_output", self.data._path_output)
|
self.set_line_edit_text("lineEdit_output", self.data._path_output)
|
||||||
self.set_line_edit_text("lineEdit_output_cmd", self.data._cmd_output)
|
self.set_line_edit_text("lineEdit_output_cmd", self.data._cmd_output)
|
||||||
|
|
||||||
def connect(self):
|
def setup_connection(self):
|
||||||
# File button
|
# File button
|
||||||
buttons = {
|
buttons = {
|
||||||
"pushButton_input": (lambda: self.file_dialog(
|
"pushButton_input": (lambda: self.file_dialog(
|
||||||
select_file = True,
|
select_file=True,
|
||||||
callback = lambda f: self.set_line_edit_text("lineEdit_input", f[0])
|
callback=lambda f: self.set_line_edit_text(
|
||||||
|
"lineEdit_input", f[0])
|
||||||
)),
|
)),
|
||||||
"pushButton_solver": (lambda: self.file_dialog(
|
"pushButton_solver": (lambda: self.file_dialog(
|
||||||
select_file = True,
|
select_file=True,
|
||||||
callback = lambda f: self.set_line_edit_text("lineEdit_solver", f[0])
|
callback=lambda f: self.set_line_edit_text(
|
||||||
|
"lineEdit_solver", f[0])
|
||||||
)),
|
)),
|
||||||
"pushButton_output": (lambda: self.file_dialog(
|
"pushButton_output": (lambda: self.file_dialog(
|
||||||
select_file = True,
|
select_file=True,
|
||||||
callback = lambda f: self.set_line_edit_text("lineEdit_output", f[0])
|
callback=lambda f: self.set_line_edit_text(
|
||||||
|
"lineEdit_output", f[0])
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,9 +96,11 @@ class ConfigureSolverWindow(ASubWindow):
|
|||||||
else:
|
else:
|
||||||
# Build new solver from selected type
|
# Build new solver from selected type
|
||||||
stype = self.get_combobox_text("comboBox_solver")
|
stype = self.get_combobox_text("comboBox_solver")
|
||||||
self.data = solver_type_list[stype](self.get_line_edit_text("lineEdit_name"))
|
self.data = solver_type_list[stype](
|
||||||
|
self.get_line_edit_text("lineEdit_name"))
|
||||||
|
|
||||||
self.data.description = self.get_line_edit_text("lineEdit_description")
|
self.data.description = self.get_line_edit_text(
|
||||||
|
"lineEdit_description")
|
||||||
self.data.set_input(
|
self.data.set_input(
|
||||||
self.get_line_edit_text("lineEdit_input"),
|
self.get_line_edit_text("lineEdit_input"),
|
||||||
self.get_line_edit_text("lineEdit_input_cmd")
|
self.get_line_edit_text("lineEdit_input_cmd")
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Translate.py -- 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 -*-
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
from View.Tools.PamhyrTranslate import PamhyrTranslate
|
||||||
|
|
||||||
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigureTranslate(PamhyrTranslate):
|
||||||
|
def __init__(self):
|
||||||
|
super(ConfigureTranslate, self).__init__()
|
||||||
|
|
||||||
|
self._sub_dict["table_headers"] = {
|
||||||
|
"name": _translate("Configure", "Name"),
|
||||||
|
"type": _translate("Configure", "Type"),
|
||||||
|
"description": _translate("Configure", "Description"),
|
||||||
|
}
|
||||||
+96
-104
@@ -21,13 +21,14 @@ import logging
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from View.ASubWindow import ASubWindow
|
from View.Tools.PamhyrWindow import PamhyrDialog
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from View.Stricklers.Table import TableModel
|
from View.Stricklers.Table import TableModel
|
||||||
from View.Stricklers.translate import *
|
from View.Stricklers.translate import StricklersTranslate
|
||||||
from View.Stricklers.UndoCommand import *
|
from View.Stricklers.UndoCommand import *
|
||||||
|
|
||||||
|
from View.Configure.Translate import ConfigureTranslate
|
||||||
from View.Configure.Solver.Window import ConfigureSolverWindow
|
from View.Configure.Solver.Window import ConfigureSolverWindow
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
@@ -48,126 +49,109 @@ from Solver.Solvers import solver_long_name
|
|||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
class SolverTableModel(QAbstractTableModel):
|
|
||||||
def __init__(self, headers=[], rows=[]):
|
|
||||||
super(QAbstractTableModel, self).__init__()
|
|
||||||
self.rows = rows
|
|
||||||
self.headers = headers
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self.rows)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return len(self.headers)
|
|
||||||
|
|
||||||
|
class SolverTableModel(PamhyrTableModel):
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role != Qt.ItemDataRole.DisplayRole:
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
ret = self.rows[index.row()][self.headers[index.column()]]
|
ret = self._data[index.row()][self._headers[index.column()]]
|
||||||
|
|
||||||
if self.headers[index.column()] == "type":
|
if self._headers[index.column()] == "type":
|
||||||
ret = solver_long_name[ret]
|
ret = solver_long_name[ret]
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def headerData(self, section, orientation, role):
|
|
||||||
if (role == Qt.ItemDataRole.DisplayRole and
|
|
||||||
orientation == Qt.Orientation.Horizontal):
|
|
||||||
return self.headers[section].capitalize()
|
|
||||||
|
|
||||||
if (role == Qt.ItemDataRole.DisplayRole and
|
|
||||||
orientation == Qt.Orientation.Vertical):
|
|
||||||
return section + 1 # Start at 1
|
|
||||||
|
|
||||||
return QVariant()
|
|
||||||
|
|
||||||
def removeRow(self, index):
|
def removeRow(self, index):
|
||||||
del self.rows[index.row()]
|
del self._data[index.row()]
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def add_solver(self, solver):
|
def add_solver(self, solver):
|
||||||
self.rows.append(solver)
|
self._data.append(solver)
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def change_solver(self, solver, index):
|
def change_solver(self, solver, index):
|
||||||
self.rows[index.row()] = solver
|
self._data[index.row()] = solver
|
||||||
self.layoutChanged.emit()
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
|
|
||||||
class ConfigureWindow(ASubWindow, ListedSubWindow):
|
class ConfigureWindow(PamhyrDialog):
|
||||||
def __init__(self, conf=None, title="Configure", parent=None):
|
_pamhyr_ui = "ConfigureDialog"
|
||||||
|
_pamhyr_name = "Configure"
|
||||||
|
|
||||||
|
def __init__(self, config=None, parent=None):
|
||||||
|
if config is None:
|
||||||
|
config = Config()
|
||||||
|
|
||||||
super(ConfigureWindow, self).__init__(
|
super(ConfigureWindow, self).__init__(
|
||||||
name=title, ui="ConfigureDialog", parent=parent
|
title=self._pamhyr_name,
|
||||||
|
config=config,
|
||||||
|
trad=ConfigureTranslate(),
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
self.ui.setWindowTitle(title)
|
|
||||||
|
|
||||||
if conf is None:
|
self._trad_stricklers = StricklersTranslate()
|
||||||
self.conf = Config()
|
|
||||||
else:
|
|
||||||
self.conf = conf
|
|
||||||
|
|
||||||
self.setup_sc()
|
self.setup_custom_sc()
|
||||||
|
self.setup_solver()
|
||||||
|
self.setup_stricklers()
|
||||||
|
self.setup_data()
|
||||||
|
self.setup_connection()
|
||||||
|
|
||||||
# Solver
|
def setup_solver(self):
|
||||||
table = self.find(QTableView, "tableView_solver")
|
table = self.find(QTableView, "tableView_solver")
|
||||||
self.solver_table_model = SolverTableModel(
|
self.solver_table_model = SolverTableModel(
|
||||||
headers = ["name", "type", "description"],
|
table_view=table,
|
||||||
rows = conf.solvers
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
|
data=self._config.solvers
|
||||||
)
|
)
|
||||||
table.setModel(self.solver_table_model)
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
||||||
table.setAlternatingRowColors(True)
|
|
||||||
|
|
||||||
|
def setup_stricklers(self):
|
||||||
|
table = self.find(QTableView, f"tableView_stricklers")
|
||||||
|
self._stricklers = deepcopy(self._config.stricklers)
|
||||||
|
self._stricklers_table = TableModel(
|
||||||
|
table_view=table,
|
||||||
|
table_headers=self._trad_stricklers.get_dict("table_headers"),
|
||||||
|
editable_headers=["name", "comment", "minor", "medium"],
|
||||||
|
data=self._stricklers,
|
||||||
|
undo=self._undo_stack,
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup_data(self):
|
||||||
# Meshing_Tool
|
# Meshing_Tool
|
||||||
self.set_line_edit_text("lineEdit_meshing_tool", self.conf.meshing_tool)
|
self.set_line_edit_text("lineEdit_meshing_tool",
|
||||||
|
self._config.meshing_tool)
|
||||||
|
|
||||||
# Const
|
# Const
|
||||||
self.set_line_edit_text("lineEdit_segment", str(self.conf.segment))
|
self.set_line_edit_text("lineEdit_segment", str(self._config.segment))
|
||||||
self.set_line_edit_text("lineEdit_max_listing", str(self.conf.max_listing))
|
self.set_line_edit_text("lineEdit_max_listing",
|
||||||
|
str(self._config.max_listing))
|
||||||
|
|
||||||
# Backup
|
# Backup
|
||||||
self.set_check_box("checkBox_backup", self.conf.backup_enable)
|
self.set_check_box("checkBox_backup", self._config.backup_enable)
|
||||||
self.set_line_edit_text("lineEdit_backup_path", self.conf.backup_path)
|
self.set_line_edit_text("lineEdit_backup_path",
|
||||||
self.set_time_edit("timeEdit_backup_frequence", self.conf.backup_frequence)
|
self._config.backup_path)
|
||||||
self.set_spin_box("spinBox_backup_max", self.conf.backup_max)
|
self.set_time_edit("timeEdit_backup_frequence",
|
||||||
|
self._config.backup_frequence)
|
||||||
self.find(QTableView, "tableView_solver").resizeColumnsToContents()
|
self.set_spin_box("spinBox_backup_max", self._config.backup_max)
|
||||||
self.connect()
|
|
||||||
|
|
||||||
# Stricklers
|
|
||||||
table = self.find(QTableView, f"tableView_stricklers")
|
|
||||||
self._stricklers = deepcopy(self.conf.stricklers)
|
|
||||||
self._stricklers_table = TableModel(
|
|
||||||
data = self._stricklers,
|
|
||||||
undo = self._undo_stack,
|
|
||||||
)
|
|
||||||
table.setModel(self._stricklers_table)
|
|
||||||
table.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
||||||
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
||||||
table.setAlternatingRowColors(True)
|
|
||||||
|
|
||||||
# Editor
|
# Editor
|
||||||
self.set_line_edit_text("lineEdit_editor_cmd", str(self.conf.editor))
|
self.set_line_edit_text("lineEdit_editor_cmd",
|
||||||
|
str(self._config.editor))
|
||||||
|
|
||||||
# Language
|
# Language
|
||||||
languages = Config.languages()
|
languages = Config.languages()
|
||||||
for lang in languages:
|
for lang in languages:
|
||||||
self.combobox_add_item("comboBox_language", lang)
|
self.combobox_add_item("comboBox_language", lang)
|
||||||
if self.conf.lang == languages[lang]:
|
if self._config.lang == languages[lang]:
|
||||||
self.set_combobox_text("comboBox_language", lang)
|
self.set_combobox_text("comboBox_language", lang)
|
||||||
|
|
||||||
def setup_sc(self):
|
def setup_custom_sc(self):
|
||||||
self._undo_stack = QUndoStack()
|
self._debug_sc = QShortcut(QKeySequence("Ctrl+G"), self)
|
||||||
|
self._debug_sc.activated.connect(self.set_debug)
|
||||||
|
|
||||||
self.debug_sc = QShortcut(QKeySequence("Ctrl+G"), self)
|
def setup_connection(self):
|
||||||
self.undo_sc = QShortcut(QKeySequence.Undo, self)
|
|
||||||
self.redo_sc = QShortcut(QKeySequence.Redo, self)
|
|
||||||
self.copy_sc = QShortcut(QKeySequence.Copy, self)
|
|
||||||
self.paste_sc = QShortcut(QKeySequence.Paste, self)
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
buttons = {
|
buttons = {
|
||||||
# Solvers
|
# Solvers
|
||||||
"pushButton_solver_add": self.add_solver,
|
"pushButton_solver_add": self.add_solver,
|
||||||
@@ -179,14 +163,14 @@ class ConfigureWindow(ASubWindow, ListedSubWindow):
|
|||||||
"pushButton_stricklers_sort": self.sort_stricklers,
|
"pushButton_stricklers_sort": self.sort_stricklers,
|
||||||
# Others
|
# Others
|
||||||
"pushButton_backup_path": lambda: self.file_dialog(
|
"pushButton_backup_path": lambda: self.file_dialog(
|
||||||
select_file = False,
|
select_file=False,
|
||||||
callback = lambda f: self.set_line_edit_text(
|
callback=lambda f: self.set_line_edit_text(
|
||||||
"lineEdit_backup_path", f[0]
|
"lineEdit_backup_path", f[0]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
"pushButton_meshing_tool" : lambda: self.file_dialog(
|
"pushButton_meshing_tool": lambda: self.file_dialog(
|
||||||
select_file = True,
|
select_file=True,
|
||||||
callback = lambda f: self.set_line_edit_text(
|
callback=lambda f: self.set_line_edit_text(
|
||||||
"lineEdit_meshing_tool", f[0]
|
"lineEdit_meshing_tool", f[0]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@@ -195,33 +179,36 @@ class ConfigureWindow(ASubWindow, ListedSubWindow):
|
|||||||
for button in buttons:
|
for button in buttons:
|
||||||
self.find(QPushButton, button).clicked.connect(buttons[button])
|
self.find(QPushButton, button).clicked.connect(buttons[button])
|
||||||
|
|
||||||
self.debug_sc.activated.connect(self.set_debug)
|
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
# Solvers
|
# Solvers
|
||||||
self.conf.solvers = self.solver_table_model.rows.copy()
|
self._config.solvers = self.solver_table_model._data.copy()
|
||||||
|
|
||||||
# Meshing_Tool
|
# Meshing_Tool
|
||||||
self.conf.meshing_tool = self.get_line_edit_text("lineEdit_meshing_tool")
|
self._config.meshing_tool = self.get_line_edit_text(
|
||||||
|
"lineEdit_meshing_tool")
|
||||||
|
|
||||||
# Const
|
# Const
|
||||||
self.conf.segment = self.get_line_edit_text("lineEdit_segment")
|
self._config.segment = self.get_line_edit_text("lineEdit_segment")
|
||||||
self.conf.max_listing = self.get_line_edit_text("lineEdit_max_listing")
|
self._config.max_listing = self.get_line_edit_text(
|
||||||
|
"lineEdit_max_listing")
|
||||||
|
|
||||||
# Backup
|
# Backup
|
||||||
self.conf.backup_enable = self.get_check_box("checkBox_backup")
|
self._config.backup_enable = self.get_check_box("checkBox_backup")
|
||||||
self.conf.backup_path = self.get_line_edit_text("lineEdit_backup_path")
|
self._config.backup_path = self.get_line_edit_text(
|
||||||
self.conf.backup_frequence = self.get_time_edit("timeEdit_backup_frequence")
|
"lineEdit_backup_path")
|
||||||
self.conf.backup_max = self.get_spin_box("spinBox_backup_max")
|
self._config.backup_frequence = self.get_time_edit(
|
||||||
|
"timeEdit_backup_frequence")
|
||||||
|
self._config.backup_max = self.get_spin_box("spinBox_backup_max")
|
||||||
|
|
||||||
# Stricklers
|
# Stricklers
|
||||||
self.conf.stricklers = deepcopy(self._stricklers)
|
self._config.stricklers = deepcopy(self._stricklers)
|
||||||
|
|
||||||
# Editor
|
# Editor
|
||||||
self.conf.editor = self.get_line_edit_text("lineEdit_editor_cmd")
|
self._config.editor = self.get_line_edit_text("lineEdit_editor_cmd")
|
||||||
|
|
||||||
# Language
|
# Language
|
||||||
self.conf.lang = Config.languages()[self.get_combobox_text("comboBox_language")]
|
self._config.lang = Config.languages(
|
||||||
|
)[self.get_combobox_text("comboBox_language")]
|
||||||
|
|
||||||
self.end()
|
self.end()
|
||||||
|
|
||||||
@@ -230,26 +217,30 @@ class ConfigureWindow(ASubWindow, ListedSubWindow):
|
|||||||
self.end()
|
self.end()
|
||||||
|
|
||||||
def end(self):
|
def end(self):
|
||||||
self.conf.save()
|
self._config.save()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
# Debug
|
# Debug
|
||||||
|
|
||||||
def set_debug(self):
|
def set_debug(self):
|
||||||
self.conf.debug = not self.conf.debug
|
self._config.debug = not self._config.debug
|
||||||
logger.info(f"Debug mode set : {self.conf.debug}")
|
logger.info(f"Debug mode set : {self._config.debug}")
|
||||||
self.parent.setup_debug_mode()
|
self.parent.setup_debug_mode()
|
||||||
|
|
||||||
# Solvers
|
# Solvers
|
||||||
|
|
||||||
def edit_solver(self):
|
def edit_solver(self):
|
||||||
indexes = self.find(QTableView, "tableView_solver").selectionModel().selectedRows()
|
indexes = self.find(
|
||||||
|
QTableView, "tableView_solver").selectionModel().selectedRows()
|
||||||
for index in indexes:
|
for index in indexes:
|
||||||
self.edit_solver = ConfigureSolverWindow(
|
self.edit_solver = ConfigureSolverWindow(
|
||||||
data=self.solver_table_model.rows[index.row()],
|
data=self.solver_table_model._data[index.row()],
|
||||||
|
config=self._config,
|
||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
if self.edit_solver.exec_():
|
if self.edit_solver.exec_():
|
||||||
self.solver_table_model.change_solver(self.edit_solver.data, index)
|
self.solver_table_model.change_solver(
|
||||||
|
self.edit_solver.data, index)
|
||||||
|
|
||||||
def add_solver(self):
|
def add_solver(self):
|
||||||
dialog_solver = ConfigureSolverWindow(parent=self)
|
dialog_solver = ConfigureSolverWindow(parent=self)
|
||||||
@@ -257,7 +248,8 @@ class ConfigureWindow(ASubWindow, ListedSubWindow):
|
|||||||
self.solver_table_model.add_solver(dialog_solver.data)
|
self.solver_table_model.add_solver(dialog_solver.data)
|
||||||
|
|
||||||
def remove_solver(self):
|
def remove_solver(self):
|
||||||
indices = self.find(QTableView, "tableView_solver").selectionModel().selectedRows()
|
indices = self.find(
|
||||||
|
QTableView, "tableView_solver").selectionModel().selectedRows()
|
||||||
for index in sorted(indices):
|
for index in sorted(indices):
|
||||||
self.solver_table_model.removeRow(index)
|
self.solver_table_model.removeRow(index)
|
||||||
|
|
||||||
|
|||||||
+32
-20
@@ -20,8 +20,8 @@ import logging
|
|||||||
|
|
||||||
from tools import trace, timer
|
from tools import trace, timer
|
||||||
|
|
||||||
from View.ASubWindow import ASubMainWindow
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
from View.ListedSubWindow import ListedSubWindow
|
from View.Tools.PamhyrPythonEditor import PamhyrPythonEditor
|
||||||
|
|
||||||
from PyQt5.QtGui import (
|
from PyQt5.QtGui import (
|
||||||
QKeySequence,
|
QKeySequence,
|
||||||
@@ -38,34 +38,42 @@ from PyQt5.QtWidgets import (
|
|||||||
QFileDialog, QTableView, QAbstractItemView,
|
QFileDialog, QTableView, QAbstractItemView,
|
||||||
QUndoStack, QShortcut, QAction, QItemDelegate,
|
QUndoStack, QShortcut, QAction, QItemDelegate,
|
||||||
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
|
||||||
QProgressBar, QLabel, QTextEdit,
|
QProgressBar, QLabel, QTextEdit, QHBoxLayout,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from PyQt5.Qsci import QsciScintilla, QsciLexerPython
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
class ReplWindow(ASubMainWindow, ListedSubWindow):
|
|
||||||
def __init__(self, title="Debug REPL",
|
class ReplWindow(PamhyrWindow):
|
||||||
study=None, config=None,
|
_pamhyr_ui = "DebugRepl"
|
||||||
|
_pamhyr_name = "Debug REPL"
|
||||||
|
|
||||||
|
def __init__(self, study=None, config=None,
|
||||||
solver=None, parent=None):
|
solver=None, parent=None):
|
||||||
self._title = title
|
|
||||||
|
|
||||||
self._study = study
|
|
||||||
self._config = config
|
|
||||||
self._parent = parent
|
|
||||||
|
|
||||||
super(ReplWindow, self).__init__(
|
super(ReplWindow, self).__init__(
|
||||||
name=self._title, ui="DebugRepl", parent=parent
|
title=self._pamhyr_name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
)
|
)
|
||||||
self.ui.setWindowTitle(self._title)
|
|
||||||
|
|
||||||
self.__debug_exec_result__ = None
|
self.__debug_exec_result__ = None
|
||||||
self._history = []
|
self._history = []
|
||||||
self._history_ind = 0
|
self._history_ind = 0
|
||||||
|
|
||||||
|
self.setup_editor()
|
||||||
self.setup_connections()
|
self.setup_connections()
|
||||||
|
|
||||||
|
def setup_editor(self):
|
||||||
|
layout = self.find(QHBoxLayout, "horizontalLayout")
|
||||||
|
self._editor = PamhyrPythonEditor()
|
||||||
|
layout.insertWidget(0, self._editor)
|
||||||
|
|
||||||
def setup_connections(self):
|
def setup_connections(self):
|
||||||
self._hup_sc = QShortcut(QKeySequence("ctrl+Up"), self)
|
self._hup_sc = QShortcut(QKeySequence("ctrl+Up"), self)
|
||||||
self._hdown_sc = QShortcut(QKeySequence("ctrl+Down"), self)
|
self._hdown_sc = QShortcut(QKeySequence("ctrl+Down"), self)
|
||||||
@@ -77,31 +85,35 @@ class ReplWindow(ASubMainWindow, ListedSubWindow):
|
|||||||
def history_up(self):
|
def history_up(self):
|
||||||
if self._history_ind < len(self._history):
|
if self._history_ind < len(self._history):
|
||||||
self._history_ind += 1
|
self._history_ind += 1
|
||||||
self.set_plaintext_edit_text("plainTextEdit", self._history[-self._history_ind])
|
self._editor.setText(self._history[-self._history_ind])
|
||||||
|
|
||||||
def history_down(self):
|
def history_down(self):
|
||||||
if self._history_ind > 0:
|
if self._history_ind > 0:
|
||||||
self._history_ind -= 1
|
self._history_ind -= 1
|
||||||
self.set_plaintext_edit_text("plainTextEdit", self._history[-self._history_ind])
|
self._editor.setText(self._history[-self._history_ind])
|
||||||
else:
|
else:
|
||||||
self.set_plaintext_edit_text("plainTextEdit", "")
|
self._editor.setText("")
|
||||||
|
|
||||||
def eval_python(self):
|
def eval_python(self):
|
||||||
code = self.get_plaintext_edit_text("plainTextEdit")
|
code = self._editor.text()
|
||||||
self._history.append(code)
|
self._history.append(code)
|
||||||
self.set_plaintext_edit_text("plainTextEdit", "")
|
self._editor.setText("")
|
||||||
self._history_ind = 0
|
self._history_ind = 0
|
||||||
|
|
||||||
|
# Code to rich_code
|
||||||
rich_code = code.strip().split("\n")
|
rich_code = code.strip().split("\n")
|
||||||
|
# Add return variable for results display at last row
|
||||||
rich_code[-1] = "self.__debug_exec_result__ = " + rich_code[-1]
|
rich_code[-1] = "self.__debug_exec_result__ = " + rich_code[-1]
|
||||||
rich_code = "\n".join(rich_code)
|
rich_code = "\n".join(rich_code)
|
||||||
logger.debug(f"User debug command : {rich_code}")
|
logger.debug(f"User debug command : \n{rich_code}")
|
||||||
try:
|
try:
|
||||||
value = exec(rich_code)
|
value = exec(rich_code)
|
||||||
value = self.__debug_exec_result__
|
value = self.__debug_exec_result__
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
value = f"<font color=\"red\">" + str(e) + "</font>"
|
value = f"<font color=\"red\">" + str(e) + "</font>"
|
||||||
|
|
||||||
|
# Display code
|
||||||
msg = f"<font color=\"grey\"> # " + code + " #</font>"
|
msg = f"<font color=\"grey\"> # " + code + " #</font>"
|
||||||
self.find(QTextEdit, "textEdit").append(msg)
|
self.find(QTextEdit, "textEdit").append(msg)
|
||||||
|
# Display results
|
||||||
self.find(QTextEdit, "textEdit").append(str(value))
|
self.find(QTextEdit, "textEdit").append(str(value))
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# Window.py -- 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 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QUrl
|
||||||
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QAction
|
||||||
|
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
|
||||||
|
|
||||||
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
class DocWindow(PamhyrWindow):
|
||||||
|
_pamhyr_ui = "WebView"
|
||||||
|
_pamhyr_name = "Doc"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _path_file(cls, filename):
|
||||||
|
if ".py" in sys.argv[0]:
|
||||||
|
return os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
"..", "..", "..", "doc", filename
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
"..", "..", "..", "..", "doc", filename
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, filename=None,
|
||||||
|
study=None, config=None,
|
||||||
|
parent=None):
|
||||||
|
super(DocWindow, self).__init__(
|
||||||
|
title=self._pamhyr_name,
|
||||||
|
study=study,
|
||||||
|
config=config,
|
||||||
|
options=[],
|
||||||
|
parent=parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self._path = self._path_file(filename)
|
||||||
|
|
||||||
|
self.setup_web_engine()
|
||||||
|
self.setup_url(self._path)
|
||||||
|
self.setup_connection()
|
||||||
|
|
||||||
|
def setup_connection(self):
|
||||||
|
self.findChild(QAction, "action_back").triggered.connect(self.back)
|
||||||
|
self.findChild(QAction, "action_forward").triggered.connect(
|
||||||
|
self.forward)
|
||||||
|
|
||||||
|
self.findChild(QAction, "action_open").triggered.connect(self.open)
|
||||||
|
|
||||||
|
def setup_web_engine(self):
|
||||||
|
vl = self.find(QVBoxLayout, "verticalLayout")
|
||||||
|
self._web_view = QWebEngineView()
|
||||||
|
|
||||||
|
settings = self._web_view.settings()
|
||||||
|
settings.setAttribute(QWebEngineSettings.PluginsEnabled, True)
|
||||||
|
settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True)
|
||||||
|
settings.setAttribute(QWebEngineSettings.PdfViewerEnabled, True)
|
||||||
|
|
||||||
|
vl.addWidget(self._web_view)
|
||||||
|
|
||||||
|
def setup_url(self, filename):
|
||||||
|
logger.info(f"Open documentation : {filename}")
|
||||||
|
self._web_view.setUrl(QUrl(f"file://{self._path_file(filename)}"))
|
||||||
|
|
||||||
|
def back(self):
|
||||||
|
self._web_view.back()
|
||||||
|
|
||||||
|
def forward(self):
|
||||||
|
self._web_view.forward()
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
url = QUrl(f"file://{self._path}")
|
||||||
|
QDesktopServices.openUrl(url)
|
||||||
+11
-5
@@ -16,9 +16,15 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from View.ASubWindow import ASubWindow
|
from View.Tools.PamhyrWindow import PamhyrWindow
|
||||||
|
|
||||||
class DummyWindow(ASubWindow):
|
|
||||||
def __init__(self, title="Dummy", parent=None):
|
class DummyWindow(PamhyrWindow):
|
||||||
super(DummyWindow, self).__init__(name=title, ui="dummy", parent=parent)
|
__ui = "Dummy"
|
||||||
self.ui.setWindowTitle(title)
|
__name = "Pamhyr Dummy Window"
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(DummyWindow, self).__init__(
|
||||||
|
title=self.__name,
|
||||||
|
parent=parent,
|
||||||
|
)
|
||||||
Loaded 100 of 215 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user