diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5e670bc1..19d0962c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,22 +1,130 @@
+# .gitlab-ci.yml -- Pamhyr gitlab-ci
+# 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 .
+
stages:
- build
- test
+ - package
- release
#########
# BUILD #
#########
+build-mage-linux:
+ stage: build
+ tags:
+ - linux
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
+ script:
+ - curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test5/downloads/packages/mage_linux.tgz
+ - mkdir -p mage
+ - cd mage
+ - tar xvf ../mage.tgz
+ artifacts:
+ paths:
+ - mage/mage
+ - mage/mage_extraire
+ - mage/mailleurPF
+
+# build-mage-linux:
+# stage: build
+# 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:
+ - linux
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
+ script:
+ - curl -L -o mage.tgz https://gitlab.irstea.fr/jean-baptiste.faure/mage/-/releases/Test5/downloads/packages/mage_windows.tgz
+ - mkdir -p mage
+ - cd mage
+ - tar xvf ../mage.tgz
+ artifacts:
+ paths:
+ - mage/mage.exe
+ - mage/mage_extraire.exe
+ - mage/mailleurPF.exe
+
+# build-mage-windows:
+# stage: build
+# 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:
stage: build
+ tags:
+ - linux
script:
- - echo "TODO build pamhyr"
+ - cd packages
+ - ./version.sh "$CI_COMMIT_BRANCH" "$CI_COMMIT_TAG" "$CI_COMMIT_SHORT_SHA"
+ artifacts:
+ paths:
+ - VERSION
-# build-lang:
-# stage: build
-# script:
-# - cd ./src/lang/
-# - ./create_ts.sh
+build-lang:
+ stage: build
+ tags:
+ - linux
+ script:
+ - cd ./src/lang/
+ - ./create_ts.sh
+ artifacts:
+ paths:
+ - src/lang/*.qm
#########
# TESTS #
@@ -32,56 +140,69 @@ test:
############
linux-package:
- stage: release
+ stage: package
tags:
- release
- linux
+ needs:
+ - job: build-lang
+ artifacts: true
+ - job: build
+ artifacts: true
+ - job: build-mage-linux
+ artifacts: true
rules:
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_TAG
- when: never
+ - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
artifacts:
paths:
- # - packages/pamhyr-src.tar.gz
- packages/pamhyr-gnulinux-amd64.tar.xz
script:
- cd packages
- ./linux.sh
-# windows-package:
-# stage: release
-# tags:
-# - release
-# - wine
-# rules:
-# - if: $CI_COMMIT_BRANCH == 'master'
-# - if: $CI_COMMIT_TAG
-# when: never
-# artifacts:
-# paths:
-# - packages/pamhyr-win-amd64.zip
-# - packages/pamhyr-win-amd64.exe
-# script:
-# - cd packages
-# - ./wine.sh ci
+windows-package:
+ stage: package
+ tags:
+ - release
+ - wine
+ needs:
+ - job: build-lang
+ artifacts: true
+ - job: build
+ artifacts: true
+ - job: build-mage-windows
+ artifacts: true
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'master' || $CI_COMMIT_TAG
+ artifacts:
+ paths:
+ - packages/pamhyr-win-amd64.exe
+ script:
+ - cd packages
+ - ./windows.bat
+
+###########
+# RELEASE #
+###########
tag-release:
stage: release
tags:
- release
- linux
- - wine
+ needs:
+ - job: linux-package
+ artifacts: true
+ - job: windows-package
+ artifacts: true
rules:
- if: $CI_COMMIT_TAG
artifacts:
paths:
- packages/pamhyr-gnulinux-amd64.tar.xz
- # - packages/pamhyr-win-amd64.zip
- # - packages/pamhyr-win-amd64.exe
+ - packages/pamhyr-win-amd64.exe
script:
- cd packages
- - ./linux.sh
- # - ./wine.sh ci
release:
name: '$CI_COMMIT_TAG'
description: 'Automatic release from tag $CI_COMMIT_TAG'
@@ -92,12 +213,8 @@ tag-release:
- name: 'GNU/Linux amd64 (tar.xz)'
url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-gnulinux-amd64.tar.xz'
filepath: '/packages/pamhyr-gnulinux-amd64.tar.xz'
- link_type: 'other'
- # - name: 'Windows amd64 (zip)'
- # url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-win-amd64.zip'
- # filepath: '/packages/pamhyr-win-amd64.zip'
- # link_type: 'Packages'
- # - name: 'Windows amd64 (exe)'
- # url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-win-amd64.exe'
- # filepath: '/packages/pamhyr-win-amd64.exe'
- # link_type: 'Packages'
+ link_type: 'package'
+ - name: 'Windows amd64 (exe)'
+ url: '${CI_PROJECT_URL}/-/jobs/${CI_JOB_ID}/artifacts/raw/packages/pamhyr-win-amd64.exe'
+ filepath: '/packages/pamhyr-win-amd64.exe'
+ link_type: 'package'
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..e69de29b
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..0ce9cdac
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Sylvain COULIBALY, INRAE, 2020 - 2022
+Théophile TERRAZ, INRAE, 2022 - 2023
+Pierre-Antoine ROUBY, INRAE, 2023
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..001d0883
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ 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 .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ pamhyr Copyright (C) 2023 INRAE
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/VERSION b/VERSION
new file mode 100644
index 00000000..5664e303
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+git
diff --git a/packages/linux.sh b/packages/linux.sh
index 1cd72d28..44770b6e 100755
--- a/packages/linux.sh
+++ b/packages/linux.sh
@@ -1,5 +1,21 @@
#! /bin/sh
+# linux.sh -- 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 .
+
echo " *** RM OLD ENV"
rm dist/ -rf
@@ -35,6 +51,18 @@ cp -r ../src/View/ui/*.ui dist/pamhyr/View/ui/
mkdir -p dist/pamhyr/lang
cp -r ../src/lang/*.qm dist/pamhyr/lang/
+cp ../VERSION dist/pamhyr/
+cp ../AUTHORS dist/pamhyr/
+cp ../LICENSE dist/pamhyr/
+
+mkdir -p dist/pamhyr/mage/
+cp ../mage/mage dist/pamhyr/mage/
+cp ../mage/mage_extraire dist/pamhyr/mage/
+cp ../mage/mailleurPF dist/pamhyr/mage/
+
+mkdir -p dist/pamhyr/tests_cases/
+mkdir -p dist/pamhyr/tests_cases/Saar
+cp ../tests_cases/Saar/Saar.pamhyr dist/pamhyr/tests_cases/Saar/
echo " *** MAKE SRC PACKAGE"
diff --git a/packages/pamhyr.nsi b/packages/pamhyr.nsi
index 35be24ad..ccd25a76 100644
--- a/packages/pamhyr.nsi
+++ b/packages/pamhyr.nsi
@@ -1,8 +1,12 @@
!include "x64.nsh"
-Name "PAMHYR"
+!define LIC_NAME "LICENSE"
+!define APP_NAME "PAMHYR"
+Name "PAMHYR"
OutFile "pamhyr-win-amd64.exe"
+LicenseData "..\LICENSE"
+LicenseText "I Agree"
RequestExecutionLevel admin
@@ -11,6 +15,7 @@ InstallDir $PROGRAMFILES\PAMHYR
InstallDirRegKey HKLM "Software\PAMHYR" "Install_Dir"
+Page license
Page components
Page directory
Page instfiles
diff --git a/packages/version.sh b/packages/version.sh
new file mode 100755
index 00000000..8f5e8bcf
--- /dev/null
+++ b/packages/version.sh
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+# version.sh -- 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 .
+
+# ./version.sh BRANCH TAG COMMIT
+
+if [ -z $2 ];
+then
+ echo "$1-$3" > ../VERSION
+else
+ echo "$2" > ../VERSION
+fi
diff --git a/packages/windows.bat b/packages/windows.bat
new file mode 100644
index 00000000..16aba85c
--- /dev/null
+++ b/packages/windows.bat
@@ -0,0 +1,54 @@
+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 .
+
+@ECHO ON
+
+rem Python environment
+python -m pip install -r ..\requirements.txt
+
+rem Build windows version
+pyinstaller ..\src\pamhyr.py -y
+
+rem Copy data
+mkdir dist\pamhyr\View\ui\ressources
+mkdir dist\pamhyr\View\ui\Widgets
+
+rem UI
+copy /y ..\src\View\ui\ressources\ dist\pamhyr\View\ui\ressources
+copy /y ..\src\View\ui\Widgets\*.ui dist\pamhyr\View\ui\Widgets
+copy /y ..\src\View\ui\*.ui dist\pamhyr\View\ui\
+
+rem Lang
+copy /y ..\src\lang\*.qm dist\pamhyr\lang\
+
+rem Information
+copy /y ..\VERSION dist\pamhyr\
+copy /y ..\AUTHORS dist\pamhyr\
+copy /y ..\LICENSE dist\pamhyr\
+
+rem MAGE
+mkdir dist\pamhyr\mage
+copy /y ..\mage\mage.exe dist\pamhyr\mage\
+copy /y ..\mage\mage_extraire.exe dist\pamhyr\mage\
+copy /y ..\mage\mailleurPF.exe dist\pamhyr\mage\
+
+rem Copy tests_cases
+mkdir dist\pamhyr\tests_cases
+mkdir dist\pamhyr\tests_cases\Saar
+copy /y ..\tests_cases\Saar\Saar.pamhyr dist\pamhyr\tests_cases\Saar\
+
+rem Make installer
+"C:\Program Files (x86)\NSIS\makensis.exe" pamhyr.nsi
diff --git a/packages/wine.sh b/packages/wine.sh
index 1a769f51..4f794c51 100755
--- a/packages/wine.sh
+++ b/packages/wine.sh
@@ -1,5 +1,21 @@
#! /bin/sh
+# wine.sh -- 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 .
+
echo " *** SETUP ENV"
export WINARCH=win64
@@ -70,6 +86,9 @@ cp -r ../src/View/ui/ressources/ dist/pamhyr/View/ui/
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/
+cp ../AUTHORS dist/pamhyr/
+
# Update TS and build QM files
OLD_PWD=$PWD
cd ../src/lang/
diff --git a/src/AUTHORS b/src/AUTHORS
new file mode 120000
index 00000000..9eadf712
--- /dev/null
+++ b/src/AUTHORS
@@ -0,0 +1 @@
+../AUTHORS
\ No newline at end of file
diff --git a/src/Checker/Checker.py b/src/Checker/Checker.py
index 6e87a601..d10a8c4d 100644
--- a/src/Checker/Checker.py
+++ b/src/Checker/Checker.py
@@ -1,3 +1,19 @@
+# Checker.py -- Pamhyr abstract checker 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 .
+
# -*- coding: utf-8 -*-
from enum import Enum
diff --git a/src/Checker/Mage.py b/src/Checker/Mage.py
index 4e121d51..edb0c349 100644
--- a/src/Checker/Mage.py
+++ b/src/Checker/Mage.py
@@ -1,3 +1,19 @@
+# Mage.py -- Pamhyr MAGE checkers
+# 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 .
+
# -*- coding: utf-8 -*-
import time
diff --git a/src/Checker/Study.py b/src/Checker/Study.py
index c6c41fed..868ac104 100644
--- a/src/Checker/Study.py
+++ b/src/Checker/Study.py
@@ -1,3 +1,19 @@
+# Study.py -- Pamhyr study checkers
+# 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 .
+
# -*- coding: utf-8 -*-
import time
diff --git a/src/Model/BoundaryCondition/BoundaryCondition.py b/src/Model/BoundaryCondition/BoundaryCondition.py
index 152a6269..86e0f1d2 100644
--- a/src/Model/BoundaryCondition/BoundaryCondition.py
+++ b/src/Model/BoundaryCondition/BoundaryCondition.py
@@ -1,10 +1,30 @@
+# BoundaryCondition.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 .
+
# -*- coding: utf-8 -*-
+import logging
+
from tools import trace, timer, old_pamhyr_date_to_timestamp
from Model.DB import SQLSubModel
from Model.Except import NotImplementedMethodeError
+logger = logging.getLogger()
+
class BoundaryCondition(SQLSubModel):
_sub_classes = []
_id_cnt = 0
@@ -301,14 +321,17 @@ class BoundaryCondition(SQLSubModel):
new = cls(name = self.name, status = self._status)
new.node = self.node
- for i, _ in self.data:
+ for i, _ in enumerate(self.data):
new.add(i)
for i in [0,1]:
for j in [0,1]:
if self._header[i] == new.header[j]:
for ind, v in self.data:
- new._set_i_c_v(ind, j, v[i])
+ try:
+ new._set_i_c_v(ind, j, v[i])
+ except Exception as e:
+ logger.info(e)
return new
diff --git a/src/Model/BoundaryCondition/BoundaryConditionList.py b/src/Model/BoundaryCondition/BoundaryConditionList.py
index d14a870b..1a342dc7 100644
--- a/src/Model/BoundaryCondition/BoundaryConditionList.py
+++ b/src/Model/BoundaryCondition/BoundaryConditionList.py
@@ -1,3 +1,19 @@
+# BoundaryConditionList.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 .
+
# -*- coding: utf-8 -*-
from copy import copy
diff --git a/src/Model/BoundaryCondition/BoundaryConditionTypes.py b/src/Model/BoundaryCondition/BoundaryConditionTypes.py
index c87e5b83..b2c73f11 100644
--- a/src/Model/BoundaryCondition/BoundaryConditionTypes.py
+++ b/src/Model/BoundaryCondition/BoundaryConditionTypes.py
@@ -1,3 +1,19 @@
+# BoundaryConditionTypes.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 .
+
# -*- coding: utf-8 -*-
from Model.Except import NotImplementedMethodeError
diff --git a/src/Model/DB.py b/src/Model/DB.py
index 90869740..ef7d729d 100644
--- a/src/Model/DB.py
+++ b/src/Model/DB.py
@@ -1,3 +1,19 @@
+# DB.py -- Pamhyr abstract model database 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 .
+
# -*- coding: utf-8 -*-
import os
diff --git a/src/Model/Except.py b/src/Model/Except.py
index ad311666..7d5e3959 100644
--- a/src/Model/Except.py
+++ b/src/Model/Except.py
@@ -1,3 +1,19 @@
+# Except.py -- Pamhyr model exceptions
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import (
diff --git a/src/Model/Friction/Friction.py b/src/Model/Friction/Friction.py
index f7328dd4..18167a86 100644
--- a/src/Model/Friction/Friction.py
+++ b/src/Model/Friction/Friction.py
@@ -1,3 +1,19 @@
+# Friction.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 .
+
# -*- coding: utf-8 -*-
from tools import trace, timer
diff --git a/src/Model/Friction/FrictionList.py b/src/Model/Friction/FrictionList.py
index a82c9f22..21e10695 100644
--- a/src/Model/Friction/FrictionList.py
+++ b/src/Model/Friction/FrictionList.py
@@ -1,3 +1,19 @@
+# FrictionList.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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/Model/Geometry/Point.py b/src/Model/Geometry/Point.py
index 98d1e348..cc1971c0 100644
--- a/src/Model/Geometry/Point.py
+++ b/src/Model/Geometry/Point.py
@@ -1,3 +1,19 @@
+# Point.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 .
+
# -*- coding: utf-8 -*-
from Model.Except import NotImplementedMethodeError
diff --git a/src/Model/Geometry/PointXY.py b/src/Model/Geometry/PointXY.py
index 9b84ef7c..7448d045 100644
--- a/src/Model/Geometry/PointXY.py
+++ b/src/Model/Geometry/PointXY.py
@@ -1,3 +1,19 @@
+# PointXY.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 .
+
# -*- coding: utf-8 -*-
from math import dist
diff --git a/src/Model/Geometry/PointXYZ.py b/src/Model/Geometry/PointXYZ.py
index ff0a62fb..33a3bebf 100644
--- a/src/Model/Geometry/PointXYZ.py
+++ b/src/Model/Geometry/PointXYZ.py
@@ -1,3 +1,19 @@
+# PointXYZ.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 .
+
# -*- coding: utf-8 -*-
from math import dist
diff --git a/src/Model/Geometry/Profile.py b/src/Model/Geometry/Profile.py
index 9fa8e9ed..d8137932 100644
--- a/src/Model/Geometry/Profile.py
+++ b/src/Model/Geometry/Profile.py
@@ -1,3 +1,19 @@
+# Profile.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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py
index cb681383..12c4ea77 100644
--- a/src/Model/Geometry/ProfileXYZ.py
+++ b/src/Model/Geometry/ProfileXYZ.py
@@ -1,3 +1,19 @@
+# ProfileXYZ.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 .
+
# -*- coding: utf-8 -*-
import numpy as np
diff --git a/src/Model/Geometry/Reach.py b/src/Model/Geometry/Reach.py
index 728cf2db..0ddf06d8 100644
--- a/src/Model/Geometry/Reach.py
+++ b/src/Model/Geometry/Reach.py
@@ -1,3 +1,19 @@
+# Reach.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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/Model/Geometry/Vector_1d.py b/src/Model/Geometry/Vector_1d.py
index 51fef7f2..a3da9358 100644
--- a/src/Model/Geometry/Vector_1d.py
+++ b/src/Model/Geometry/Vector_1d.py
@@ -1,3 +1,19 @@
+# Vector_1d.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 .
+
# -*- coding: utf-8 -*-
import numpy as np
diff --git a/src/Model/InitialConditions/InitialConditions.py b/src/Model/InitialConditions/InitialConditions.py
index bb106662..3bf747b0 100644
--- a/src/Model/InitialConditions/InitialConditions.py
+++ b/src/Model/InitialConditions/InitialConditions.py
@@ -1,3 +1,19 @@
+# InitialConditions.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 .
+
# -*- coding: utf-8 -*-
from copy import copy, deepcopy
diff --git a/src/Model/InitialConditions/InitialConditionsDict.py b/src/Model/InitialConditions/InitialConditionsDict.py
index 5e8d5fba..48da56a0 100644
--- a/src/Model/InitialConditions/InitialConditionsDict.py
+++ b/src/Model/InitialConditions/InitialConditionsDict.py
@@ -1,3 +1,19 @@
+# InitialConditionsDict.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 .
+
# -*- coding: utf-8 -*-
from copy import copy
diff --git a/src/Model/LateralContribution/LateralContribution.py b/src/Model/LateralContribution/LateralContribution.py
index 5098e9ba..38cbada4 100644
--- a/src/Model/LateralContribution/LateralContribution.py
+++ b/src/Model/LateralContribution/LateralContribution.py
@@ -1,10 +1,30 @@
+# LateralContribution.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 .
+
# -*- coding: utf-8 -*-
+import logging
+
from tools import trace, timer, old_pamhyr_date_to_timestamp
from Model.DB import SQLSubModel
from Model.Except import NotImplementedMethodeError
+logger = logging.getLogger()
+
class LateralContribution(SQLSubModel):
_sub_classes = []
_id_cnt = 0
@@ -342,14 +362,17 @@ class LateralContribution(SQLSubModel):
new.begin_kp = self.begin_kp
new.end_kp = self.end_kp
- for i, _ in self.data:
+ for i, _ in enumerate(self.data):
new.add(i)
for i in [0,1]:
for j in [0,1]:
if self._header[i] == new.header[j]:
for ind, v in self.data:
- new._set_i_c_v(ind, j, v[i])
+ try:
+ new._set_i_c_v(ind, j, v[i])
+ except Exception as e:
+ logger.info(e)
self._status.modified()
return new
diff --git a/src/Model/LateralContribution/LateralContributionList.py b/src/Model/LateralContribution/LateralContributionList.py
index 4d6a8567..ca7c111e 100644
--- a/src/Model/LateralContribution/LateralContributionList.py
+++ b/src/Model/LateralContribution/LateralContributionList.py
@@ -1,3 +1,19 @@
+# LateralContributionList.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 .
+
# -*- coding: utf-8 -*-
from copy import copy
diff --git a/src/Model/LateralContribution/LateralContributionTypes.py b/src/Model/LateralContribution/LateralContributionTypes.py
index 69d9946c..d669266a 100644
--- a/src/Model/LateralContribution/LateralContributionTypes.py
+++ b/src/Model/LateralContribution/LateralContributionTypes.py
@@ -1,3 +1,19 @@
+# LateralContributionTypes.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 .
+
# -*- coding: utf-8 -*-
from Model.Except import NotImplementedMethodeError
diff --git a/src/Model/Network/Edge.py b/src/Model/Network/Edge.py
index f1ced151..12249943 100644
--- a/src/Model/Network/Edge.py
+++ b/src/Model/Network/Edge.py
@@ -1,3 +1,19 @@
+# Edge.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 .
+
# -*- coding: utf-8 -*-
from Model.Network.Node import Node
diff --git a/src/Model/Network/Graph.py b/src/Model/Network/Graph.py
index e2d549fb..62948a2b 100644
--- a/src/Model/Network/Graph.py
+++ b/src/Model/Network/Graph.py
@@ -1,3 +1,19 @@
+# Graph.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 .
+
# -*- coding: utf-8 -*-
from functools import reduce
diff --git a/src/Model/Network/Node.py b/src/Model/Network/Node.py
index 5f37101f..7b8f52ba 100644
--- a/src/Model/Network/Node.py
+++ b/src/Model/Network/Node.py
@@ -1,3 +1,19 @@
+# Node.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 .
+
# -*- coding: utf-8 -*-
from Model.Network.Point import Point
diff --git a/src/Model/Network/Point.py b/src/Model/Network/Point.py
index 8ea0ecd9..0bb12609 100644
--- a/src/Model/Network/Point.py
+++ b/src/Model/Network/Point.py
@@ -1,3 +1,19 @@
+# Point.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 .
+
# -*- coding: utf-8 -*-
class Point(object):
diff --git a/src/Model/Results/Results.py b/src/Model/Results/Results.py
new file mode 100644
index 00000000..67698f4e
--- /dev/null
+++ b/src/Model/Results/Results.py
@@ -0,0 +1,50 @@
+# Results.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 .
+
+import logging
+import numpy as np
+
+from copy import deepcopy
+from datetime import datetime
+
+from Model.Results.River.River import River
+
+logger = logging.getLogger()
+
+class Results(object):
+ def __init__(self, study = None):
+ self._study = study
+ self._river = River(self._study)
+
+ self._meta_data = {
+ # Keep results creation date
+ "creation_date": datetime.now(),
+ }
+
+ @property
+ def date(self):
+ date = self._meta_data["creation_date"]
+ return f"{date.isoformat(sep=' ')}"
+
+ @property
+ def river(self):
+ return self._river
+
+ def set(self, key, value):
+ self._meta_data[key] = value
+
+ def get(self, key):
+ return self._meta_data[key]
diff --git a/src/Model/Results/River/River.py b/src/Model/Results/River/River.py
new file mode 100644
index 00000000..5ae1e90f
--- /dev/null
+++ b/src/Model/Results/River/River.py
@@ -0,0 +1,107 @@
+# River.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 .
+
+import logging
+
+from datetime import datetime
+
+logger = logging.getLogger()
+
+class Profile(object):
+ def __init__(self, profile, study):
+ self._study = study
+ self._profile = profile # Source profile in the study
+ self._data = {} # Dict of dict {: {: , ...}, ...}
+
+ @property
+ def name(self):
+ return self._profile.name
+
+ @property
+ def kp(self):
+ return self._profile.kp
+
+ @property
+ def geometry(self):
+ return self._profile
+
+ def set(self, timestamp, key, data):
+ if timestamp not in self._data:
+ self._data[timestamp] = {}
+
+ self._data[timestamp][key] = data
+
+ def get_ts(self, timestamp):
+ return self._data[timestamp]
+
+ def get_key(self, key):
+ return list(
+ map(lambda ts: self._data[ts][key], self._data)
+ )
+
+ def get_ts_key(self, timestamp, key):
+ return self._data[timestamp][key]
+
+class Reach(object):
+ def __init__(self, reach, study):
+ self._study = study
+ self._reach = reach # Source reach in the study
+ self._profiles = list(
+ map(
+ lambda p: Profile(p, self._study),
+ reach.profiles
+ )
+ )
+
+ @property
+ def name(self):
+ return self._reach.name
+
+ @property
+ def geometry(self):
+ return self._reach
+
+ @property
+ def profiles(self):
+ return self._profiles.copy()
+
+ def profile(self, id):
+ return self._profiles[id]
+
+ def set(self, profile_id, timestamp, key, data):
+ self._profiles[profile_id].set(timestamp, key, data)
+
+class River(object):
+ def __init__(self, study):
+ self._study = study
+
+ # Dict with timestamps as key
+ self._reachs = []
+
+ @property
+ def reachs(self):
+ return self._reachs.copy()
+
+ def reach(self, id):
+ return self._reachs[id]
+
+ def add(self, reach_id):
+ reachs = self._study.river.enable_edges()
+
+ new = Reach(reachs[reach_id].reach, self._study)
+
+ self._reachs.append(new)
+ return new
diff --git a/src/Model/River.py b/src/Model/River.py
index b21a95a9..3041c6c7 100644
--- a/src/Model/River.py
+++ b/src/Model/River.py
@@ -1,3 +1,19 @@
+# River.py -- Pamhyr river 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 .
+
# -*- coding: utf-8 -*-
from Model.DB import SQLSubModel
diff --git a/src/Model/Saved.py b/src/Model/Saved.py
index 3f672731..60013cde 100644
--- a/src/Model/Saved.py
+++ b/src/Model/Saved.py
@@ -1,3 +1,19 @@
+# Saved.py -- Pamhyr model status 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 .
+
# -*- coding: utf-8 -*-
import logging
@@ -17,5 +33,5 @@ class SavedStatus(object):
self._saved = True
def modified(self):
- logger.debug("model status set as modified")
+ # logger.debug("model status set as modified")
self._saved = False
diff --git a/src/Model/Serializable.py b/src/Model/Serializable.py
index 57f2a4c1..0c083448 100644
--- a/src/Model/Serializable.py
+++ b/src/Model/Serializable.py
@@ -1,3 +1,19 @@
+# Serializable.py -- Pamhyr pickle abstract 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 .
+
# -*- coding: utf-8 -*-
import pickle
diff --git a/src/Model/SolverParameters/SolverParametersList.py b/src/Model/SolverParameters/SolverParametersList.py
index 88d1d567..a6471356 100644
--- a/src/Model/SolverParameters/SolverParametersList.py
+++ b/src/Model/SolverParameters/SolverParametersList.py
@@ -1,3 +1,19 @@
+# SolverParametersList.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 .
+
# -*- coding: utf-8 -*-
from copy import copy
diff --git a/src/Model/Stricklers/Stricklers.py b/src/Model/Stricklers/Stricklers.py
index cbc10009..baa484fa 100644
--- a/src/Model/Stricklers/Stricklers.py
+++ b/src/Model/Stricklers/Stricklers.py
@@ -1,3 +1,19 @@
+# Stricklers.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 .
+
# -*- coding: utf-8 -*-
from tools import trace, timer
@@ -124,7 +140,7 @@ class Stricklers(SQLSubModel):
@minor.setter
def minor(self, minor):
- self._minor = int(minor)
+ self._minor = float(minor)
@property
def medium(self):
@@ -132,4 +148,4 @@ class Stricklers(SQLSubModel):
@medium.setter
def medium(self, medium):
- self._medium = int(medium)
+ self._medium = float(medium)
diff --git a/src/Model/Stricklers/StricklersList.py b/src/Model/Stricklers/StricklersList.py
index 049d9b83..82076bb1 100644
--- a/src/Model/Stricklers/StricklersList.py
+++ b/src/Model/Stricklers/StricklersList.py
@@ -1,3 +1,19 @@
+# StricklersList.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 .
+
# -*- coding: utf-8 -*-
from tools import trace, timer
diff --git a/src/Model/Study.py b/src/Model/Study.py
index fc553f94..c907da3e 100644
--- a/src/Model/Study.py
+++ b/src/Model/Study.py
@@ -1,3 +1,19 @@
+# Study.py -- Pamhyr Study 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 .
+
# -*- coding: utf-8 -*-
import os
diff --git a/src/Scripts/plot_3DST.py b/src/Scripts/plot_3DST.py
index 2647a32a..bcadf1f1 100644
--- a/src/Scripts/plot_3DST.py
+++ b/src/Scripts/plot_3DST.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
# a lancer depuis src
diff --git a/src/Solver/ASolver.py b/src/Solver/ASolver.py
index e94bac4b..64cc01cb 100644
--- a/src/Solver/ASolver.py
+++ b/src/Solver/ASolver.py
@@ -1,8 +1,26 @@
+# ASolver.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 .
+
# -*- coding: utf-8 -*-
import os
import logging
+from tools import timer
+
try:
from signal import SIGTERM, SIGSTOP, SIGCONT
_signal = True
@@ -13,6 +31,9 @@ from enum import Enum
from Model.Except import NotImplementedMethodeError
+from Model.Results.Results import Results
+from Model.Results.River.River import River, Reach, Profile
+
logger = logging.getLogger()
class STATUS(Enum):
@@ -148,25 +169,72 @@ class AbstractSolver(object):
"""
raise NotImplementedMethodeError(self, self.log_file)
+ ###########
+ # RESULTS #
+ ###########
+
+ @timer
+ def results(self, study, repertory, qlog = None):
+ results = Results(study = study)
+ return results
+
#######
# Run #
#######
+ def _install_dir(self):
+ return os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__),
+ ".."
+ )
+ )
+
+ def _format_command(self, cmd, path = ""):
+ """Format command line
+
+ Args:
+ cmd: The command line
+ path: Optional path string (replace @path in cmd)
+
+ Returns:
+ The executable and list of arguments
+ """
+ # HACK: Works in most case... Trust me i'm an engineer
+
+ cmd = cmd.replace("@install_dir", self._install_dir())
+ cmd = cmd.replace("@path", path.replace(" ", "\ "))
+ cmd = cmd.replace("@input", self.input_param())
+ cmd = cmd.replace("@dir", self._process.workingDirectory())
+
+ logger.debug(f"! {cmd}")
+
+ if cmd[0] == "\"":
+ # Command line executable path is between " char
+ cmd = cmd.split("\"")
+ exe = cmd[1].replace("\ ", " ")
+ args = "\"".join(cmd[2:]).split(" ")[1:]
+ else:
+ # We suppose the command line executable path as no space char
+ cmd = cmd.replace("\ ", "&_&").split(" ")
+ exe = cmd[0].replace("&_&", " ")
+ args = list(map(lambda s: s.replace("&_&", "\ "), cmd[1:]))
+
+ logger.info(f"! {exe} {args}")
+ return exe, args
+
def run_input_data_fomater(self):
if self._cmd_input == "":
self._run_next()
return True
cmd = self._cmd_input
- cmd = cmd.replace("@path", self._path_input)
- cmd = cmd.replace("@input", self.input_param())
- cmd = cmd.replace("@dir", self._process.workingDirectory())
+ exe, args = self._format_command(cmd, self._path_input)
- logger.debug(f"! {cmd}")
-
- cmd = cmd.split()
- exe = cmd[0]
- args = cmd[1:]
+ if not os.path.exists(exe):
+ error = f"[ERROR] Path {exe} do not exists"
+ logger.info(error)
+ return error
self._process.start(
exe, args,
@@ -180,15 +248,12 @@ class AbstractSolver(object):
return True
cmd = self._cmd_solver
- cmd = cmd.replace("@path", self._path_solver)
- cmd = cmd.replace("@input", self.input_param())
- cmd = cmd.replace("@dir", self._process.workingDirectory())
+ exe, args = self._format_command(cmd, self._path_solver)
- logger.debug(f"! {cmd}")
-
- cmd = cmd.split()
- exe = cmd[0]
- args = cmd[1:]
+ if not os.path.exists(exe):
+ error = f"[ERROR] Path {exe} do not exists"
+ logger.info(error)
+ return error
self._process.start(
exe, args,
@@ -203,15 +268,12 @@ class AbstractSolver(object):
return True
cmd = self._cmd_output
- cmd = cmd.replace("@path", self._path_output)
- cmd = cmd.replace("@input", self.input_param())
- cmd = cmd.replace("@dir", self._process.workingDirectory())
+ exe, args = self._format_command(cmd, self._path_output)
- logger.debug(f"! {cmd}")
-
- cmd = cmd.split()
- exe = cmd[0]
- args = cmd[1:]
+ if not os.path.exists(exe):
+ error = f"[ERROR] Path {exe} do not exists"
+ logger.info(error)
+ return error
self._process.start(
exe, args,
@@ -228,7 +290,9 @@ class AbstractSolver(object):
def _run_next(self):
self._step += 1
if self._step < len(self._runs):
- self._runs[self._step]()
+ res = self._runs[self._step]()
+ if res is not True:
+ self._output.put(res)
else:
self._status = STATUS.STOPED
@@ -254,7 +318,9 @@ class AbstractSolver(object):
]
self._step = 0
# Run first step
- self._runs[0]()
+ res = self._runs[0]()
+ if res is not True:
+ self._output.put(res)
def kill(self):
if self._process is None:
diff --git a/src/Solver/GenericSolver.py b/src/Solver/GenericSolver.py
index a80adf23..9e588bae 100644
--- a/src/Solver/GenericSolver.py
+++ b/src/Solver/GenericSolver.py
@@ -1,3 +1,19 @@
+# GenericSolver.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 .
+
# -*- coding: utf-8 -*-
from Solver.ASolver import (
diff --git a/src/Solver/Mage.py b/src/Solver/Mage.py
index 125fcfff..6c129f88 100644
--- a/src/Solver/Mage.py
+++ b/src/Solver/Mage.py
@@ -1,12 +1,35 @@
+# Mage.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 .
+
# -*- coding: utf-8 -*-
import os
+import logging
+import numpy as np
from tools import timer
from Solver.ASolver import AbstractSolver
from Checker.Mage import MageNetworkGraphChecker
+from Model.Results.Results import Results
+from Model.Results.River.River import River, Reach, Profile
+
+logger = logging.getLogger()
+
def mage_file_open(filepath, mode):
f = open(filepath, mode)
@@ -321,6 +344,21 @@ class Mage(AbstractSolver):
return True
+ ###########
+ # RESULTS #
+ ###########
+
+ def read_bin(self, study, repertory, results, qlog = None):
+ return
+
+ @timer
+ def results(self, study, repertory, qlog = None):
+ results = Results(study = study)
+
+ self.read_bin(study, repertory, results, qlog)
+
+ return results
+
##########
# MAGE 7 #
##########
@@ -434,3 +472,128 @@ class Mage8(Mage):
self._export_REP(study, repertory, files, qlog)
return True
+
+ ###########
+ # RESULTS #
+ ###########
+
+ def read_bin(self, study, repertory, results, qlog = None):
+ logger.info(f"read_bin: Start ...")
+
+ with mage_file_open(os.path.join(repertory, f"0.BIN"), "r") as f:
+ newline = lambda: np.fromfile(f, dtype=np.int32, count=1)
+ endline = lambda: np.fromfile(f, dtype=np.int32, count=1)
+
+ read_int = lambda size: np.fromfile(f, dtype=np.int32, count=size)
+ read_float = lambda size: np.fromfile(f, dtype=np.float32, count=size)
+ read_float64 = lambda size: np.fromfile(f, dtype=np.float64, count=size)
+
+ # Meta data (1st line)
+ newline()
+
+ data = read_int(3)
+
+ nb_reach = data[0]
+ nb_profile = data[1]
+ mage_version = data[2]
+
+ logger.debug(f"read_bin: nb_reach = {nb_reach}")
+ logger.debug(f"read_bin: nb_profile = {nb_profile}")
+ logger.debug(f"read_bin: mage_version = {mage_version}")
+
+ if mage_version <= 80:
+ msg = (
+ "Read BIN files: " +
+ f"Possible incompatible mage version '{mage_version}', " +
+ "please check your solver configuration..."
+ )
+ logger.warning(msg)
+
+ if qlog is not None:
+ qlog.put("[WARNING] " + msg)
+
+ results.set("solver_version", f"Mage8 ({mage_version})")
+ results.set("nb_reach", f"{nb_reach}")
+ results.set("nb_profile", f"{nb_profile}")
+
+ endline()
+
+ # Reach information (2nd line)
+ newline()
+
+ reachs = []
+ iprofiles = {}
+ reach_offset = {}
+
+ data = read_int(2*nb_reach)
+
+ for i in range(nb_reach):
+ # Add results reach to reach list
+ r = results.river.add(i)
+ reachs.append(r)
+
+ # ID of first and last reach profiles
+ i1 = data[2*i] - 1
+ i2 = data[2*i+1] - 1
+
+ # Add profile id correspondance to reach
+ key = (i1, i2)
+ iprofiles[key] = r
+
+ # Profile ID offset
+ reach_offset[r] = i1
+
+ logger.debug(f"read_bin: iprofiles = {iprofiles}")
+
+ endline()
+
+ # X (3rd line)
+ newline()
+ _ = read_float(nb_profile)
+ endline()
+
+ # Z and Y (4th line)
+ newline()
+ _ = read_float(3*nb_profile)
+ endline()
+
+ # Data
+ newline()
+
+ ip_to_r = lambda i: iprofiles[
+ next(
+ filter(
+ lambda k: k[0] <= i <= k[1],
+ iprofiles
+ )
+ )
+ ]
+ ip_to_ri = lambda r, i: i - reach_offset[r]
+
+ ts = set()
+ end = False
+ while not end:
+ n = read_int(1)[0]
+ timestamp = read_float64(1)[0]
+ key = bytearray(np.fromfile(f, dtype=np.byte, count=1)).decode()
+ data = read_float(n)
+
+ logger.debug(f"read_bin: timestamp = {timestamp} sec")
+ ts.add(timestamp)
+
+ if key in ["Z", "Q"]:
+ for i, d in enumerate(data):
+ # Get reach corresponding to profile ID
+ reach = ip_to_r(i)
+ # Get profile id in reach
+ ri = ip_to_ri(reach, i)
+
+ # Set data for profile RI
+ reach.set(ri, timestamp, key, d)
+
+ endline()
+ end = newline().size <= 0
+
+ logger.debug(reachs[0].profiles[0]._data)
+ results.set("timestamps", ts)
+ logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
diff --git a/src/Solver/Solvers.py b/src/Solver/Solvers.py
index 58db6f49..221f1ff4 100644
--- a/src/Solver/Solvers.py
+++ b/src/Solver/Solvers.py
@@ -1,3 +1,19 @@
+# Solvers.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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/VERSION b/src/VERSION
new file mode 120000
index 00000000..6ff19de4
--- /dev/null
+++ b/src/VERSION
@@ -0,0 +1 @@
+../VERSION
\ No newline at end of file
diff --git a/src/View/ASubWindow.py b/src/View/ASubWindow.py
index 478993cf..4e1c1327 100644
--- a/src/View/ASubWindow.py
+++ b/src/View/ASubWindow.py
@@ -1,3 +1,19 @@
+# ASubWindow.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 .
+
# -*- coding: utf-8 -*-
import os
@@ -19,6 +35,7 @@ from PyQt5.QtWidgets import (
QRadioButton, QComboBox, QFileDialog,
QMessageBox, QTableView, QAction,
QDateTimeEdit, QWidget, QPlainTextEdit,
+ QLabel,
)
from PyQt5.QtCore import (
QTime, QDateTime,
@@ -61,13 +78,14 @@ class WindowToolKit(object):
return header, values
- def file_dialog(self, select_file=True, callback=lambda x: None):
+ def file_dialog(self, select_file=True, callback=lambda x: None, directory=None):
"""Open a new file dialog and send result to callback function
Args:
select_file: Select a file if True, else select a dir
callback: The callback function with one arguments, files
selection list
+ directory: Defaut directory
Returns:
The returns of callback
@@ -80,6 +98,8 @@ class WindowToolKit(object):
mode = QFileDialog.FileMode.Directory
dialog.setFileMode(mode)
+ if directory is not None:
+ dialog.setDirectory(directory)
if dialog.exec_():
file_names = dialog.selectedFiles()
@@ -130,6 +150,30 @@ class ASubWindowFeatures(object):
return qtype
+ def get_label_text(self, name:str):
+ """Get text of label component
+
+ Args:
+ label: The label component name
+
+ Returns:
+ Text
+ """
+ return self.find(QLabel, name).text()
+
+ def set_label_text(self, name:str, text:str):
+ """Set text of label component
+
+ Args:
+ text_edit: The label component name
+ text: The text
+
+ Returns:
+ Nothing
+ """
+ self.find(QLabel, name).setText(text)
+
+
def set_line_edit_text(self, name:str, text:str):
"""Set text of line edit component
@@ -421,10 +465,12 @@ class ASubWindowFeatures(object):
class ASubMainWindow(QMainWindow, ASubWindowFeatures, WindowToolKit):
def __init__(self, name="", ui="dummy", parent=None):
super(ASubMainWindow, self).__init__(parent=parent)
- self.ui = loadUi(
- os.path.join(os.path.dirname(__file__), "ui", f"{ui}.ui"),
- self
- )
+ if ui is not None:
+ self.ui = loadUi(
+ os.path.join(os.path.dirname(__file__), "ui", f"{ui}.ui"),
+ self
+ )
+
self.name = name
self.parent = parent
if self.parent is not None:
diff --git a/src/View/About/Window.py b/src/View/About/Window.py
index 9f84ad86..7c269aaf 100644
--- a/src/View/About/Window.py
+++ b/src/View/About/Window.py
@@ -1,8 +1,63 @@
+# 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 .
+
# -*- coding: utf-8 -*-
+import os
+import logging
+
from View.ASubWindow import ASubWindow
+from PyQt5.QtCore import QCoreApplication
+
+_translate = QCoreApplication.translate
+logger = logging.getLogger()
+
class AboutWindow(ASubWindow):
+ def _path_file(self, filename):
+ return os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__),
+ "..", "..", filename
+ )
+ )
+
+
def __init__(self, title="About", parent=None):
super(AboutWindow, self).__init__(name=title, ui="about", parent=parent)
self.ui.setWindowTitle(title)
+
+ # Version
+ with open(self._path_file("VERSION"), "r") as f:
+ version = f.readline().strip()
+ logger.info(f"version: {version}")
+
+ label = self.get_label_text("label_version")
+ label = label.replace("@version", version)
+ self.set_label_text("label_version", label)
+
+ # Authors
+ with open(self._path_file("AUTHORS"), "r") as f:
+ label = ""
+ try:
+ while True:
+ author = next(f).strip()
+ logger.info(f"author: {author}")
+ label = f"\n - {author}" + label
+ except StopIteration:
+ label = _translate("About", "Contributors: ") + label
+ label = "Copyright © 2023 INRAE\n" + label
+ self.set_label_text("label_copyright", label)
diff --git a/src/View/BoundaryCondition/Edit/Plot.py b/src/View/BoundaryCondition/Edit/Plot.py
index 9f6df875..b27380a5 100644
--- a/src/View/BoundaryCondition/Edit/Plot.py
+++ b/src/View/BoundaryCondition/Edit/Plot.py
@@ -1,5 +1,23 @@
+# Plot.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 .
+
# -*- coding: utf-8 -*-
+import logging
+
from datetime import datetime
from tools import timer, trace
@@ -13,6 +31,8 @@ from View.BoundaryCondition.Edit.translate import *
_translate = QCoreApplication.translate
+logger = logging.getLogger()
+
class Plot(APlot):
def __init__(self, canvas=None, data=None,
mode = "time", toolbar=None):
@@ -25,6 +45,9 @@ class Plot(APlot):
self._mode = mode
def custom_ticks(self):
+ if self.data.header[0] != "time":
+ return
+
t0 = datetime.fromtimestamp(0)
nb = len(self.data.data)
mod = int(nb / 5)
diff --git a/src/View/BoundaryCondition/Edit/Table.py b/src/View/BoundaryCondition/Edit/Table.py
index dfe805e1..6536bd0d 100644
--- a/src/View/BoundaryCondition/Edit/Table.py
+++ b/src/View/BoundaryCondition/Edit/Table.py
@@ -1,6 +1,23 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
import logging
+import traceback
from datetime import date, time, datetime, timedelta
@@ -196,11 +213,15 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- self._undo.push(
- SetDataCommand(
- self._data, row, column, value
+ try:
+ self._undo.push(
+ SetDataCommand(
+ self._data, row, column, value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/BoundaryCondition/Edit/UndoCommand.py b/src/View/BoundaryCondition/Edit/UndoCommand.py
index b2eb09ac..4bb2605f 100644
--- a/src/View/BoundaryCondition/Edit/UndoCommand.py
+++ b/src/View/BoundaryCondition/Edit/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -17,7 +33,8 @@ class SetDataCommand(QUndoCommand):
self._index = index
self._column = column
self._old = self._data.get_i(self._index)[self._column]
- self._new = new_value
+ _type = self._data.get_type_column(self._column)
+ self._new = _type(new_value)
def undo(self):
self._data._set_i_c_v(self._index, self._column, self._old)
diff --git a/src/View/BoundaryCondition/Edit/Window.py b/src/View/BoundaryCondition/Edit/Window.py
index 4e8513fa..efcf0993 100644
--- a/src/View/BoundaryCondition/Edit/Window.py
+++ b/src/View/BoundaryCondition/Edit/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from tools import timer, trace
@@ -55,7 +71,7 @@ class EditBoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
self._title = (
_translate("Edit boundary condition", self._title) +
f" - {self._study.name} " +
- f" - {self._data.name} " +
+ f" - {self._data.name} ({self._data.id}) " +
f"({long_types[self._data.bctype]} - {node_name})"
)
diff --git a/src/View/BoundaryCondition/Edit/translate.py b/src/View/BoundaryCondition/Edit/translate.py
index 44ef5a46..4c09f5fc 100644
--- a/src/View/BoundaryCondition/Edit/translate.py
+++ b/src/View/BoundaryCondition/Edit/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/BoundaryCondition/Table.py b/src/View/BoundaryCondition/Table.py
index 98890e0c..fd39a13a 100644
--- a/src/View/BoundaryCondition/Table.py
+++ b/src/View/BoundaryCondition/Table.py
@@ -1,5 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
+import logging
+import traceback
+
from tools import trace, timer
from PyQt5.QtCore import (
@@ -27,6 +46,8 @@ from View.BoundaryCondition.UndoCommand import (
)
from View.BoundaryCondition.translate import *
+logger = logging.getLogger()
+
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -137,25 +158,29 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- if self._headers[column] == "name":
- self._undo.push(
- SetNameCommand(
- self._bcs, self._tab,row, value
+ try:
+ if self._headers[column] == "name":
+ self._undo.push(
+ SetNameCommand(
+ self._bcs, self._tab,row, value
+ )
)
- )
- elif self._headers[column] == "type":
- key = next(k for k, v in long_types.items() if v == value)
- self._undo.push(
- SetTypeCommand(
- self._bcs, self._tab,row, BC_types[key]
+ elif self._headers[column] == "type":
+ key = next(k for k, v in long_types.items() if v == value)
+ self._undo.push(
+ SetTypeCommand(
+ self._bcs, self._tab,row, BC_types[key]
+ )
)
- )
- elif self._headers[column] == "node":
- self._undo.push(
- SetNodeCommand(
- self._bcs, self._tab,row, self._data.node(value)
+ elif self._headers[column] == "node":
+ self._undo.push(
+ SetNodeCommand(
+ self._bcs, self._tab,row, self._data.node(value)
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/BoundaryCondition/UndoCommand.py b/src/View/BoundaryCondition/UndoCommand.py
index 7b1c7f5e..bbf8cb2c 100644
--- a/src/View/BoundaryCondition/UndoCommand.py
+++ b/src/View/BoundaryCondition/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -18,7 +34,7 @@ class SetNameCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._bcs.get(self._tab, self._index).name
- self._new = new_value
+ self._new = str(new_value)
def undo(self):
self._bcs.get(self._tab, self._index).name = self._old
diff --git a/src/View/BoundaryCondition/Window.py b/src/View/BoundaryCondition/Window.py
index 2e7dd430..a2853590 100644
--- a/src/View/BoundaryCondition/Window.py
+++ b/src/View/BoundaryCondition/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
@@ -49,7 +65,7 @@ logger = logging.getLogger()
class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Boundary conditions", study=None, parent=None):
- title = title + " - " + study.name
+ self._title = title + " - " + study.name
super(BoundaryConditionWindow, self).__init__(
name=title, ui="BoundaryConditions", parent=parent
@@ -63,7 +79,7 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
self.setup_graph()
self.setup_connections()
- self.ui.setWindowTitle(title)
+ self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
@@ -204,9 +220,17 @@ class BoundaryConditionWindow(ASubMainWindow, ListedSubWindow):
tab = self.current_tab()
rows = self.index_selected_rows()
for row in rows:
- win = EditBoundaryConditionWindow(
- data=self._bcs.get(tab, row),
- study=self._study,
- parent=self
+ win = self.sub_win_filter_first(
+ "Edit boundary condition",
+ contain = [f"({self._bcs.get(tab, row).id})"]
)
- win.show()
+
+ if win is None:
+ win = EditBoundaryConditionWindow(
+ data=self._bcs.get(tab, row),
+ study=self._study,
+ parent=self
+ )
+ win.show()
+ else:
+ win.activateWindow()
diff --git a/src/View/BoundaryCondition/translate.py b/src/View/BoundaryCondition/translate.py
index e191d0be..661c1ad0 100644
--- a/src/View/BoundaryCondition/translate.py
+++ b/src/View/BoundaryCondition/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/CheckList/Table.py b/src/View/CheckList/Table.py
index 071b4907..5810c4be 100644
--- a/src/View/CheckList/Table.py
+++ b/src/View/CheckList/Table.py
@@ -1,3 +1,19 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
from tools import trace, timer
diff --git a/src/View/CheckList/Window.py b/src/View/CheckList/Window.py
index d04c8913..4c40ad1f 100644
--- a/src/View/CheckList/Window.py
+++ b/src/View/CheckList/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from tools import trace, timer
diff --git a/src/View/CheckList/Worker.py b/src/View/CheckList/Worker.py
index 9137d26b..efd95ded 100644
--- a/src/View/CheckList/Worker.py
+++ b/src/View/CheckList/Worker.py
@@ -1,3 +1,19 @@
+# Worker.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 .
+
# -*- coding: utf-8 -*-
import time
diff --git a/src/View/Configure/Solver/Window.py b/src/View/Configure/Solver/Window.py
index 71d4f798..c295481f 100644
--- a/src/View/Configure/Solver/Window.py
+++ b/src/View/Configure/Solver/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from View.ASubWindow import ASubWindow
diff --git a/src/View/Configure/Window.py b/src/View/Configure/Window.py
index 818e5d9c..23a371ac 100644
--- a/src/View/Configure/Window.py
+++ b/src/View/Configure/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/View/Debug/Window.py b/src/View/Debug/Window.py
index 974eace3..346c2ce0 100644
--- a/src/View/Debug/Window.py
+++ b/src/View/Debug/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/View/DummyWindow.py b/src/View/DummyWindow.py
index 576b5188..05117bca 100644
--- a/src/View/DummyWindow.py
+++ b/src/View/DummyWindow.py
@@ -1,3 +1,19 @@
+# DummyWindow.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 .
+
# -*- coding: utf-8 -*-
from View.ASubWindow import ASubWindow
diff --git a/src/View/Frictions/PlotStricklers.py b/src/View/Frictions/PlotStricklers.py
index 8f706782..71ff6e6f 100644
--- a/src/View/Frictions/PlotStricklers.py
+++ b/src/View/Frictions/PlotStricklers.py
@@ -1,3 +1,19 @@
+# PlotStricklers.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 .
+
# -*- coding: utf-8 -*-
from tools import timer, flatten
diff --git a/src/View/Frictions/Table.py b/src/View/Frictions/Table.py
index 2c96ef97..ef9dc32f 100644
--- a/src/View/Frictions/Table.py
+++ b/src/View/Frictions/Table.py
@@ -1,5 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
+import logging
+import traceback
+
from tools import trace, timer
from PyQt5.QtCore import (
@@ -24,6 +43,8 @@ from View.Frictions.UndoCommand import (
from View.Frictions.translate import *
+logger = logging.getLogger()
+
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -132,36 +153,40 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- if self._headers[column] == "name":
- self._undo.push(
- SetNameCommand(
- self._frictions, row, value
+ try:
+ if self._headers[column] == "name":
+ self._undo.push(
+ SetNameCommand(
+ self._frictions, row, value
+ )
)
- )
- elif self._headers[column] == "begin_kp":
- self._undo.push(
- SetBeginCommand(
- self._frictions, row, value
+ elif self._headers[column] == "begin_kp":
+ self._undo.push(
+ SetBeginCommand(
+ self._frictions, row, value
+ )
)
- )
- elif self._headers[column] == "end_kp":
- self._undo.push(
- SetEndCommand(
- self._frictions, row, value
+ elif self._headers[column] == "end_kp":
+ self._undo.push(
+ SetEndCommand(
+ self._frictions, row, value
+ )
)
- )
- elif self._headers[column] == "begin_strickler":
- self._undo.push(
- SetBeginStricklerCommand(
- self._frictions, row, self._study.river.strickler(value)
+ elif self._headers[column] == "begin_strickler":
+ self._undo.push(
+ SetBeginStricklerCommand(
+ self._frictions, row, self._study.river.strickler(value)
+ )
)
- )
- elif self._headers[column] == "end_strickler":
- self._undo.push(
- SetEndStricklerCommand(
- self._frictions, row, self._study.river.strickler(value)
+ elif self._headers[column] == "end_strickler":
+ self._undo.push(
+ SetEndStricklerCommand(
+ self._frictions, row, self._study.river.strickler(value)
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/Frictions/UndoCommand.py b/src/View/Frictions/UndoCommand.py
index 0d685ace..ef902f07 100644
--- a/src/View/Frictions/UndoCommand.py
+++ b/src/View/Frictions/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -17,7 +33,7 @@ class SetNameCommand(QUndoCommand):
self._frictions = frictions
self._index = index
self._old = self._frictions.get(self._index).name
- self._new = new_value
+ self._new = str(new_value)
def undo(self):
self._frictions.get(self._index).name = self._old
@@ -32,7 +48,7 @@ class SetBeginCommand(QUndoCommand):
self._frictions = frictions
self._index = index
self._old = self._frictions.get(self._index).begin_kp
- self._new = new_value
+ self._new = float(new_value)
def undo(self):
self._frictions.get(self._index).begin_kp = float(self._old)
@@ -47,7 +63,7 @@ class SetEndCommand(QUndoCommand):
self._frictions = frictions
self._index = index
self._old = self._frictions.get(self._index).end_kp
- self._new = new_value
+ self._new = float(new_value)
def undo(self):
self._frictions.get(self._index).end_kp = float(self._old)
diff --git a/src/View/Frictions/Window.py b/src/View/Frictions/Window.py
index 18b39e3c..4af3b66c 100644
--- a/src/View/Frictions/Window.py
+++ b/src/View/Frictions/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
@@ -52,7 +68,7 @@ class FrictionsWindow(ASubMainWindow, ListedSubWindow):
self.setup_title(title)
super(FrictionsWindow, self).__init__(
- name=self._title, ui="Frictions", parent=parent
+ name=title, ui="Frictions", parent=parent
)
self.setup_sc()
@@ -230,9 +246,17 @@ class FrictionsWindow(ASubMainWindow, ListedSubWindow):
self._table.redo()
def edit_stricklers(self):
- self.strick = StricklersWindow(
- study = self._study,
- config = self.parent.conf,
- parent = self
+ strick = self.sub_win_filter_first(
+ "Stricklers",
+ contain = []
)
- self.strick.show()
+
+ if strick is None:
+ strick = StricklersWindow(
+ study = self._study,
+ config = self.parent.conf,
+ parent = self
+ )
+ strick.show()
+ else:
+ strick.activateWindow()
diff --git a/src/View/Frictions/translate.py b/src/View/Frictions/translate.py
index c404f59c..21981ab1 100644
--- a/src/View/Frictions/translate.py
+++ b/src/View/Frictions/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/Geometry/PlotAC.py b/src/View/Geometry/PlotAC.py
index 9709d3bc..fe6d933f 100644
--- a/src/View/Geometry/PlotAC.py
+++ b/src/View/Geometry/PlotAC.py
@@ -1,3 +1,19 @@
+# PlotAC.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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/View/Geometry/PlotKPZ.py b/src/View/Geometry/PlotKPZ.py
index b37f988f..eb7d5e28 100644
--- a/src/View/Geometry/PlotKPZ.py
+++ b/src/View/Geometry/PlotKPZ.py
@@ -1,3 +1,19 @@
+# PlotKPC.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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/View/Geometry/PlotXY.py b/src/View/Geometry/PlotXY.py
index 36de09cc..54e056a9 100644
--- a/src/View/Geometry/PlotXY.py
+++ b/src/View/Geometry/PlotXY.py
@@ -1,3 +1,19 @@
+# PlotXY.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 .
+
# -*- coding: utf-8 -*-
from tools import timer, trace
diff --git a/src/View/Geometry/Profile/Plot.py b/src/View/Geometry/Profile/Plot.py
index 2dc7f522..076c2703 100644
--- a/src/View/Geometry/Profile/Plot.py
+++ b/src/View/Geometry/Profile/Plot.py
@@ -1,3 +1,19 @@
+# Plot.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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/View/Geometry/Profile/Table.py b/src/View/Geometry/Profile/Table.py
index d55ebfcd..2de665aa 100644
--- a/src/View/Geometry/Profile/Table.py
+++ b/src/View/Geometry/Profile/Table.py
@@ -1,6 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
import numpy as np
+import logging
+import traceback
from tools import timer, trace
@@ -20,6 +38,8 @@ from Model.Geometry.ProfileXYZ import ProfileXYZ
from View.Geometry.Profile.UndoCommand import *
+logger = logging.getLogger()
+
_translate = QCoreApplication.translate
@@ -132,38 +152,42 @@ class TableEditableModel(QAbstractTableModel):
column = index.column()
if role == Qt.EditRole:
- if column == 0:
- self._undo_stack.push(
- SetXCommand(
- self._profile, row,
- self._profile.point(row).x,
- value
+ try:
+ if column == 0:
+ self._undo_stack.push(
+ SetXCommand(
+ self._profile, row,
+ self._profile.point(row).x,
+ value
+ )
)
- )
- elif column == 1:
- self._undo_stack.push(
- SetYCommand(
- self._profile, row,
- self._profile.point(row).y,
- value
+ elif column == 1:
+ self._undo_stack.push(
+ SetYCommand(
+ self._profile, row,
+ self._profile.point(row).y,
+ value
+ )
)
- )
- elif column == 2:
- self._undo_stack.push(
- SetZCommand(
- self._profile, row,
- self._profile.point(row).z,
- value
+ elif column == 2:
+ self._undo_stack.push(
+ SetZCommand(
+ self._profile, row,
+ self._profile.point(row).z,
+ value
+ )
)
- )
- elif column == 3:
- self._undo_stack.push(
- SetNameCommand(
- self._profile, row,
- self._profile.point(row).name,
- value
+ elif column == 3:
+ self._undo_stack.push(
+ SetNameCommand(
+ self._profile, row,
+ self._profile.point(row).name,
+ value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/Geometry/Profile/UndoCommand.py b/src/View/Geometry/Profile/UndoCommand.py
index d0d45b99..7f0cd138 100644
--- a/src/View/Geometry/Profile/UndoCommand.py
+++ b/src/View/Geometry/Profile/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from tools import trace, timer
@@ -16,9 +32,13 @@ class SetDataCommand(QUndoCommand):
self._profile = profile
self._index = index
self._old = old_value
- self._new = new_value
+ self._new = self.type(new_value)
class SetXCommand(SetDataCommand):
+ def __init__(self, reach, index, old_value, new_value):
+ self.type = float
+ super(SetXCommand, self).__init__(reach, index, old_value, new_value)
+
def undo(self):
self._profile.point(self._index).x = self._old
@@ -26,6 +46,10 @@ class SetXCommand(SetDataCommand):
self._profile.point(self._index).x = self._new
class SetYCommand(SetDataCommand):
+ def __init__(self, reach, index, old_value, new_value):
+ self.type = float
+ super(SetYCommand, self).__init__(reach, index, old_value, new_value)
+
def undo(self):
self._profile.point(self._index).y = self._old
@@ -33,6 +57,10 @@ class SetYCommand(SetDataCommand):
self._profile.point(self._index).y = self._new
class SetZCommand(SetDataCommand):
+ def __init__(self, reach, index, old_value, new_value):
+ self.type = float
+ super(SetZCommand, self).__init__(reach, index, old_value, new_value)
+
def undo(self):
self._profile.point(self._index).z = self._old
@@ -40,6 +68,10 @@ class SetZCommand(SetDataCommand):
self._profile.point(self._index).z = self._new
class SetNameCommand(SetDataCommand):
+ def __init__(self, reach, index, old_value, new_value):
+ self.type = str
+ super(SetNameCommand, self).__init__(reach, index, old_value, new_value)
+
def undo(self):
self._profile.point(self._index).name = self._old
diff --git a/src/View/Geometry/Profile/Window.py b/src/View/Geometry/Profile/Window.py
index 815cc2ec..54d1e011 100644
--- a/src/View/Geometry/Profile/Window.py
+++ b/src/View/Geometry/Profile/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import copy
@@ -21,7 +37,7 @@ from PyQt5.QtWidgets import (
from Model.Geometry.Reach import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ
-from View.ASubWindow import WindowToolKit
+from View.ASubWindow import ASubMainWindow
from View.Geometry.Profile.mainwindow_ui_profile import Ui_MainWindow
from View.Geometry.Profile.Plot import Plot
from View.Geometry.Profile.Table import *
@@ -29,10 +45,14 @@ from View.Geometry.Profile.Table import *
_translate = QCoreApplication.translate
-class ProfileWindow(QMainWindow, WindowToolKit):
- def __init__(self, profile=None, parent=None):
+class ProfileWindow(ASubMainWindow):
+ def __init__(self, profile=None, title="Profile", parent=None):
+ self._title = title
self.parent = parent
- super(ProfileWindow, self).__init__(self.parent)
+ super(ProfileWindow, self).__init__(
+ name=self._title,
+ parent=self.parent
+ )
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
@@ -66,12 +86,14 @@ class ProfileWindow(QMainWindow, WindowToolKit):
if (name is None) or (name == ""):
name = _translate("MainWindowProfile", "(no name)")
- self.setWindowTitle(
+ self._title = (
header + " - " +
f"{self._profile.reach.name}" + " - " +
f"{name} ({self._profile.kp})"
)
+ self.setWindowTitle(self._title)
+
def setup_sc(self):
self._undo_stack = QUndoStack()
diff --git a/src/View/Geometry/Profile/mainwindow_ui_profile.py b/src/View/Geometry/Profile/mainwindow_ui_profile.py
index 8de74df0..0b9443f8 100644
--- a/src/View/Geometry/Profile/mainwindow_ui_profile.py
+++ b/src/View/Geometry/Profile/mainwindow_ui_profile.py
@@ -1,3 +1,19 @@
+# mainwindow_ui_profile.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 .
+
# -*- coding: utf-8 -*-
import os.path
diff --git a/src/View/Geometry/Table.py b/src/View/Geometry/Table.py
index 8cc29dc8..1b055209 100644
--- a/src/View/Geometry/Table.py
+++ b/src/View/Geometry/Table.py
@@ -1,6 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
import time
+import logging
+import traceback
from tools import timer, trace
@@ -21,6 +39,7 @@ from Model.Geometry import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ
from View.Geometry.UndoCommand import *
+logger = logging.getLogger()
_translate = QCoreApplication.translate
@@ -98,23 +117,27 @@ class TableEditableModel(QAbstractTableModel):
column = index.column()
if role == Qt.EditRole and index.column() != 2:
- if index.column() == 0:
- self._undo_stack.push(
- SetNameCommand(
- self._reach, index.row(),
- self._reach.profile(index.row()).name,
- value
+ try:
+ if index.column() == 0:
+ self._undo_stack.push(
+ SetNameCommand(
+ self._reach, index.row(),
+ self._reach.profile(index.row()).name,
+ value
+ )
)
- )
- if index.column() == 1:
- self._undo_stack.push(
- SetKPCommand(
- self._reach, index.row(),
- self._reach.profile(index.row()).kp,
+ if index.column() == 1:
+ self._undo_stack.push(
+ SetKPCommand(
+ self._reach, index.row(),
+ self._reach.profile(index.row()).kp,
value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
self.layoutChanged.emit()
diff --git a/src/View/Geometry/UndoCommand.py b/src/View/Geometry/UndoCommand.py
index ed911c66..1df9c58c 100644
--- a/src/View/Geometry/UndoCommand.py
+++ b/src/View/Geometry/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -17,9 +33,13 @@ class SetDataCommand(QUndoCommand):
self._reach = reach
self._index = index
self._old = old_value
- self._new = new_value
+ self._new = self.type(new_value)
class SetNameCommand(SetDataCommand):
+ def __init__(self, reach, index, old_value, new_value):
+ self.type = str
+ super(SetNameCommand, self).__init__(reach, index, old_value, new_value)
+
def undo(self):
self._reach.profile(self._index).name = self._old
@@ -27,6 +47,10 @@ class SetNameCommand(SetDataCommand):
self._reach.profile(self._index).name = self._new
class SetKPCommand(SetDataCommand):
+ def __init__(self, reach, index, old_value, new_value):
+ self.type = float
+ super(SetKPCommand, self).__init__(reach, index, old_value, new_value)
+
def undo(self):
self._reach.profile(self._index).kp = self._old
diff --git a/src/View/Geometry/Window.py b/src/View/Geometry/Window.py
index 835db523..7776d737 100644
--- a/src/View/Geometry/Window.py
+++ b/src/View/Geometry/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import os
@@ -25,7 +41,8 @@ from View.Geometry.PlotXY import PlotXY
from View.Geometry.PlotKPZ import PlotKPZ
from View.Geometry.PlotAC import PlotAC
-from View.ASubWindow import WindowToolKit
+from View.ASubWindow import ASubMainWindow, WindowToolKit
+from View.ListedSubWindow import ListedSubWindow
from View.Geometry.mainwindow_ui_reach import Ui_MainWindow
from View.Geometry.Table import *
from View.Geometry.Profile.Window import ProfileWindow
@@ -33,10 +50,14 @@ from View.Geometry.Profile.Window import ProfileWindow
_translate = QCoreApplication.translate
-class GeometryWindow(QMainWindow, WindowToolKit):
- def __init__(self, model=None, parent=None):
+class GeometryWindow(ASubMainWindow, ListedSubWindow):
+ def __init__(self, model=None, title="Geometry", parent=None):
+ self._title = title
self.parent = parent
- super(GeometryWindow, self).__init__(parent=parent)
+ super(GeometryWindow, self).__init__(
+ name=self._title,
+ parent=parent
+ )
self._model = model
self._reach = model.river.current_reach().reach
@@ -59,7 +80,8 @@ class GeometryWindow(QMainWindow, WindowToolKit):
self.changed_slider_value()
def setup_window(self):
- self.setWindowTitle(f"{self.ui.mainwindow_title} - {self._reach.name}")
+ self._title = f"{self.ui.mainwindow_title} - {self._reach.name}"
+ self.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
@@ -162,13 +184,20 @@ class GeometryWindow(QMainWindow, WindowToolKit):
for row in rows:
profile = self._reach.profile(row)
- win = ProfileWindow(
- profile = profile,
- parent = self,
+ win = self.sub_win_filter_first(
+ "Profile",
+ contain = [self._reach.name, str(profile.kp)]
)
- self._profile_window.append(win)
- win.show()
+ if win is None:
+ win = ProfileWindow(
+ profile = profile,
+ parent = self,
+ )
+ self._profile_window.append(win)
+ win.show()
+ else:
+ win.activateWindow()
self.tableView.model().blockSignals(False)
diff --git a/src/View/Geometry/mainwindow_ui_reach.py b/src/View/Geometry/mainwindow_ui_reach.py
index f04ee9e8..747b6ca4 100644
--- a/src/View/Geometry/mainwindow_ui_reach.py
+++ b/src/View/Geometry/mainwindow_ui_reach.py
@@ -1,3 +1,19 @@
+# mainwindow_ui_reach.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 .
+
# -*- coding: utf-8 -*-
import sys
diff --git a/src/View/InitialConditions/DialogDischarge.py b/src/View/InitialConditions/DialogDischarge.py
index 8d01ef0e..f8e7e32a 100644
--- a/src/View/InitialConditions/DialogDischarge.py
+++ b/src/View/InitialConditions/DialogDischarge.py
@@ -1,3 +1,19 @@
+# DialogDischarge.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 .
+
# -*- coding: utf-8 -*-
from View.ASubWindow import ASubWindow
diff --git a/src/View/InitialConditions/DialogHeight.py b/src/View/InitialConditions/DialogHeight.py
index 91ceadb1..18ad67c8 100644
--- a/src/View/InitialConditions/DialogHeight.py
+++ b/src/View/InitialConditions/DialogHeight.py
@@ -1,3 +1,19 @@
+# DialogHeight.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 .
+
# -*- coding: utf-8 -*-
from View.ASubWindow import ASubWindow
diff --git a/src/View/InitialConditions/PlotDKP.py b/src/View/InitialConditions/PlotDKP.py
index 247605b3..58a83219 100644
--- a/src/View/InitialConditions/PlotDKP.py
+++ b/src/View/InitialConditions/PlotDKP.py
@@ -1,3 +1,19 @@
+# PlotDKP.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 .
+
# -*- coding: utf-8 -*-
from tools import timer
@@ -26,7 +42,7 @@ class PlotDKP(APlot):
return
self.canvas.axes.set_ylabel(
- _translate("MainWindow_reach", "Draft (m)"),
+ _translate("MainWindow_reach", "Elevation (m)"),
color='green', fontsize=11
)
self.canvas.axes.set_xlabel(
diff --git a/src/View/InitialConditions/PlotDischarge.py b/src/View/InitialConditions/PlotDischarge.py
index 07664683..1fe05def 100644
--- a/src/View/InitialConditions/PlotDischarge.py
+++ b/src/View/InitialConditions/PlotDischarge.py
@@ -1,3 +1,19 @@
+# PlotDischarge.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 .
+
# -*- coding: utf-8 -*-
from tools import timer
diff --git a/src/View/InitialConditions/Table.py b/src/View/InitialConditions/Table.py
index 13eb5218..5e704ba9 100644
--- a/src/View/InitialConditions/Table.py
+++ b/src/View/InitialConditions/Table.py
@@ -1,5 +1,23 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
+import logging
+import traceback
from tools import trace, timer
from PyQt5.QtCore import (
@@ -23,6 +41,8 @@ from View.InitialConditions.UndoCommand import (
from View.InitialConditions.translate import *
+logger = logging.getLogger()
+
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -119,12 +139,16 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- if self._headers[column] is not None:
- self._undo.push(
- SetCommand(
- self._ics, row, self._headers[column], value
+ try:
+ if self._headers[column] is not None:
+ self._undo.push(
+ SetCommand(
+ self._ics, row, self._headers[column], value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/InitialConditions/UndoCommand.py b/src/View/InitialConditions/UndoCommand.py
index 215c299b..c96f90fa 100644
--- a/src/View/InitialConditions/UndoCommand.py
+++ b/src/View/InitialConditions/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -18,7 +34,12 @@ class SetCommand(QUndoCommand):
self._row = row
self._column = column
self._old = self._ics.get(self._row)[column]
- self._new = new_value
+
+ _type = float
+ if column == "name" or column == "comment":
+ _type = str
+
+ self._new = _type(new_value)
def undo(self):
self._ics.get(self._row)[self._column] = self._old
diff --git a/src/View/InitialConditions/Window.py b/src/View/InitialConditions/Window.py
index 35822811..95f6004a 100644
--- a/src/View/InitialConditions/Window.py
+++ b/src/View/InitialConditions/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
diff --git a/src/View/InitialConditions/translate.py b/src/View/InitialConditions/translate.py
index 43890acb..370d4a22 100644
--- a/src/View/InitialConditions/translate.py
+++ b/src/View/InitialConditions/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/LateralContribution/Edit/Plot.py b/src/View/LateralContribution/Edit/Plot.py
index d7c95ec0..5843ee56 100644
--- a/src/View/LateralContribution/Edit/Plot.py
+++ b/src/View/LateralContribution/Edit/Plot.py
@@ -1,3 +1,19 @@
+# Plot.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 .
+
# -*- coding: utf-8 -*-
from datetime import datetime
@@ -25,6 +41,9 @@ class Plot(APlot):
self._mode = mode
def custom_ticks(self):
+ if self.data.header[0] != "time":
+ return
+
t0 = datetime.fromtimestamp(0)
nb = len(self.data.data)
mod = int(nb / 5)
diff --git a/src/View/LateralContribution/Edit/Table.py b/src/View/LateralContribution/Edit/Table.py
index 4101995c..e9e878fd 100644
--- a/src/View/LateralContribution/Edit/Table.py
+++ b/src/View/LateralContribution/Edit/Table.py
@@ -1,6 +1,23 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
import logging
+import traceback
from datetime import date, time, datetime, timedelta
from tools import trace, timer
@@ -194,11 +211,15 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- self._undo.push(
- SetDataCommand(
- self._data, row, column, value
+ try:
+ self._undo.push(
+ SetDataCommand(
+ self._data, row, column, value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/LateralContribution/Edit/UndoCommand.py b/src/View/LateralContribution/Edit/UndoCommand.py
index b5963b76..715683c9 100644
--- a/src/View/LateralContribution/Edit/UndoCommand.py
+++ b/src/View/LateralContribution/Edit/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -17,7 +33,8 @@ class SetDataCommand(QUndoCommand):
self._index = index
self._column = column
self._old = self._data.get_i(self._index)[self._column]
- self._new = new_value
+ _type = self._data.get_type_column(self._column)
+ self._new = _type(new_value)
def undo(self):
self._data._set_i_c_v(self._index, self._column, self._old)
diff --git a/src/View/LateralContribution/Edit/Window.py b/src/View/LateralContribution/Edit/Window.py
index e9927710..3a801591 100644
--- a/src/View/LateralContribution/Edit/Window.py
+++ b/src/View/LateralContribution/Edit/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from tools import timer, trace
@@ -29,7 +45,7 @@ from View.LateralContribution.Edit.Plot import Plot
_translate = QCoreApplication.translate
class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
- def __init__(self, title="Edit lateral conditribution",
+ def __init__(self, title="Edit lateral contribution",
data=None, study=None, parent=None):
self._data = data
self._study = study
@@ -38,7 +54,7 @@ class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
self.compute_title()
super(EditLateralContributionWindow, self).__init__(
- name=self._title, ui="EditLateralContribution", parent=parent
+ name=title, ui="EditLateralContribution", parent=parent
)
self.ui.setWindowTitle(self._title)
@@ -53,9 +69,9 @@ class EditLateralContributionWindow(ASubMainWindow, ListedSubWindow):
edge_name = (self._data.edge.name if self._data.edge is not None
else _translate("LateralContribution", "Not associate"))
self._title = (
- _translate("Edit Lateral contribution", self._title) +
+ _translate("Edit lateral contribution", self._title) +
f" - {self._study.name} " +
- f" - {self._data.name} " +
+ f" - {self._data.name} ({self._data.id}) " +
f"({long_types[self._data.lctype]} - {edge_name})"
)
diff --git a/src/View/LateralContribution/Edit/translate.py b/src/View/LateralContribution/Edit/translate.py
index e44147e2..243d9ad8 100644
--- a/src/View/LateralContribution/Edit/translate.py
+++ b/src/View/LateralContribution/Edit/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/LateralContribution/Table.py b/src/View/LateralContribution/Table.py
index 307fc56e..682bf00d 100644
--- a/src/View/LateralContribution/Table.py
+++ b/src/View/LateralContribution/Table.py
@@ -1,5 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
+import logging
+import traceback
+
from tools import trace, timer
from PyQt5.QtCore import (
@@ -27,6 +46,8 @@ from Model.LateralContribution.LateralContributionTypes import (
)
from View.LateralContribution.translate import *
+logger = logging.getLogger()
+
_translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
@@ -140,37 +161,41 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- if self._headers[column] == "name":
- self._undo.push(
- SetNameCommand(
- self._lcs, self._tab, row, value
+ try:
+ if self._headers[column] == "name":
+ self._undo.push(
+ SetNameCommand(
+ self._lcs, self._tab, row, value
+ )
)
- )
- elif self._headers[column] == "type":
- key = next(k for k, v in long_types.items() if v == value)
- self._undo.push(
- SetTypeCommand(
- self._lcs, self._tab, row, LC_types[key]
+ elif self._headers[column] == "type":
+ key = next(k for k, v in long_types.items() if v == value)
+ self._undo.push(
+ SetTypeCommand(
+ self._lcs, self._tab, row, LC_types[key]
+ )
)
- )
- elif self._headers[column] == "edge":
- self._undo.push(
- SetEdgeCommand(
- self._lcs, self._tab, row, self._data.edge(value)
+ elif self._headers[column] == "edge":
+ self._undo.push(
+ SetEdgeCommand(
+ self._lcs, self._tab, row, self._data.edge(value)
+ )
)
- )
- elif self._headers[column] == "begin_kp":
- self._undo.push(
- SetBeginCommand(
- self._lcs, self._tab, row, value
+ elif self._headers[column] == "begin_kp":
+ self._undo.push(
+ SetBeginCommand(
+ self._lcs, self._tab, row, value
+ )
)
- )
- elif self._headers[column] == "end_kp":
- self._undo.push(
- SetEndCommand(
- self._lcs, self._tab, row, value
+ elif self._headers[column] == "end_kp":
+ self._undo.push(
+ SetEndCommand(
+ self._lcs, self._tab, row, value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/LateralContribution/UndoCommand.py b/src/View/LateralContribution/UndoCommand.py
index f7e680b3..3d858436 100644
--- a/src/View/LateralContribution/UndoCommand.py
+++ b/src/View/LateralContribution/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -18,7 +34,7 @@ class SetNameCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._lcs.get(self._tab, self._index).name
- self._new = new_value
+ self._new = str(new_value)
def undo(self):
self._lcs.get(self._tab, self._index).name = self._old
@@ -34,7 +50,7 @@ class SetBeginCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._lcs.get(self._tab, self._index).begin_kp
- self._new = new_value
+ self._new = float(new_value)
def undo(self):
self._lcs.get(self._tab, self._index).begin_kp = float(self._old)
@@ -50,7 +66,7 @@ class SetEndCommand(QUndoCommand):
self._tab = tab
self._index = index
self._old = self._lcs.get(self._tab, self._index).end_kp
- self._new = new_value
+ self._new = float(new_value)
def undo(self):
self._lcs.get(self._tab, self._index).end_kp = float(self._old)
diff --git a/src/View/LateralContribution/Window.py b/src/View/LateralContribution/Window.py
index b87e9968..dc3dd94f 100644
--- a/src/View/LateralContribution/Window.py
+++ b/src/View/LateralContribution/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
@@ -49,7 +65,7 @@ logger = logging.getLogger()
class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Lateral contribution", study=None, parent=None):
- title = title + " - " + study.name
+ self._title = title + " - " + study.name
super(LateralContributionWindow, self).__init__(
name=title, ui="LateralContributions", parent=parent
@@ -63,7 +79,7 @@ class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
self.setup_graph()
self.setup_connections()
- self.ui.setWindowTitle(title)
+ self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
@@ -250,9 +266,17 @@ class LateralContributionWindow(ASubMainWindow, ListedSubWindow):
tab = self.current_tab()
rows = self.index_selected_rows()
for row in rows:
- win = EditLateralContributionWindow(
- data=self._lcs.get(tab, row),
- study=self._study,
- parent=self
+ win = self.sub_win_filter_first(
+ "Edit lateral contribution",
+ contain = [f"({self._lcs.get(tab, row).id})"]
)
- win.show()
+
+ if win is None:
+ win = EditLateralContributionWindow(
+ data=self._lcs.get(tab, row),
+ study=self._study,
+ parent=self
+ )
+ win.show()
+ else:
+ win.activateWindow()
diff --git a/src/View/LateralContribution/translate.py b/src/View/LateralContribution/translate.py
index c2b9e789..e9c6deeb 100644
--- a/src/View/LateralContribution/translate.py
+++ b/src/View/LateralContribution/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/ListedSubWindow.py b/src/View/ListedSubWindow.py
index c88fd7b4..b4dfe416 100644
--- a/src/View/ListedSubWindow.py
+++ b/src/View/ListedSubWindow.py
@@ -1,3 +1,19 @@
+# ListedSubWindow.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 .
+
# -*- coding: utf-8 -*-
import logging
@@ -32,9 +48,50 @@ class ListedSubWindow(object):
self.sub_win_cnt = len(self.sub_win_list)
logger.info(f"Close window: {name} ({self.sub_win_cnt})")
- def sub_win_exists(self, name):
+ def _sub_win_exists(self, name):
return reduce(
lambda acc, n: (acc or (n[0] == name)),
self.sub_win_list,
False
)
+
+ def _sub_win_exists_with_contain(self, name, contain):
+ return reduce(
+ lambda acc, n: (
+ acc or
+ (
+ (n[0] == name) and
+ reduce(
+ lambda acc, c: acc and (c in n[1]._title),
+ contain,
+ True
+ )
+ )
+ ),
+ self.sub_win_list,
+ False
+ )
+
+ def sub_win_exists(self, name, contain = []):
+ if contain == []:
+ return self._sub_win_exists(name)
+ else:
+ return self._sub_win_exists_with_contain(name, contain)
+
+ def sub_win_filter_first(self, name, contain):
+ try:
+ return next(
+ filter(
+ lambda n: (
+ (name in n[0]) and
+ reduce(
+ lambda acc, c: acc and (c in n[1]._title),
+ contain,
+ True
+ )
+ ),
+ self.sub_win_list,
+ )
+ )[1]
+ except:
+ return None
diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py
index 71301e1b..2fc14efa 100644
--- a/src/View/MainWindow.py
+++ b/src/View/MainWindow.py
@@ -1,3 +1,19 @@
+# MainWindow.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 .
+
# -*- coding: utf-8 -*-
import os
@@ -39,6 +55,7 @@ from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow
from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
from View.CheckList.Window import CheckListWindow
+from View.Results.Window import ResultsWindow
from View.Debug.Window import ReplWindow
from Model.Study import Study
@@ -93,6 +110,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
# Model
self.model = None
+ # Results
+ self._last_results = None
+
# UI
self.ui = loadUi(
os.path.join(os.path.dirname(__file__), "ui", "MainWindow.ui"),
@@ -107,6 +127,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
self.trans = QTranslator(self)
#self.ui.retranslateUi()
+ if self.conf.last_study != "" and not self.conf.close_correctly:
+ self.dialog_reopen_study()
+
def set_title(self):
if self.model is not None:
self.setWindowTitle(f"PAMHYR - {self.model.name}")
@@ -192,16 +215,24 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
if self.model is not None and not self.model.is_saved:
self._close_question = True
if self.dialog_close():
+ # PAMHYR is close correctly (no crash)
+ self.conf.set_close_correctly()
+
super(ApplicationWindow, self).close()
else:
self._close_question = False
else:
+ # PAMHYR is close correctly (no crash)
+ self.conf.set_close_correctly()
+
super(ApplicationWindow, self).close()
def closeEvent(self, event):
if not self._close_question:
if self.model is not None and not self.model.is_saved:
if self.dialog_close(cancel = False):
+ # PAMHYR is close correctly (no crash)
+ self.conf.set_close_correctly()
super(ApplicationWindow, self).closeEvent(event)
else:
super(ApplicationWindow, self).closeEvent(event)
@@ -261,11 +292,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
def set_model(self, model):
self.model = model
self.update_enable_action()
+ self.conf.set_last_study(self.model.filename)
self.set_title()
def close_model(self):
self.model = None
self.update_enable_action()
+ self.conf.set_close_correctly()
self.set_title()
def update_enable_action(self):
@@ -288,10 +321,26 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
for action in model_action:
self.enable_actions(action, not no_model)
+ def set_results(self, results):
+ self._last_results = results
+
############
# FEATURES #
############
+ def open_study(self, filename):
+ """Open a study
+
+ Args:
+ filename: The study path
+
+ Returns:
+ Nothing
+ """
+ self.set_model(Study.open(filename))
+ logger.info(f"Open Study - {self.model.name}")
+ self.set_title()
+
def save_study(self):
"""Save current study
@@ -348,6 +397,27 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"Geometry edition need a reach selected "
"into river network window to work on it")
+ def dialog_reopen_study(self):
+ dlg = QMessageBox(self)
+
+ dlg.setWindowTitle("Last open study")
+ dlg.setText("Do you want to open again the last open study?")
+ opt = QMessageBox.Cancel | QMessageBox.Ok #| QMessageBox.Open
+
+ dlg.setStandardButtons(opt)
+ dlg.setIcon(QMessageBox.Question)
+
+ res = dlg.exec()
+
+ if res == QMessageBox.Ok:
+ self.open_study(self.conf.last_study)
+ return True
+ elif res == QMessageBox.Open:
+ self.open_model()
+ return True
+ elif res == QMessageBox.Cancel:
+ return False
+
def dialog_close(self, cancel = True):
dlg = QMessageBox(self)
@@ -408,12 +478,11 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
dialog.setDefaultSuffix(".pamhyr")
#dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden)
dialog.setNameFilters(['PamHyr (*.pamhyr)'])
+ dialog.setDirectory(os.path.dirname(self.conf.last_study))
if dialog.exec_():
file_name = dialog.selectedFiles()
- self.set_model(Study.open(file_name[0]))
- logger.info(f"Open Study - {self.model.name}")
- self.set_title()
+ self.open_study(file_name[0])
def open_new_study(self):
"""Open dialog to set new study
@@ -441,10 +510,12 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
Returns:
Nothing
"""
- if (self.model is not None and
- not self.sub_win_exists("River network")):
- self.network = NetworkWindow(model=self.model, parent=self)
- self.network.show()
+ if self.model is not None:
+ if not self.sub_win_exists("River network"):
+ self.network = NetworkWindow(model=self.model, parent=self)
+ self.network.show()
+ else:
+ self.network.activateWindow()
def open_geometry(self):
"""Open geometry window
@@ -452,56 +523,112 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
Returns:
Nothing
"""
- if (self.model is not None and
- self.model.river.has_current_reach()):
- geometry = GeometryWindow(model=self.model, parent=self)
- geometry.show()
+ if (self.model is not None and self.model.river.has_current_reach()):
+ geometry = self.sub_win_filter_first(
+ "Geometry",
+ contain = [self.model.river.current_reach().name]
+ )
+
+ if geometry is None:
+ geometry = GeometryWindow(model=self.model, parent=self)
+ geometry.show()
+ else:
+ geometry.activateWindow()
else:
self.msg_select_reach()
def open_boundary_cond(self):
- bound = BoundaryConditionWindow(study = self.model, parent = self)
- bound.show()
+ bound = self.sub_win_filter_first(
+ "Boundary conditions",
+ contain = []
+ )
+
+ if bound is None:
+ bound = BoundaryConditionWindow(study = self.model, parent = self)
+ bound.show()
+ else:
+ bound.activateWindow()
def open_lateral_contrib(self):
- lateral = LateralContributionWindow(study = self.model, parent = self)
- lateral.show()
+ lateral = self.sub_win_filter_first(
+ "Lateral contribution",
+ contain = []
+ )
+
+ if lateral is None:
+ lateral = LateralContributionWindow(study = self.model, parent = self)
+ lateral.show()
+ else:
+ lateral.activateWindow()
def open_stricklers(self):
- strick = StricklersWindow(
- study = self.model,
- config = self.conf,
- parent = self
+ strick = self.sub_win_filter_first(
+ "Stricklers",
+ contain = []
)
- strick.show()
+
+ if strick is None:
+ strick = StricklersWindow(
+ study = self.model,
+ config = self.conf,
+ parent = self
+ )
+ strick.show()
+ else:
+ strick.activateWindow()
def open_frictions(self):
if (self.model is not None and
self.model.river.has_current_reach()):
- frictions = FrictionsWindow(
- study = self.model,
- parent = self
+
+ frictions = self.sub_win_filter_first(
+ "Frictions",
+ contain = [self.model.river.current_reach().name]
)
- frictions.show()
+
+ if frictions is None:
+ frictions = FrictionsWindow(
+ study = self.model,
+ parent = self
+ )
+ frictions.show()
+ else:
+ frictions.activateWindow()
else:
self.msg_select_reach()
def open_initial_conditions(self):
if self.model.river.has_current_reach():
- initial = InitialConditionsWindow(
- study = self.model,
- parent = self
+ initial = self.sub_win_filter_first(
+ "Initial condition",
+ contain = [self.model.river.current_reach().name]
)
- initial.show()
+
+ if initial is None:
+ initial = InitialConditionsWindow(
+ study = self.model,
+ parent = self
+ )
+ initial.show()
+ else:
+ initial.activateWindow()
else:
self.msg_select_reach()
def open_solver_parameters(self):
- params = SolverParametersWindow(
- study = self.model,
- parent = self
+ params = self.sub_win_filter_first(
+ "Solver parameters",
+ contain = []
)
- params.show()
+
+ if params is None:
+ params = SolverParametersWindow(
+ study = self.model,
+ parent = self
+ )
+ params.show()
+ else:
+ params.activateWindow()
def open_sediment_layers(self):
sl = SedimentLayersWindow(
@@ -545,6 +672,32 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
)
sol.show()
+ def open_solver_results(self, solver, results = None):
+ # If no specific results, get last results
+ if results is None:
+ results = self._last_results
+
+ # No results available
+ if results is None:
+ return
+
+ # Windows already opened
+ res = self.sub_win_filter_first(
+ "Results",
+ contain = [solver.name, results.date]
+ )
+
+ if res is None:
+ res = ResultsWindow(
+ study = self.model,
+ solver = solver,
+ results = results,
+ parent = self
+ )
+ res.show()
+ else:
+ res.activateWindow()
+
#########
# DEBUG #
#########
diff --git a/src/View/Network/GraphWidget.py b/src/View/Network/GraphWidget.py
index 2569497a..870792b8 100644
--- a/src/View/Network/GraphWidget.py
+++ b/src/View/Network/GraphWidget.py
@@ -1,6 +1,23 @@
+# GraphWidget.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 .
+
# -*- coding: utf-8 -*-
import math
+import logging
from tools import timer
@@ -23,6 +40,8 @@ from Model.Network.Graph import Graph
from View.Network.UndoCommand import *
+logger = logging.getLogger()
+
_translate = QCoreApplication.translate
@@ -158,7 +177,7 @@ class EdgeItem(QGraphicsItem):
if self.graph.selected_item() == self:
color = Qt.red
elif self.graph.current_edge() == self:
- color = Qt.blue
+ color = Qt.black
elif not self.graph.graph.is_enable_edge(self.edge):
color = Qt.darkGray
@@ -555,14 +574,17 @@ class GraphWidget(QGraphicsView):
Returns:
Nothing
"""
- previous_item = self._selected_item
- self._selected_item = item
+ try:
+ previous_item = self._selected_item
+ self._selected_item = item
- if previous_item:
- previous_item.update()
+ if previous_item:
+ previous_item.update()
- if item:
- item.update()
+ if item:
+ item.update()
+ except Exception as e:
+ logger.debug(str(e))
def selected_new_edge_src_node(self):
"""The current node item selected to add new edge
@@ -714,6 +736,9 @@ class GraphWidget(QGraphicsView):
def mouseReleaseEvent(self, event):
self.clicked = False
+ if self._only_display:
+ return
+
if self._state == "move":
if self._current_moved_node is not None:
pos = self.mapToScene(event.pos())
@@ -819,6 +844,9 @@ class GraphWidget(QGraphicsView):
self.reverse_edge(items[0])
def contextMenuEvent(self, event):
+ if self._only_display:
+ return
+
pos = self.mapToScene(event.pos())
items = self.items(event.pos())
diff --git a/src/View/Network/Table.py b/src/View/Network/Table.py
index a8254745..b24865e8 100644
--- a/src/View/Network/Table.py
+++ b/src/View/Network/Table.py
@@ -1,5 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
+import logging
+import traceback
+
from Model.Network.Node import Node
from Model.Network.Edge import Edge
from Model.Network.Graph import Graph
@@ -137,31 +156,35 @@ class GraphTableModel(QAbstractTableModel):
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
- if (self.headers[index.column()] == "node1" or
- self.headers[index.column()] == "node2"):
- node = self.graph.node(value)
- self._undo.push(
- SetNodeCommand(
- self.graph,
- self.rows[index.row()],
- self.headers[index.column()],
- node
+ try:
+ if (self.headers[index.column()] == "node1" or
+ self.headers[index.column()] == "node2"):
+ node = self.graph.node(value)
+ self._undo.push(
+ SetNodeCommand(
+ self.graph,
+ self.rows[index.row()],
+ self.headers[index.column()],
+ node
+ )
)
- )
- elif self.headers[index.column()] == "enable":
- self._undo.push(
- EnableEdgeCommand(
- self.rows[index.row()], value
+ # elif self.headers[index.column()] == "enable":
+ # self._undo.push(
+ # EnableEdgeCommand(
+ # self.rows[index.row()], value
+ # )
+ # )
+ else:
+ self._undo.push(
+ SetCommand(
+ self.rows[index.row()],
+ self.headers[index.column()],
+ value
+ )
)
- )
- else:
- self._undo.push(
- SetCommand(
- self.rows[index.row()],
- self.headers[index.column()],
- value
- )
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index, [Qt.DisplayRole])
self.layoutChanged.emit()
diff --git a/src/View/Network/UndoCommand.py b/src/View/Network/UndoCommand.py
index d6d38125..c9cce895 100644
--- a/src/View/Network/UndoCommand.py
+++ b/src/View/Network/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
diff --git a/src/View/Network/Window.py b/src/View/Network/Window.py
index 8fdf3988..05051862 100644
--- a/src/View/Network/Window.py
+++ b/src/View/Network/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtGui import (
@@ -34,7 +50,7 @@ class NetworkWindow(ASubMainWindow):
self.setup_title()
super(NetworkWindow, self).__init__(
- name=self._title, ui="Network", parent=parent
+ name=title, ui="Network", parent=parent
)
self.ui.setWindowTitle(self._title)
@@ -71,7 +87,8 @@ class NetworkWindow(ASubMainWindow):
# Edges table
self._reachs_model = GraphTableModel(
- headers = ["name", "enable", "node1", "node2"],
+ headers = ["name", # "enable",
+ "node1", "node2"],
graph = self._graph,
rows_type = "edges",
undo = self._undo_stack,
@@ -86,9 +103,9 @@ class NetworkWindow(ASubMainWindow):
table = self.find(QTableView, "tableView_reachs")
table.setModel(self._reachs_model)
- table.setItemDelegateForColumn(1, self.delegate_true_false_combobox)
+ # table.setItemDelegateForColumn(1, self.delegate_true_false_combobox)
+ table.setItemDelegateForColumn(1, self.delegate_combobox)
table.setItemDelegateForColumn(2, self.delegate_combobox)
- table.setItemDelegateForColumn(3, self.delegate_combobox)
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
#table.resizeColumnsToContents()
diff --git a/src/View/Plot/APlot.py b/src/View/Plot/APlot.py
index cca27087..cd9988cf 100644
--- a/src/View/Plot/APlot.py
+++ b/src/View/Plot/APlot.py
@@ -1,3 +1,19 @@
+# APlot.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 .
+
# -*- coding: utf-8 -*-
class APlot(object):
diff --git a/src/View/Plot/MplCanvas.py b/src/View/Plot/MplCanvas.py
index 5b3fc4a8..ee1f5373 100644
--- a/src/View/Plot/MplCanvas.py
+++ b/src/View/Plot/MplCanvas.py
@@ -1,3 +1,19 @@
+# MplCanvas.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 .
+
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
diff --git a/src/View/Plot/mpl_canvas_onpick_event.py b/src/View/Plot/mpl_canvas_onpick_event.py
index 010959bc..fdfa1de6 100644
--- a/src/View/Plot/mpl_canvas_onpick_event.py
+++ b/src/View/Plot/mpl_canvas_onpick_event.py
@@ -1,3 +1,19 @@
+# mpl_canvas_onpick_event.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 .
+
import logging
from time import time
diff --git a/src/View/Plot/navigation_toolbar_2qt.py b/src/View/Plot/navigation_toolbar_2qt.py
index 37186450..1cca7cf0 100644
--- a/src/View/Plot/navigation_toolbar_2qt.py
+++ b/src/View/Plot/navigation_toolbar_2qt.py
@@ -1,3 +1,19 @@
+# navigation_toolbar_2qt.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 .
+
# -*- coding: utf-8 -*-
import os
diff --git a/src/View/Results/PlotAC.py b/src/View/Results/PlotAC.py
new file mode 100644
index 00000000..f0e4b0e2
--- /dev/null
+++ b/src/View/Results/PlotAC.py
@@ -0,0 +1,115 @@
+# PlotAC.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 .
+
+# -*- coding: utf-8 -*-
+
+from tools import timer
+from View.Plot.APlot import APlot
+
+from PyQt5.QtCore import (
+ QCoreApplication
+)
+
+_translate = QCoreApplication.translate
+
+class PlotAC(APlot):
+ def __init__(self, canvas=None, results=None,
+ reach_id=0, profile_id=0,
+ toolbar=None):
+ super(PlotAC, self).__init__(
+ canvas=canvas,
+ data=results,
+ toolbar=toolbar
+ )
+
+ self._current_timestamp = max(results.get("timestamps"))
+ self._current_reach_id = reach_id
+ self._current_profile_id = profile_id
+
+ @property
+ def results(self):
+ return self.data
+
+ @timer
+ def draw(self, highlight=None):
+ self.canvas.axes.cla()
+ self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
+
+ if self.results is None:
+ return
+
+ self.canvas.axes.set_xlabel(
+ _translate("MainWindow_reach", "X (m)"),
+ color='green', fontsize=11
+ )
+ self.canvas.axes.set_ylabel(
+ _translate("MainWindow_reach", "Elevation (m)"),
+ color='green', fontsize=11
+ )
+
+ reach = self.results.river.reach(self._current_reach_id)
+ profile = reach.profile(self._current_profile_id)
+ x = profile.geometry.get_station()
+ z = profile.geometry.z()
+
+ self.canvas.axes.set_xlim(
+ left = min(x), right = max(x)
+ )
+
+ self.line_kp, = self.canvas.axes.plot(
+ x, z,
+ linestyle="solid",
+ lw=1.8,
+ color='grey',
+ )
+
+ kp = reach.geometry.get_kp()
+
+ # Water elevation
+ water_z = profile.get_ts_key(self._current_timestamp, "Z")
+
+ self.canvas.axes.plot(
+ [min(x), max(x)], [water_z, water_z],
+ lw=1., color='b',
+ )
+
+ x_z = list(map(lambda _: water_z, x))
+ self.canvas.axes.fill_between(
+ x, z, water_z,
+ where=z <= water_z,
+ color='blue', alpha=0.5, interpolate=True
+ )
+
+ self.canvas.figure.tight_layout()
+ self.canvas.figure.canvas.draw_idle()
+ if self.toolbar is not None:
+ self.toolbar.update()
+
+ def set_reach(self, reach_id):
+ self._current_reach_id = reach_id
+ self._current_profile_id = 0
+ self.draw()
+
+ def set_profile(self, profile_id):
+ self._current_profile_id = profile_id
+ self.draw()
+
+ def set_timestamp(self, timestamp):
+ self._current_timestamp = timestamp
+ self.draw()
+
+ def update(self):
+ self.draw()
diff --git a/src/View/Results/PlotH.py b/src/View/Results/PlotH.py
new file mode 100644
index 00000000..dcc9f7f6
--- /dev/null
+++ b/src/View/Results/PlotH.py
@@ -0,0 +1,131 @@
+# PlotH.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 .
+
+# -*- coding: utf-8 -*-
+
+import logging
+
+from functools import reduce
+
+from tools import timer, trace
+from View.Plot.APlot import APlot
+
+from PyQt5.QtCore import (
+ QCoreApplication
+)
+
+_translate = QCoreApplication.translate
+
+logger = logging.getLogger()
+
+class PlotH(APlot):
+ def __init__(self, canvas=None, results=None,
+ reach_id=0, profile_id=0,
+ toolbar=None, display_current=True):
+ super(PlotH, self).__init__(
+ canvas=canvas,
+ data=results,
+ toolbar=toolbar
+ )
+
+ self.display_current = display_current
+
+ self._current_timestamp = max(results.get("timestamps"))
+ self._current_reach_id = reach_id
+ self._current_profile_id = profile_id
+
+ @property
+ def results(self):
+ return self.data
+
+ @timer
+ def draw(self, highlight=None):
+ self.canvas.axes.cla()
+ self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
+
+ if self.results is None:
+ return
+
+ reach = self.results.river.reach(self._current_reach_id)
+ profile = reach.profile(self._current_profile_id)
+
+ if reach.geometry.number_profiles == 0:
+ self._init = False
+ return
+
+ kp_min, kp_max = (-1, -1)
+ if highlight is not None:
+ kp_min, kp_max = highlight
+
+ # Axes
+ self.canvas.axes.set_xlabel(
+ _translate("Results", "Time (s)"),
+ color='green', fontsize=12
+ )
+ self.canvas.axes.set_ylabel(
+ _translate("Results", "Discharge (m³/s)"),
+ color='green', fontsize=12
+ )
+
+ ts = list(self.results.get("timestamps"))
+ ts.sort()
+
+ self.canvas.axes.set_xlim(
+ left = min(ts), right = max(ts)
+ )
+
+ # Draw discharge for each timestamp
+ x = ts
+ y = profile.get_key("Q")
+
+ if len(ts) != len(x):
+ logger.warning(
+ "Results as less Q data ({len(x)}) " +
+ "than timestamps ({len(ts)}) " +
+ "for profile {self._current_profile_id}"
+ )
+ return
+
+ self._line = [
+ self.canvas.axes.plot(
+ x, y, lw=1.,
+ color='r',
+ markersize=3, marker='+'
+ )
+ ]
+
+ self.canvas.axes.autoscale_view(True, True, True)
+ self.canvas.axes.autoscale()
+ self.canvas.figure.tight_layout()
+ self.canvas.figure.canvas.draw_idle()
+ if self.toolbar is not None:
+ self.toolbar.update()
+
+ def set_reach(self, reach_id):
+ self._current_reach_id = reach_id
+ self._current_profile_id = 0
+ self.draw()
+
+ def set_profile(self, profile_id):
+ self._current_profile_id = profile_id
+ self.draw()
+
+ def set_timestamp(self, timestamp):
+ self._current_timestamp = timestamp
+ self.draw()
+
+ def update(self):
+ self.draw()
diff --git a/src/View/Results/PlotKPC.py b/src/View/Results/PlotKPC.py
new file mode 100644
index 00000000..68f6fb4e
--- /dev/null
+++ b/src/View/Results/PlotKPC.py
@@ -0,0 +1,117 @@
+# PlotKPC.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 .
+
+# -*- coding: utf-8 -*-
+
+from tools import timer
+from View.Plot.APlot import APlot
+
+from PyQt5.QtCore import (
+ QCoreApplication
+)
+
+_translate = QCoreApplication.translate
+
+class PlotKPC(APlot):
+ def __init__(self, canvas=None, results=None,
+ reach_id=0, profile_id=0,
+ toolbar=None):
+ super(PlotKPC, self).__init__(
+ canvas=canvas,
+ data=results,
+ toolbar=toolbar
+ )
+
+ self._current_timestamp = max(results.get("timestamps"))
+ self._current_reach_id = reach_id
+ self._current_profile_id = profile_id
+
+ @property
+ def results(self):
+ return self.data
+
+ @timer
+ def draw(self, highlight=None):
+ self.canvas.axes.cla()
+ self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
+
+ if self.results is None:
+ return
+
+ reach = self.results.river.reach(self._current_reach_id)
+
+ self.canvas.axes.set_ylabel(
+ _translate("MainWindow_reach", "Elevation (m)"),
+ color='green', fontsize=11
+ )
+ self.canvas.axes.set_xlabel(
+ _translate("MainWindow_reach", "KP (m)"),
+ color='green', fontsize=11
+ )
+
+ kp = reach.geometry.get_kp()
+ z_min = reach.geometry.get_z_min()
+
+ self.canvas.axes.set_xlim(
+ left = min(kp), right = max(kp)
+ )
+
+ self.line_kp_zmin = self.canvas.axes.plot(
+ kp, z_min,
+ color='grey', lw=1.
+ )
+
+ if len(reach.geometry.profiles) != 0:
+ kp = reach.geometry.get_kp()
+
+ # Water elevation
+ water_z = list(
+ map(
+ lambda p: p.get_ts_key(self._current_timestamp, "Z"),
+ reach.profiles
+ )
+ )
+
+ self.canvas.axes.plot(
+ kp, water_z, lw=1.,
+ color='b',
+ )
+
+ self.canvas.axes.fill_between(
+ kp, z_min, water_z,
+ color='blue', alpha=0.5, interpolate=True
+ )
+
+ self.canvas.figure.tight_layout()
+ self.canvas.figure.canvas.draw_idle()
+ if self.toolbar is not None:
+ self.toolbar.update()
+
+ def set_reach(self, reach_id):
+ self._current_reach_id = reach_id
+ self._current_profile_id = 0
+ self.draw()
+
+ def set_profile(self, profile_id):
+ self._current_profile_id = profile_id
+ self.draw()
+
+ def set_timestamp(self, timestamp):
+ self._current_timestamp = timestamp
+ self.draw()
+
+ def update(self):
+ self.draw()
diff --git a/src/View/Results/PlotXY.py b/src/View/Results/PlotXY.py
new file mode 100644
index 00000000..3e7a88f3
--- /dev/null
+++ b/src/View/Results/PlotXY.py
@@ -0,0 +1,186 @@
+# PlotXY.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 .
+
+# -*- coding: utf-8 -*-
+
+import logging
+
+from functools import reduce
+
+from tools import timer, trace
+from View.Plot.APlot import APlot
+
+from PyQt5.QtCore import (
+ QCoreApplication
+)
+
+_translate = QCoreApplication.translate
+
+logger = logging.getLogger()
+
+class PlotXY(APlot):
+ def __init__(self, canvas=None, results=None,
+ reach_id=0, profile_id=0,
+ toolbar=None, display_current=True):
+ super(PlotXY, self).__init__(
+ canvas=canvas,
+ data=results,
+ toolbar=toolbar
+ )
+
+ self.display_current = display_current
+
+ self.line_xy = []
+ self.line_gl = []
+
+ self._current_timestamp = max(results.get("timestamps"))
+ self._current_reach_id = reach_id
+ self._current_profile_id = profile_id
+
+ @property
+ def results(self):
+ return self.data
+
+ @timer
+ def draw(self, highlight=None):
+ self.canvas.axes.cla()
+ self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
+
+ if self.results is None:
+ return
+
+ reach = self.results.river.reach(self._current_reach_id)
+
+ if reach.geometry.number_profiles == 0:
+ self._init = False
+ return
+
+ kp_min, kp_max = (-1, -1)
+ if highlight is not None:
+ kp_min, kp_max = highlight
+
+ # Axes
+ self.canvas.axes.set_xlabel(
+ _translate("Results", "X (m)"),
+ color='green', fontsize=12
+ )
+ self.canvas.axes.set_ylabel(
+ _translate("Results", "Y (m)"),
+ color='green', fontsize=12
+ )
+ self.canvas.axes.axis("equal")
+
+ kp = reach.geometry.get_kp()
+ self.canvas.axes.set_xlim(
+ left = min(kp), right = max(kp)
+ )
+
+ # Draw line for each profile
+ self.line_xy = [
+ self.canvas.axes.plot(
+ x, y, lw=1.,
+ color='b' if kp_min <= kp <= kp_max else 'grey',
+ markersize=3, marker='+'
+ )
+ for x, y, kp in zip(
+ reach.geometry.get_x(),
+ reach.geometry.get_y(),
+ kp
+ )
+ ]
+
+ # Guide lines
+ x_complete = reach.geometry.get_guidelines_x()
+ y_complete = reach.geometry.get_guidelines_y()
+
+ self.line_gl = [
+ self.canvas.axes.plot(
+ x, y,
+ )
+ for x, y in zip(x_complete, y_complete)
+ ]
+
+ if self.display_current:
+ # Current profile
+ profile = reach.profile(self._current_profile_id).geometry
+
+ self.plot_selected, = self.canvas.axes.plot(
+ profile.x(),
+ profile.y(),
+ lw=1., markersize=3,
+ marker='+', color="b"
+ )
+ self.plot_selected.set_visible(False)
+
+ # Display point under water
+ poly_l_x = []
+ poly_l_y = []
+ poly_r_x = []
+ poly_r_y = []
+ for profile in reach.profiles:
+ water_z = profile.get_ts_key(
+ self._current_timestamp, "Z"
+ )
+ pgeo = profile.geometry
+
+ x, y = reduce(
+ lambda acc, pts: (acc[0] + [pts.x], acc[1] + [pts.y]),
+ filter(
+ lambda pts: pts.z < water_z,
+ pgeo.points
+ ),
+ ([], [])
+ )
+
+ poly_l_x.append(x[0])
+ poly_l_y.append(y[0])
+ poly_r_x.append(x[-1])
+ poly_r_y.append(y[-1])
+
+ self.canvas.axes.plot(
+ x, y, lw=1.,
+ color='b',
+ markersize=1,
+ marker='o'
+ )
+
+ poly_x = poly_l_x + list(reversed(poly_r_x)) + [poly_l_x[0]]
+ poly_y = poly_l_y + list(reversed(poly_r_y)) + [poly_l_y[0]]
+
+ self.canvas.axes.fill(poly_x, poly_y, color='blue', alpha=1)
+
+ self.canvas.axes.autoscale_view(True, True, True)
+ self.canvas.axes.autoscale()
+ self.canvas.figure.tight_layout()
+ self.canvas.figure.canvas.draw_idle()
+ if self.toolbar is not None:
+ self.toolbar.update()
+
+ def set_reach(self, reach_id):
+ self._current_reach_id = reach_id
+ self._current_profile_id = 0
+ self.draw()
+
+ def set_profile(self, profile_id):
+ self._current_profile_id = profile_id
+ self.draw()
+
+ def set_timestamp(self, timestamp):
+ self._current_timestamp = timestamp
+ self.draw()
+
+ def update(self):
+ self.draw()
diff --git a/src/View/Results/Table.py b/src/View/Results/Table.py
new file mode 100644
index 00000000..8e167459
--- /dev/null
+++ b/src/View/Results/Table.py
@@ -0,0 +1,107 @@
+# Table.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 .
+
+# -*- coding: utf-8 -*-
+
+import logging
+import traceback
+
+from tools import timer, trace
+
+from PyQt5.QtGui import (
+ QKeySequence, QColor
+)
+from PyQt5.QtCore import (
+ Qt, QAbstractTableModel, QModelIndex,
+ QVariant, pyqtSlot, QCoreApplication,
+)
+from PyQt5.QtWidgets import (
+ QMessageBox, QUndoCommand, QUndoStack,
+ QStyledItemDelegate, QLineEdit, QAbstractItemView,
+ QComboBox,
+)
+
+from View.Results.translate import *
+
+logger = logging.getLogger()
+
+_translate = QCoreApplication.translate
+
+
+class TableModel(QAbstractTableModel):
+ def __init__(self, results = None, study = None, mode = None, undo=None):
+ super(QAbstractTableModel, self).__init__()
+
+ self._results = results
+ self._study = study
+ self._mode = mode
+ self._undo_stack = undo
+
+ self._table_headers = table_headers_reach
+ if mode != "reach":
+ self._table_headers = table_headers_profile
+
+ self._headers = list(self._table_headers.keys())
+
+ self._selected = 0
+ self._timestamp = 0
+
+ def rowCount(self, parent=QModelIndex()):
+ if self._mode == "reach":
+ return len(self._results.river.reachs)
+
+ current_reach = self._results.river.reach(self._selected)
+ return len(current_reach.profiles)
+
+ def columnCount(self, parent=QModelIndex()):
+ return len(self._headers)
+
+ def data(self, index, role=Qt.DisplayRole):
+ if role != Qt.ItemDataRole.DisplayRole:
+ return QVariant()
+
+ row = index.row()
+ column = index.column()
+
+ if self._mode == "reach":
+ if self._headers[column] == "name":
+ v = self._results.river.reach(row).name
+ return str(v)
+ else:
+ current_reach = self._results.river.reach(self._selected)
+ if self._headers[column] == "name":
+ v = current_reach.profile(row).name
+ return str(v)
+ elif self._headers[column] == "kp":
+ v = current_reach.profile(row).kp
+ return f"{v:.4f}"
+
+ return QVariant()
+
+ def headerData(self, section, orientation, role=Qt.DisplayRole):
+ if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
+ return self._table_headers[self._headers[section]]
+
+ return QVariant()
+
+ def index(self, row, column, parent=QModelIndex()):
+ if not self.hasIndex(row, column, parent):
+ return QModelIndex()
+
+ return self.createIndex(row, column, QModelIndex())
+
+ def flags(self, index):
+ return Qt.ItemIsEnabled | Qt.ItemIsSelectable
diff --git a/src/View/Results/UndoCommand.py b/src/View/Results/UndoCommand.py
new file mode 100644
index 00000000..ca18efaa
--- /dev/null
+++ b/src/View/Results/UndoCommand.py
@@ -0,0 +1,17 @@
+# UndoCommand.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 .
+
+# -*- coding: utf-8 -*-
diff --git a/src/View/Results/Window.py b/src/View/Results/Window.py
new file mode 100644
index 00000000..22d0a2c4
--- /dev/null
+++ b/src/View/Results/Window.py
@@ -0,0 +1,268 @@
+# 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 .
+
+# -*- coding: utf-8 -*-
+
+import logging
+
+from tools import trace, timer
+
+from View.ASubWindow import ASubMainWindow
+from View.ListedSubWindow import ListedSubWindow
+
+from PyQt5.QtGui import (
+ QKeySequence,
+)
+
+from PyQt5.QtCore import (
+ Qt, QVariant, QAbstractTableModel,
+ QCoreApplication, QModelIndex, pyqtSlot,
+)
+
+from PyQt5.QtWidgets import (
+ QDialogButtonBox, QPushButton, QLineEdit,
+ QFileDialog, QTableView, QAbstractItemView,
+ QUndoStack, QShortcut, QAction, QItemDelegate,
+ QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
+ QSlider,
+)
+
+from View.Plot.MplCanvas import MplCanvas
+
+from View.Results.PlotXY import PlotXY
+from View.Results.PlotAC import PlotAC
+from View.Results.PlotKPC import PlotKPC
+from View.Results.PlotH import PlotH
+
+from View.Results.Table import TableModel
+from View.Results.translate import *
+from View.Stricklers.Window import StricklersWindow
+
+_translate = QCoreApplication.translate
+
+logger = logging.getLogger()
+
+class ResultsWindow(ASubMainWindow, ListedSubWindow):
+ def __init__(self, title="Results",
+ study=None, solver=None, results=None,
+ parent=None):
+ self._study = study
+ self._solver = solver
+ self._results = results
+
+ self._timestamps = sorted(list(self._results.get("timestamps")))
+
+ self.setup_title(title)
+
+ super(ResultsWindow, self).__init__(
+ name=title, ui="Results", parent=parent
+ )
+
+ self.setup_sc()
+ self.setup_table()
+ self.setup_graph()
+ self.setup_slider()
+ self.setup_connections()
+
+ self.ui.setWindowTitle(self._title)
+
+ def setup_title(self, title):
+ self._title = (
+ title + " - "
+ + self._study.name + " - "
+ + self._solver.name + " - "
+ + self._results.date
+ )
+
+ 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):
+ self._table = {}
+
+ for t in ["reach", "profile"]:
+ table = self.find(QTableView, f"tableView_{t}")
+ self._table[t] = TableModel(
+ results = self._results,
+ study = self._study,
+ mode = t,
+ undo = self._undo_stack,
+ )
+ table.setModel(self._table[t])
+
+ table.setSelectionBehavior(QAbstractItemView.SelectRows)
+ table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
+ table.setAlternatingRowColors(True)
+
+ def setup_slider(self):
+ self._slider_profile = self.find(QSlider, f"verticalSlider_profile")
+ default_reach = self._results.river.reach(0)
+ self._slider_profile.setMaximum(len(default_reach.profiles) - 1)
+ self._slider_profile.setValue(0)
+
+ self._slider_time = self.find(QSlider, f"horizontalSlider_time")
+ self._slider_time.setMaximum(len(self._timestamps) - 1)
+ self._slider_time.setValue(len(self._timestamps) - 1)
+
+ def setup_graph(self):
+ self.canvas = MplCanvas(width=5, height=4, dpi=100)
+ self.canvas.setObjectName("canvas")
+ self.plot_layout = self.find(QVBoxLayout, "verticalLayout")
+ self.plot_layout.addWidget(self.canvas)
+
+ self.plot_xy = PlotXY(
+ canvas = self.canvas,
+ results = self._results,
+ reach_id = 0,
+ profile_id = 0,
+ toolbar = None,
+ display_current = False
+ )
+ self.plot_xy.draw()
+
+ self.canvas_2 = MplCanvas(width=5, height=4, dpi=100)
+ self.canvas_2.setObjectName("canvas_2")
+ self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2")
+ self.plot_layout_2.addWidget(self.canvas_2)
+
+ self.plot_kpc = PlotKPC(
+ canvas = self.canvas_2,
+ results = self._results,
+ reach_id = 0,
+ profile_id = 0,
+ toolbar = None
+ )
+ self.plot_kpc.draw()
+
+ self.canvas_3 = MplCanvas(width=5, height=4, dpi=100)
+ self.canvas_3.setObjectName("canvas_3")
+ self.plot_layout_3 = self.find(QVBoxLayout, "verticalLayout_3")
+ self.plot_layout_3.addWidget(self.canvas_3)
+
+ self.plot_ac = PlotAC(
+ canvas = self.canvas_3,
+ results = self._results,
+ reach_id = 0,
+ profile_id = 0,
+ toolbar = None
+ )
+ self.plot_ac.draw()
+
+ self.canvas_4 = MplCanvas(width=5, height=4, dpi=100)
+ self.canvas_4.setObjectName("canvas_4")
+ self.plot_layout_4 = self.find(QVBoxLayout, "verticalLayout_hydrograph")
+ self.plot_layout_4.addWidget(self.canvas_4)
+
+ self.plot_h = PlotH(
+ canvas = self.canvas_4,
+ results = self._results,
+ reach_id = 0,
+ profile_id = 0,
+ toolbar = None
+ )
+ self.plot_h.draw()
+
+ def setup_connections(self):
+ 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)
+
+ fun = {
+ "reach": self._set_current_reach,
+ "profile": self._set_current_profile,
+ }
+
+ for t in ["reach", "profile"]:
+ table = self.find(QTableView, f"tableView_{t}")
+
+ table.selectionModel()\
+ .selectionChanged\
+ .connect(fun[t])
+
+ self._table[t].dataChanged.connect(fun[t])
+
+ self._slider_profile.valueChanged.connect(self._set_current_profile_slider)
+ self._slider_time.valueChanged.connect(self._set_current_timestamp)
+
+
+ def update(self, reach_id = None, profile_id = None, timestamp = None):
+ if reach_id is not None:
+ self.plot_xy.set_reach(reach_id)
+ self.plot_ac.set_reach(reach_id)
+ self.plot_kpc.set_reach(reach_id)
+ self.plot_h.set_reach(reach_id)
+ if profile_id is not None:
+ self.plot_xy.set_profile(profile_id)
+ self.plot_ac.set_profile(profile_id)
+ self.plot_kpc.set_profile(profile_id)
+ self.plot_h.set_profile(profile_id)
+ if timestamp is not None:
+ self.plot_xy.set_timestamp(timestamp)
+ self.plot_ac.set_timestamp(timestamp)
+ self.plot_kpc.set_timestamp(timestamp)
+ self.plot_h.set_timestamp(timestamp)
+
+ self.plot_xy.draw()
+ self.plot_ac.draw()
+ self.plot_kpc.draw()
+ self.plot_h.draw()
+
+
+ def _set_current_reach(self):
+ table = self.find(QTableView, f"tableView_reach")
+ indexes = table.selectedIndexes()
+ if len(indexes) == 0:
+ return
+
+ self.update(reach_id = indexes[0].row())
+
+ def _set_current_profile(self):
+ table = self.find(QTableView, f"tableView_profile")
+ indexes = table.selectedIndexes()
+ if len(indexes) == 0:
+ return
+
+ ind = indexes[0].row()
+ self.update(profile_id = ind)
+ self._slider_profile.setValue(ind)
+
+ def _set_current_profile_slider(self):
+ pid = self._slider_profile.value()
+ self.update(profile_id = pid)
+
+ return
+
+ def _set_current_timestamp(self):
+ timestamp = self._timestamps[self._slider_time.value()]
+ self.update(timestamp = timestamp)
+
+ def copy(self):
+ logger.info("TODO: copy")
+
+ def paste(self):
+ logger.info("TODO: paste")
+
+ def undo(self):
+ self._table.undo()
+
+ def redo(self):
+ self._table.redo()
diff --git a/src/View/Results/translate.py b/src/View/Results/translate.py
new file mode 100644
index 00000000..4b5ab3c5
--- /dev/null
+++ b/src/View/Results/translate.py
@@ -0,0 +1,30 @@
+# 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 .
+
+# -*- coding: utf-8 -*-
+
+from PyQt5.QtCore import QCoreApplication
+
+_translate = QCoreApplication.translate
+
+table_headers_reach = {
+ "name": _translate("Results", "Reach name"),
+}
+
+table_headers_profile = {
+ "name": _translate("Results", "Name"),
+ "kp": _translate("Results", "KP (m)"),
+}
diff --git a/src/View/RunSolver/Log/Window.py b/src/View/RunSolver/Log/Window.py
index fb7ba631..93d42165 100644
--- a/src/View/RunSolver/Log/Window.py
+++ b/src/View/RunSolver/Log/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import tempfile
diff --git a/src/View/RunSolver/Window.py b/src/View/RunSolver/Window.py
index 822f2bb7..872d72ef 100644
--- a/src/View/RunSolver/Window.py
+++ b/src/View/RunSolver/Window.py
@@ -1,7 +1,24 @@
+# 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 .
+
# -*- coding: utf-8 -*-
-import tempfile
import os
+import logging
+import tempfile
from queue import Queue
from tools import trace, timer
@@ -37,6 +54,8 @@ except:
_translate = QCoreApplication.translate
+logger = logging.getLogger()
+
class SelectSolverWindow(ASubWindow, ListedSubWindow):
def __init__(self, title="Select solver",
study=None, config=None,
@@ -94,6 +113,8 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self._config = config
self._solver = solver
+ self._results = None
+
super(SolverLogWindow, self).__init__(
name=self._title, ui="SolverLog", parent=parent
)
@@ -153,6 +174,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_pause").triggered.connect(self.pause)
self.find(QAction, "action_stop").triggered.connect(self.stop)
self.find(QAction, "action_log_file").triggered.connect(self.log_file)
+ self.find(QAction, "action_results").triggered.connect(self.results)
self._alarm.timeout.connect(self.update)
@@ -177,12 +199,16 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(False)
+ self.find(QAction, "action_results").setEnabled(True)
if self._solver.log_file() != "":
self.find(QAction, "action_log_file").setEnabled(True)
while self._output.qsize() != 0:
s = self._output.get()
- self._log(s)
+ if type(s) is str and "[ERROR]" in s:
+ self._log(s, color="red")
+ else:
+ self._log(s)
def start(self):
if self._solver.is_stoped():
@@ -193,6 +219,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self._process = self.new_process(self._parent)
self._log(" *** Start", color="blue")
+ self._results = None
self._solver.start(self._process)
self.find(QAction, "action_start").setEnabled(False)
@@ -202,6 +229,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(True)
self.find(QAction, "action_log_file").setEnabled(False)
+ self.find(QAction, "action_results").setEnabled(False)
def pause(self):
self._log(" *** Pause", color="blue")
@@ -210,6 +238,7 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(True)
+ self.find(QAction, "action_results").setEnabled(False)
def stop(self):
self._log(" *** Stop", color="blue")
@@ -218,9 +247,15 @@ class SolverLogWindow(ASubMainWindow, ListedSubWindow):
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(False)
+ self.find(QAction, "action_results").setEnabled(True)
if self._solver.log_file() != "":
self.find(QAction, "action_log_file").setEnabled(True)
+ def results(self):
+ if self._results is None:
+ self._results = self._solver.results(self._study, self._workdir, qlog = self._output)
+ self._parent.open_solver_results(self._solver, self._results)
+
def log_file(self):
file_name = os.path.join(self._workdir, self._solver.log_file())
log = SolverLogFileWindow(
diff --git a/src/View/SolverParameters/Table.py b/src/View/SolverParameters/Table.py
index 7b44159d..5aa488ab 100644
--- a/src/View/SolverParameters/Table.py
+++ b/src/View/SolverParameters/Table.py
@@ -1,5 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
+import logging
+import traceback
+
from tools import trace, timer
from PyQt5.QtCore import (
@@ -81,16 +100,20 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- if self._headers[column] == "value":
- if value in tr.r_yes_no:
- value = tr.r_yes_no[value].lower()
+ try:
+ if self._headers[column] == "value":
+ if value in tr.r_yes_no:
+ value = tr.r_yes_no[value].lower()
- self._undo.push(
- SetCommand(
- self._params, row,
- "value", value
+ self._undo.push(
+ SetCommand(
+ self._params, row,
+ "value", value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/SolverParameters/UndoCommand.py b/src/View/SolverParameters/UndoCommand.py
index 6a8dc1eb..d3343d00 100644
--- a/src/View/SolverParameters/UndoCommand.py
+++ b/src/View/SolverParameters/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -17,7 +33,7 @@ class SetCommand(QUndoCommand):
self._index = index
self._column = column
self._old = self._data.get(self._index)[column]
- self._new = new_value
+ self._new = str(new_value)
def undo(self):
self._data.get(self._index)[self._column] = self._old
diff --git a/src/View/SolverParameters/Window.py b/src/View/SolverParameters/Window.py
index 4e154a54..c04eebc7 100644
--- a/src/View/SolverParameters/Window.py
+++ b/src/View/SolverParameters/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
@@ -40,7 +56,7 @@ class SolverParametersWindow(ASubMainWindow, ListedSubWindow):
# Init tanslate dictionary
tr.init()
- title = title + " - " + study.name
+ self._title = title + " - " + study.name
super(SolverParametersWindow, self).__init__(
name=title, ui="SolverParameters", parent=parent
@@ -53,7 +69,7 @@ class SolverParametersWindow(ASubMainWindow, ListedSubWindow):
self.setup_table()
self.setup_connections()
- self.ui.setWindowTitle(title)
+ self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = {}
diff --git a/src/View/SolverParameters/translate.py b/src/View/SolverParameters/translate.py
index 6085dbfb..76cb70ac 100644
--- a/src/View/SolverParameters/translate.py
+++ b/src/View/SolverParameters/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/Stricklers/Table.py b/src/View/Stricklers/Table.py
index 29f8fd53..5d32cda5 100644
--- a/src/View/Stricklers/Table.py
+++ b/src/View/Stricklers/Table.py
@@ -1,5 +1,24 @@
+# Table.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 .
+
# -*- coding: utf-8 -*-
+import logging
+import traceback
+
from tools import trace, timer
from PyQt5.QtCore import (
@@ -23,8 +42,9 @@ from View.Stricklers.UndoCommand import (
from View.Stricklers.translate import *
-_translate = QCoreApplication.translate
+logger = logging.getLogger()
+_translate = QCoreApplication.translate
class TableModel(QAbstractTableModel):
def __init__(self, data=None, undo=None, tab=""):
@@ -76,30 +96,34 @@ class TableModel(QAbstractTableModel):
row = index.row()
column = index.column()
- if self._headers[column] == "name":
- self._undo.push(
- SetNameCommand(
- self._data, row, value
+ try:
+ if self._headers[column] == "name":
+ self._undo.push(
+ SetNameCommand(
+ self._data, row, value
+ )
)
- )
- elif self._headers[column] == "comment":
- self._undo.push(
- SetCommentCommand(
- self._data, row, value
+ elif self._headers[column] == "comment":
+ self._undo.push(
+ SetCommentCommand(
+ self._data, row, value
+ )
)
- )
- elif self._headers[column] == "minor":
- self._undo.push(
- SetMinorCommand(
- self._data, row, value
+ elif self._headers[column] == "minor":
+ self._undo.push(
+ SetMinorCommand(
+ self._data, row, value
+ )
)
- )
- elif self._headers[column] == "medium":
- self._undo.push(
- SetMediumCommand(
- self._data, row, value
+ elif self._headers[column] == "medium":
+ self._undo.push(
+ SetMediumCommand(
+ self._data, row, value
+ )
)
- )
+ except Exception as e:
+ logger.info(e)
+ logger.debug(traceback.format_exc())
self.dataChanged.emit(index, index)
return True
diff --git a/src/View/Stricklers/UndoCommand.py b/src/View/Stricklers/UndoCommand.py
index 07e782de..ee75cf99 100644
--- a/src/View/Stricklers/UndoCommand.py
+++ b/src/View/Stricklers/UndoCommand.py
@@ -1,3 +1,19 @@
+# UndoCommand.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 .
+
# -*- coding: utf-8 -*-
from copy import deepcopy
@@ -17,7 +33,7 @@ class SetNameCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).name
- self._new = new_value
+ self._new = str(new_value)
def undo(self):
self._data.get(self._index).name = self._old
@@ -32,7 +48,7 @@ class SetCommentCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).comment
- self._new = new_value
+ self._new = str(new_value)
def undo(self):
self._data.get(self._index).comment = self._old
@@ -47,7 +63,7 @@ class SetMinorCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).minor
- self._new = new_value
+ self._new = float(new_value)
def undo(self):
self._data.get(self._index).minor = self._old
@@ -62,7 +78,7 @@ class SetMediumCommand(QUndoCommand):
self._data = data
self._index = index
self._old = self._data.get(self._index).medium
- self._new = new_value
+ self._new = float(new_value)
def undo(self):
self._data.get(self._index).medium = self._old
diff --git a/src/View/Stricklers/Window.py b/src/View/Stricklers/Window.py
index 1d2bfe43..8726f971 100644
--- a/src/View/Stricklers/Window.py
+++ b/src/View/Stricklers/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
import logging
@@ -35,7 +51,7 @@ logger = logging.getLogger()
class StricklersWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Stricklers", study=None, config=None, parent=None):
- title = title + " - " + study.name
+ self._title = title + " - " + study.name
super(StricklersWindow, self).__init__(
name=title, ui="Stricklers", parent=parent
@@ -48,7 +64,7 @@ class StricklersWindow(ASubMainWindow, ListedSubWindow):
self.setup_table()
self.setup_connections()
- self.ui.setWindowTitle(title)
+ self.ui.setWindowTitle(self._title)
def setup_sc(self):
self._undo_stack = QUndoStack()
diff --git a/src/View/Stricklers/translate.py b/src/View/Stricklers/translate.py
index 4664e163..ccafd5d8 100644
--- a/src/View/Stricklers/translate.py
+++ b/src/View/Stricklers/translate.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/View/Study/Window.py b/src/View/Study/Window.py
index a90ed549..7218f9d3 100644
--- a/src/View/Study/Window.py
+++ b/src/View/Study/Window.py
@@ -1,3 +1,19 @@
+# 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 .
+
# -*- coding: utf-8 -*-
from Model.Study import Study
diff --git a/src/View/ui/MainWindow.ui b/src/View/ui/MainWindow.ui
index e91bd14d..ea77d698 100644
--- a/src/View/ui/MainWindow.ui
+++ b/src/View/ui/MainWindow.ui
@@ -85,17 +85,12 @@
-
-
-
-
-
@@ -117,32 +112,8 @@
&Geometry
-
-
-
-
-
-
-
-
-
-
-
-
@@ -298,12 +262,8 @@
-
-
-
-
@@ -675,11 +635,17 @@
+
+ false
+
Help PAMHYR
+
+ false
+
Help MAGE
@@ -737,10 +703,10 @@
ressources/exit_bis.pngressources/exit_bis.png
- Quit application
+ Quit
- Quitter l'application (Ctrl+Q)
+ Quit the application (Ctrl+Q)
Ctrl+Q
@@ -755,7 +721,7 @@
Run solver
- Run solver on current study
+ Run a solver
@@ -836,7 +802,7 @@
Mesh
- Afficher le maillage
+ Display meshed reach
@@ -871,7 +837,7 @@
Friction
- Edit friction frictions and lateral contributions
+ Edit friction frictions
@@ -916,6 +882,9 @@
Initial conditions
+
+ Define initial conditions
+
diff --git a/src/View/ui/Results.ui b/src/View/ui/Results.ui
new file mode 100644
index 00000000..d975641b
--- /dev/null
+++ b/src/View/ui/Results.ui
@@ -0,0 +1,120 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 942
+ 655
+
+
+
+ MainWindow
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ Qt::Vertical
+
+
+
+
+
+
+
-
+
+
+ 0
+
+
+
+ Geometry
+
+
+
-
+
+
+ Qt::Vertical
+
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hydrograph
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/View/ui/SolverLog.ui b/src/View/ui/SolverLog.ui
index bbbc3edb..c94c57db 100644
--- a/src/View/ui/SolverLog.ui
+++ b/src/View/ui/SolverLog.ui
@@ -63,6 +63,7 @@
+
@@ -100,6 +101,11 @@
LogFile
+
+
+ results
+
+
diff --git a/src/View/ui/about.ui b/src/View/ui/about.ui
index 6b4f6957..579e0095 100644
--- a/src/View/ui/about.ui
+++ b/src/View/ui/about.ui
@@ -6,53 +6,86 @@
0
0
- 362
- 98
+ 553
+ 262
Form
+
+
+
-
-
+
-
-
+
- ressources/logoCemagref.gif
-
-
- true
+ ressources/Logo-INRAE.png
-
-
-
-
-
-
-
- 16
- 75
- true
-
-
-
- PamHyr
-
-
-
- -
-
-
- Version en developpement:
-
-
-
-
+
+
+
+ 16
+ 75
+ true
+
+
+
+ About PAMHYR
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ Version: @version
+
+
+
+ -
+
+
+ License: GPLv3+
+
+
+
+ -
+
+
+ <a href="https://gitlab.irstea.fr/theophile.terraz/pamhyr">Source code</a>
+
+
+ Qt::RichText
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
diff --git a/src/View/ui/ressources/Logo-INRAE.png b/src/View/ui/ressources/Logo-INRAE.png
new file mode 100644
index 00000000..0cd93142
Binary files /dev/null and b/src/View/ui/ressources/Logo-INRAE.png differ
diff --git a/src/View/ui/ui_to_py.sh b/src/View/ui/ui_to_py.sh
index 92b12ff2..f4d11a5d 100755
--- a/src/View/ui/ui_to_py.sh
+++ b/src/View/ui/ui_to_py.sh
@@ -1,5 +1,21 @@
#! /bin/sh
+# ui_to_py.sh -- 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 .
+
for ui in $(ls *.ui)
do
python3 -m PyQt5.uic.pyuic -x $ui -o ${ui%.*}.py
diff --git a/src/config.py b/src/config.py
index 46e4ad2e..d1ebb71e 100644
--- a/src/config.py
+++ b/src/config.py
@@ -1,3 +1,19 @@
+# config.py -- Pamhyr configuration manager
+# 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 .
+
# -*- coding: utf-8 -*-
import os
@@ -18,7 +34,7 @@ logger = logging.getLogger()
class Config(SQL):
def __init__(self):
- self._version = '0.0.1'
+ self._version = '0.0.3'
self.filename = Config.filename()
self.set_default_value()
@@ -63,12 +79,38 @@ class Config(SQL):
self.commit()
+
def _update(self):
version = self.execute(f"SELECT value FROM info WHERE key='version'")[0]
if version != self._version:
logger.info(f"Configuration file update from {version} to {self._version}...")
+ major, minor, release = version.strip().split(".")
+
+ if major == minor == "0":
+ if int(release) < 2:
+ # Add default solver
+ posix = os.name == 'posix'
+ self.execute(f"""
+ INSERT INTO solver VALUES (
+ 'mage8',
+ 'default-mage',
+ 'Default PAMHYR mage 8 version',
+
+ '', '', '',
+
+ '',
+ '@install_dir/mage/mage{"" if posix else ".exe"} -fp=1 @input',
+ ''
+ )
+ """)
+ if int(release) < 3:
+ self.execute(f"INSERT INTO data VALUES ('last_study', '')")
+ self.execute(f"INSERT INTO data VALUES ('close_correctly', 'True')")
+
+ self.commit()
+
def _load_solver(self):
self._solvers = []
@@ -138,6 +180,12 @@ class Config(SQL):
v = self.execute("SELECT value FROM data WHERE key='lang'")
self.lang = v[0]
+ # Last study
+ v = self.execute("SELECT value FROM data WHERE key='last_study'")
+ self.last_study = v[0]
+ v = self.execute("SELECT value FROM data WHERE key='close_correctly'")
+ self.close_correctly = v[0] == "True"
+
# Debug
v = self.execute("SELECT value FROM data WHERE key='debug'")
self.debug = v[0] == "True"
@@ -190,6 +238,8 @@ class Config(SQL):
"backup_max": self.backup_max,
"editor": self.editor,
"lang": self.lang,
+ "last_study": self.last_study,
+ "close_correctly": self.close_correctly,
"debug": self.debug,
}
@@ -212,6 +262,13 @@ class Config(SQL):
# Solvers
self._solvers = []
+ posix = os.name == 'posix'
+ ctor = solver_type_list["mage8"]
+ new = ctor("default-mage")
+ new._description = "Default PAMHYR mage 8 version"
+ new._cmd_solver = f""""@install_dir/mage/mage{"" if posix else ".exe"}" -fp=1 @input"""
+ self._solvers.append(new)
+
# Meshing tool
self.meshing_tool = ""
@@ -234,9 +291,25 @@ class Config(SQL):
# Stricklers
self.stricklers = StricklersList()
+ # Last study
+ self.last_study = ""
+ self.close_correctly = False
+
# Debug
self.debug = False
+ def set_close_correctly(self):
+ self.close_correctly = True
+ self.execute(f"UPDATE data SET value='True' WHERE key='close_correctly'")
+ self.commit()
+
+ def set_last_study(self, filename):
+ self.last_study = filename
+ self.close_correctly = False
+ self.execute(f"UPDATE data SET value='{self._sql_format(self.last_study)}' WHERE key='last_study'")
+ self.execute(f"UPDATE data SET value='{self.close_correctly}' WHERE key='close_correctly'")
+ self.commit()
+
@classmethod
def filename(cls):
file = ""
diff --git a/src/lang/constant_string.py b/src/lang/constant_string.py
index b599389a..8466a3b4 100644
--- a/src/lang/constant_string.py
+++ b/src/lang/constant_string.py
@@ -1,3 +1,19 @@
+# constant_string.py -- Pamhyr constant string definition for translate
+# 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 .
+
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
diff --git a/src/lang/create_ts.sh b/src/lang/create_ts.sh
index c3019916..1b30d684 100755
--- a/src/lang/create_ts.sh
+++ b/src/lang/create_ts.sh
@@ -1,5 +1,21 @@
#! /bin/sh
+# create_ts.sh -- Pamhyr script to generate translate files
+# 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 .
+
SOURCES=$(find ../ -name "*.py")
FROM=$(find ../ -name "*.ui")
diff --git a/src/lang/fr.ts b/src/lang/fr.ts
index d44729f7..9bc3f345 100644
--- a/src/lang/fr.ts
+++ b/src/lang/fr.ts
@@ -1,1101 +1,2132 @@
-
+
- Dialog
+ About
-
- Dialog
+
+ Contributors:
+ Contributeurs :
+
+
+
+ BoundaryCondition
+
+
+ Not associate
+ Non associer
+
+
+
+ X
-
+
+ Y
+
+
+
+
+ Time
+ Temps
+
+
+
+ Date
+ Date
+
+
+
+ Z (m)
+ Z (m)
+
+
+
+ days
+ jours
+
+
+
+ day
+ jour
+
+
+
+ Not defined
+ Non définie
+
+
+
+ Ponctual contribution
+ Contributions ponctuelles
+
+
+
+ Time over Z
+
+
+
+
+ Time over Discharge
+
+
+
+
+ Z over Discharge
+
+
+
+
Name
Nom
-
+
Type
Type
-
+
+ Node
+ Nœud
+
+
+
+ Discharge (m³/s)
+ Débit (m³/s)
+
+
+
+ Discharge (m³/s)
+
+
+
+
+ Checker
+
+
+ Mage network graph {mode} checker
+
+
+
+
+ Check if the network graph is valid
+ Vérifie si le graph réseau est valide
+
+
+
+ Study network reach checker
+
+
+
+
+ Check if exists at least one reach for study
+ Vérifie si il exists au moins un Bief dans l'étude
+
+
+
+ Study geometry checker
+ Vérificateur de géometrie de l'étude
+
+
+
+ Check if exists geometry for each reach of study
+ Vérifie si la géométrie exists pour chaque bief de l'étude
+
+
+
+ Dummy ok
+
+
+
+
+ Dummy warning
+
+
+
+
+ Dummy error
+
+
+
+
+ Dialog
+
+
+ Dialog
+
+
+
+
+ Name
+ Nom
+
+
+
+ Type
+ Type
+
+
+
Description
Description
-
+
Solver
- Solveur
+ Solver
-
+
Path
Chemin
-
+
Output formater
- Formateur de resultat
+ Formateur de sortie
-
+
Command line
Ligne de commande
-
+
Input formater
Formateur d'entrée
-
- Reverse
- Retourner
+
+ Cancel
+ Annuler
-
+
+ Run
+ Lancer
+
+
+
+ Draft
+ Débit (m³/s)
+
+
+
Solvers
- Solveurs
+ Solvers
-
+
Meshing tool
Mailleur
-
+
Meshing tool path
Chemin du mailleur
-
+
Constants
Constantes
-
+
Segment number
- Nombre de segment
+ Nombre se segments
-
+
Listing maximum size
- Taille maximum des listings
+ Taille maximal du listing
-
+
1000
1000
-
+
500000
- 500000
+
-
+
Backup
- Backup
+ Archive
-
+
Auto save
- Sauvegarde automatique
+ Sauvegarde auto
-
+
Frequence
Fréquence
-
+
Max. archives
- Nombre maximum de sauvegarde
+ Nombre max d'archive
-
+
Enable
Activé
-
+
HH:mm:ss
-
+
+ Stricklers
+ Stricklers
+
+
+
+ Editor
+ Éditeur
+
+
+
+ This value must be used for reading or editing files in speficic case.
+ Cette valeur peut être utiliser dans des cas spécifique pour lire ou écrire dans un fichier.
+
+
+
+ Editor command
+ Commande de l'éditeur
+
+
+
+ - The "@file" keyworkd is replace by the path of file to open.
+ - Le mot clef "@file" sera remplacer par le chemin du fichier à ouvrir.
+
+
+
Language
Langage
-
+
Please restart application after language modification
- Please restart application after language modification
+ Please restart application after language modification
-
+
MyNewStudy
- MaNouvelleÉtude
+ Ma nouvelle étude
+
+
+
+ Time system
+ Système de temps
+
+
+
+ Time
+ Temps
+
+
+
+ Date
+ Date
+
+
+
+ Staring date
+ Date de départ
+
+
+
+ dd/MM/yyyy HH:mm:ss
+
+
+
+
+ Creation date :
+ Date de création :
+
+
+
+ Last modification :
+ Dernière modification :
+
+
+
+ Discharge
+ Débit (m³/s)
+
+
+
+ Exception
+
+
+ Generic error message
+
+
+
+
+ Undefined error message
+
+
+
+
+ Method not implemented
+
+
+
+
+ Method
+
+
+
+
+ not implemented
+
+
+
+
+ for class
+
+
+
+
+ Not implemented method
+
+
+
+
+ FileFormatError
+
+
+
+
+ Invalid file format:
+
+
+
+
+ File format error
+
+
+
+
+ Invalid file format
+
+
+
+
+ Invalid file
+
+
+
+
+ format because of
+
+
+
+
+ Clipboard format error
+
+
+
+
+ without header
+
+
+
+
+ with header
+
+
+
+
+ Invalid clipboard data format:
+
+
+
+
+ Clipboard format unknown
+
Form
-
+
Form
-
- PamHyr
+
+ dd/MM/yyyy HH:mm:ss
-
- Version en developpement:
+
+ days
+ jours
+
+
+
+ HH:mm:ss
+
+
+
+
+ About PAMHYR
+ À propos de PAMHYR
+
+
+
+ Version: @version
+
+
+
+
+ License: GPLv3+
+ Licence: GPLv3+
+
+
+
+ <a href="https://gitlab.irstea.fr/theophile.terraz/pamhyr">Source code</a>
+ <a href="https://gitlab.irstea.fr/theophile.terraz/pamhyr">Code source</a>
+
+
+
+ ...
-
- MainWindow
+
+ Frictions
-
- PAMHYR
-
+
+ Not defined
+ Non définie
-
+
+ Name
+ Nom
+
+
+
+ Begin kp (m)
+ Pk de départ (m)
+
+
+
+ End kp (m)
+ Pk de fin (m)
+
+
+
+ Begin strickler
+ strickler de départ
+
+
+
+ End strickler
+ Strickler de fin
+
+
+
+ Geometry
+
+
+ Name
+ Nom
+
+
+
+ Kp (m)
+ Pk (m)
+
+
+
+ Type
+ Type
+
+
+
+ upstream
+ amont
+
+
+
+ downstream
+ aval
+
+
+
+ LateralContribution
+
+
+ Name
+ Nom
+
+
+
+ Minor bed
+ Lit mineur
+
+
+
+ Medium bed
+ Lit moyen
+
+
+
+ Comment
+ Commentaire
+
+
+
+ Not associate
+ Non associer
+
+
+
+ X
+
+
+
+
+ Y
+
+
+
+
+ Time
+ Temps
+
+
+
+ Date
+ Date
+
+
+
+ Z (m)
+
+
+
+
+ days
+ jours
+
+
+
+ day
+ jour
+
+
+
+ Not defined
+ Non définie
+
+
+
+ Lateral contribution
+ Contribution laterale
+
+
+
+ Rain
+ Pluie
+
+
+
+ Evaporation
+ Évaporation
+
+
+
+ Type
+ Type
+
+
+
+ Reach
+ Bief
+
+
+
+ Begin kp (m)
+ Pk de départ (m)
+
+
+
+ End kp (m)
+ Pk de fin (m)
+
+
+
+ KP (m)
+ PK (m)
+
+
+
+ Elevation (m)
+ Altitude (m)
+
+
+
+ Height (m)
+ Hauteur (m)
+
+
+
+ Discharge (m³/s)
+ Débit (m³/s)
+
+
+
+ Discharge (m³/s)
+
+
+
+
+ MainWindow
+
+
+ MainWindow
+ Fenêtre principale
+
+
+
+ toolBar
+ Bar d'outils
+
+
+
+ Add node or edge
+ Ajouter un nœud ou une arête
+
+
+
+ Remove node or edge
+ Supprimer un nœud ou une arête
+
+
+
+ PAMHYR
+ PAMHYR
+
+
+
&File
&Fichier
-
+
&River Network
&Réseau
-
+
&Geometry
&Géométrie
-
+
Comparer
- Comparer
+ Comparer
-
- Profil en travers
-
-
-
-
+
&Execute
- &Exécuter
+ &Executer
-
+
&Hydraulics
- &Hydrolique
+ &Hydraulique
-
+
&Plots
- &Graphiques
+ Gra&phique
-
+
&Cartography
&Cartographie
-
+
&Help
&Aide
-
- toolBar
-
-
-
-
+
toolBar_2
-
+
-
+
New study
Nouvelle étude
-
+
Ctrl+N
-
+ Ctrl+N
-
+
Open a study
Ouvrir une étude
-
+
Ctrl+O
-
+ Ctrl+O
-
+
Import data from MAGE
- Importer un jeu de données MAGE
+ Importer des données d'une étude MAGE
-
+
Import data from RubarBE
- Importer un jeu de données RubarBE
+ Importer des données d'une étude RubarBE
-
+
Close
Fermer
-
+
Close current study
- Fermer l'étude courante
+ Fermer l'étude en cours
-
+
Save mesh
Sauvegarder le maillage
-
+
Save
Sauvegarder
-
+
Ctrl+S
-
+ Ctrl+S
-
+
Save as ...
- Sauvegarder sous ...
+ Sauvegarder sous...
-
+
Ctrl+Shift+S
-
+ Ctrl+Shift+S
-
+
Archive
-
+ Archive
-
+
Pamhyr configuration
- Configuration de PamHyr
+ Configuration de PAMHYR
-
+
Quit
Quitter
-
+
Ctrl+F4
-
+ Ctrl+F4
-
+
Edit river network
Éditer le réseau
-
+
Edit geometry
Éditer la géométrie
-
+
Import geometry
- Importer une géometrie
+ Importer une géométrie
-
+
Export geometry
-
+ Exporter la géométrie
-
+
Run extrenal meshing tool
-
+ Lancer le mailler externe
-
+
choose meshing tool by reach
-
+
View meshed geometry
-
+ Voir la géométrie mailler
-
+
Export mesh
-
+ Exporter le maillage
-
+
Delete mesh of current reach
-
+ Supprimer le maillage
-
+
Delete all mesh
-
+
-
+
Abscisse - Cote
-
+
XYZ
-
+
-
- Numerical parameter for MAGE solver
-
+
+ Numerical parameter for solvers
+ Paramètre numerique des solvers
-
+
Boundary conditions and one-time contributions
-
+ Condition aux limites et apports ponctuels
-
+
Initial conditions
-
+ Conditions initiales
-
+
Export initial conditions
-
+ Exporter les conditions initiales
-
+
Import final state as initial condition
-
+ Importer un état final comme conditions initiales
-
+
Edit friction
-
+ Éditer les frottements
-
+
Edit lateral contributions
-
+ Éditer les apports latéraux
-
+
Edit spills
-
+
Edit cross building
-
+ Éditer les ouvrages
-
+
Run solver
-
+ Lancer un solver
-
+
+ F5
+ F5
+
+
+
Stop solver
-
+ Stopper le solver
-
+
Display listings
-
+
Simulation directory management
-
+
Open
- Ouvrir
+ Ouvrir
-
+
Hydrograph
-
+ Hydrogramme
-
+
Limnigram
-
+ Limnigramme
-
+
Map current reach
-
+ Cartographier le bief sélectionné
-
+
Help PAMHYR
-
+ Aide de PAMHYR
-
- help MAGE
-
+
+ Help MAGE
+ Aide de MAGE
-
+
About
-
+ A propos
-
+
ouvrir
-
+
Save current study
-
+ Sauvegarder l'étude
-
+
Ctrl+F
-
+ Ctrl+F
-
+
Quit application
-
+ Quitter l'application
-
- Quitter l'application (Ctrl+Q)
-
-
-
-
+
Ctrl+Q
-
+ Ctrl+Q
-
- Run solver on current study
-
-
-
-
- Ctrl+X
-
-
-
-
+
stop solver
-
+
Interrompt la simulation en cours
-
+
Ctrl+C
-
+ Ctrl+C
-
+
Run external meshing tool
-
+ Lancer le mailler externe
-
+
Run meshing tool on current reach geometry
-
+ Lancer le mailler externe sur le bief selectionné
-
+
Display simulation listing
-
+
Display current simulation listing
-
+
River network
-
+ Réseau
-
+
Geometry
-
+ Géométrie
-
+
Edit reach geometry
-
+ Éditer la géométrie
-
+
Mesh
-
+ Maillage
-
- Afficher le maillage
-
-
-
-
+
Boundary conditions
-
+ Conditions aux limites
-
+
Edit boundary conditions and one-time contributions
-
+ Éditer les conditions aux limites et les apports ponctuels
-
+
Lateral contribution
-
+ Contributions latérales
-
+
Edit lateral contribution
-
+ Éditer les contributions latérales
-
+
Spills
-
+
Edit lateral spills
-
- Sections
-
+
+ Friction
+ Frottements
-
- Edit section frictions and lateral contributions
-
+
+ Stricklers
+
-
- Frictions
-
+
+ Edit the study stricklers
+ Éditer les Stricklers de l'étude
-
- Edit friction at the bottom
-
-
-
-
+
Building
-
+ Ouvrages
-
+
Edit building (valve, ...), singularity and pump
-
+ Éditer les ouvrages
-
+
Edit study
-
+ Éditer l'étude
-
+
English
-
+
-
+
French
+
+
+
+
+ Revert
+ Retourner
+
+
+
+ Open in editor
+ Ouvrir dans l'éditeur
+
+
+
+ Eval
+ Évaluer
+
+
+
+ Ctrl+Return
+ Ctrl+Return
+
+
+
+ Liquid
+ Liquide
+
+
+
+ Solid
+ Solide
+
+
+
+ Suspenssion
+ Suspenssion
+
+
+
+ Add
+ Ajouter
+
+
+
+ Add a new boundary condition or lateral contribution
+ Ajouter une condition aux limites ou un apport ponctuel
+
+
+
+ Delete
+ Supprimer
+
+
+
+ Delete current selected rows
+ Supprimer les lignes selectionnées
+
+
+
+ Ctrl+D
+ Ctrl+D
+
+
+
+ Edit
+ Éditer
+
+
+
+ Edit boundary condition or lateral contribution
+ Éditer une condition aux limites ou un apport ponctuel
+
+
+
+ Ctrl+E
+ Ctrl+E
+
+
+
+ Sort
+ Trier
+
+
+
+ Sort boundary condition by name
+ Trié par nom
+
+
+
+ Study stricklers
+ Stricklers de l'étude
+
+
+
+ Application stricklers
+ Stricklers de l'application
+
+
+
+ Add new stricklers
+ Ajouter un stricklers
+
+
+
+ Delete selected stricklers
+ Supprimer les stricklers selectionnés
+
+
+
+ Sort stricklers
+ Trier les stricklers
+
+
+
+ delete
+ Supprimer
+
+
+
+ Edit stricklers
+ Éditer les stricklers
+
+
+
+ Cancel
+ Annuler
+
+
+
+ Retry
+ Ressayer
+
+
+
+ Run
+ Lancer
+
+
+
+ Retry check
+ Ressayer la vérification
+
+
+
+ Stop
+ Stopper
+
+
+
+ Start
+ Commencer
+
+
+
+ Pause
+ Pause
+
+
+
+ LogFile
+ Fichier de log
+
+
+
+ Generate minimal height
+ Généré une hauteur minimale
+
+
+
+ Generate constant discharge
+ Généré un debit constant
+
+
+
+ Add new initial condition
+ Ajouter une nouvelle condition initiale
+
+
+
+ Delete inital condition
+ Supprimer une condition initiale
+
+
+
+ sort
+ Trier
+
+
+
+ Sort inital condition
+ Trier les conditions initiales
+
+
+
+ Add a new point in boundary condition or lateral contribution
+ Ajouter un nouveau point
+
+
+
+ Sort boundary condition point
+ Trier les points des conditions aux limites
+
+
+
+ Quit the application (Ctrl+Q)
+ Quitter l'application (Ctrl+Q)
+
+
+
+ Run a solver
+ Lancer un solver
+
+
+
+ Display meshed reach
-
- &Fichier
-
+
+ Edit friction frictions
+ Éditer les frottements
-
- &Hydraulique
-
-
-
-
- &Graphiques
-
-
-
-
- &Cartographie
-
-
-
-
- &Aide
-
-
-
-
- Ctrl+R
-
-
-
-
- Fermer
-
-
-
-
- Enregistrer le maillage
-
-
-
-
- Enregistrer
-
-
-
-
- Enregistrer sous ...
-
-
-
-
- Archiver
-
-
-
-
- Configuration de Pamhyr
-
-
-
-
- Quitter
-
-
-
-
- Lancer le mailleur externe
-
-
-
-
- Choix du mailleur par bief
-
-
-
-
- Exporter le maillage
-
-
-
-
- Supprimer le maillage du bief courant
-
-
-
-
- Supprimer l'ensemble des maillages
-
-
-
-
- Conditions aux Limites & Apports Ponctuels
-
-
-
-
- Conditions initiales
-
-
-
-
- Solveur MAGE
-
-
-
-
- Stop Solveur
-
-
-
-
- Afficher les listings
-
-
-
-
- Ouvrir
-
-
-
-
- Hydrogramme
-
-
-
-
- Limnigramme
-
-
-
-
- Ligne d'eau
-
-
-
-
- Ligne d'eau finale
-
-
-
-
- Ligne d'eau enveloppe
-
-
-
-
- Voir l'animation (MAGE)
-
-
-
-
- Cartographier le bief courant
-
-
-
-
- Aide de PAMHYR
-
-
-
-
- Aide de MAGE
-
-
-
-
- enregistrer_etude_en_cours
-
-
-
-
- fermer_etude_en_cours
-
-
-
-
- quitter_application
-
-
-
-
- lancer_solveur
-
-
-
-
- interrompt_simulation_en_cours
-
-
-
-
- lancer_mailleur_externe
-
-
-
-
- afficher_listings_simulation
-
-
-
-
- Aficher les listings de la simulation courante
-
-
-
-
- Maillage
-
-
-
-
- Cond. Limites
-
-
-
-
- Frottements
-
-
-
-
- Ouvrages
-
+
+ Define initial conditions
+ Définire les conditions initiales
-
+
Édition des Tronçons
-
+
Ouvrir une étude
-
+
Enrégistrer étude en cours (Ctrl+S)
-
+
Fermer étude en cours (Ctrl+F)
-
-
- &Réseau
+
+
+ results
+
+
+
+
+ MainWindowProfile
+
+
+ Profile
+
+
+
+
+ (no name)
+
+
+
+
+ Quittez ?
+
+
+
+
+ MainWindowProfile
+
+
+
+
+ Trier les points par ordre croissant de X
+
+
+
+
+ Trier les points par ordre croissant de Y
+
+
+
+
+ Nom
+
+
+
+
+ Abs en travers (m)
+
+
+
+
+ La cote du fond
+ Z minimale
+
+
+
+
+ La cote maximale
+ Z maximale
+
+
+
+
+ Rive gauche
+
+
+
+
+ Rive droite
+
+
+
+
+ Abscisse en travers (m)
+
+
+
+
+ Cote (m)
-
- &Géométrie
+
+ Suppression les lignes incomplètes
-
- &Exécuter
+
+ Supprimer les lignes des cellules non renseignées ?
-
- Sous-étude Rubar3
+
+ Suppression des noms répétés
-
- Nouvelle étude MAGE
+
+ Etes-vous sûr de vouloir quitter ?
-
- Nouvelle étude RubarBE
+
+ Insérer un point
-
- Importer un jeu de données MAGE
+
+ Supprimer le/les point(s) sélectionnés
-
- Importer un jeu de données RubarBE
+
+ Trier les points par ordre décroissant de X
-
- Éditer le réseau
+
+ Trier les points par ordre décroissant de Y
-
- Éditer la géométrie
+
+ Décaler le point sélectionné vers le haut
-
- Importer une géométrie
+
+ Décaler le point sélectionné vers le bas
-
- Exporter la géométrie
+
+ Exporter (dans un fichier) les points du profil au format tabulé
-
- Visualiser la géométrie maillée
+
+ Copier la sélection au format tabulé
-
- Paramètres numériques du solveur MAGE
+
+ Coller la sélection depuis le presse-papier au format tabulé
-
- Activer/Désactiver l'export des conditions initiales
+
+ Vérifier la validité de la saisie et garder ou pas les modifications apportées
-
- Importer l'état final comme état initial
+
+ Annuler toutes les modifications depuis la dernière validation
-
- Édition des Frottements
+
+ Annuler toutes les modifications et revenir à l'état initial
-
- Édition des Apports Latéraux
+
+ Ligne d'eau :
+ Z : Cote (m)
+ A : Aire mouillée (mu00B2)
+ p : Périmètre mouillé (m)
+ L : Largeur au miroir (m)
-
- Édition des déversements
+
+ 'Maj + Clic' : Ligne d'eau & 'Ctrl + Clic' : Sélectionner des points
-
- Édition des ouvrages en travers
+
+ Abscisse en travers calculée en projétant les points
+sur le plan défini par les deux points nommés extrêmes
+
+
+
+
+ MainWindow_reach
+
+
+ Stricklers
+
+
+
+
+ Kp (m)
+ Pk (m)
+
+
+
+ Ouvrir un fichier
+
+
+
+
+ Fichiers .ST (*.ST)
+
+
+
+
+ Fichiers .M (*.M)
+
+
+
+
+ Tous les fichiers (*)
+
+
+
+
+ Kp :
+
+
+
+
+ Files .ST(*.ST or *.st)
+
+
+
+
+ All files (*)
+
+
+
+
+ Abscisse en travers (m)
+
+
+
+
+ Cote (m)
+
+
+
+
+ Profil suivant
+
+
+
+
+ Jeu de sections du Bief
+
+
+
+
+
+Ordre des sections : Amont --> Aval
+
+
+
+
+ Pk =
+
+
+
+
+ Nouveau profil
+
+
+
+
+ Trier les profils par ordre croissant des Pk
+
+
+
+
+ Name
+ Nom
+
+
+
+ Type
+ Type
+
+
+
+ Alt+Z
+
+
+
+
+ Alt+E
+
+
+
+
+ Alt+R
+
+
+
+
+ Vue globale automatique (Alt+S)
+
+
+
+
+ Vue globale automatique (Alt+D)
+
+
+
+
+ Vue globale automatique (Alt+F)
+
+
+
+
+ X (m)
+
+
+
+
+ Y (m)
+
+
+
+
+ KP (m)
+
+
+
+
+ Discharge (m^3/s)
+ Débit (m³/s)
+
+
+
+ Choisissez un nom de fichier à sauvegarder
-
- Gestion des répertoires de simulation
+
+ Édition des profils sélectionnés
-
- Vitesse(Pk) à t fixé
+
+ Vous avez sélectionné plus de 5 profils.
+Seuls les 5 premiers seront édités.
-
- Vitesse(t) à Pk fixé
+
+ Profil N° :
-
- Charge hydraulique(Pk) à t fixé
+
+ Profil précédent
-
- Charge hydraulique(t) à Pk fixé
+
+ Profil sélectionné
-
- Autres résulats MAGE
+
+ Importer une géométrie
-
- À propos
+
+ Supprimer le profil sélectionné
-
- Lancer le solveur pour réaliser une simulation
+
+ Éditer le profil sélectionné
-
- Lancer le mailleur externe sur la géométrie du bief courant
+
+ Copier le profil sélectionné
-
- Réseau
+
+ Coller le profil en fin de liste (penser à modifier le Pk avant de trier)
-
- Ouvrir l'éditeur de la topologie du réseau
+
+ Dupliquer la section sélectionnée
-
- Géométrie
+
+ Trier les profils par ordre décroissant des Pk
-
- Ouvrir l'éditeur de géométrie
+
+ Changer l'ordre des profils (en décalant le profil sélectionné vers le haut)
-
- Ouvir l'éditeur des Conditions aux Limites & Apports Ponctuels
+
+ Changer l'ordre des profils (en décalant le profil sélectionné vers le bas)
-
- App. Latéraux
+
+ Terminer l'édition
-
- Ouvrir l'éditeur des Apports Latéraux Distribués
+
+ Vue isométrique (Alt+Z)
-
- Déversements
+
+ Vue isométrique (Alt+E)
-
- Ouvrir l'éditeur des Déversements Latéraux
+
+ Vue isométrique (Alt+R)
+
+
+
+
+ Elevation (m)
+ Altitude (m)
+
+
+
+ Network
+
+
+ Add node
+ Ajouter un nœud
+
+
+
+ Delete the node
+ Supprimer un nœud
+
+
+
+ Disable the node
+ Déactiver un nœud
+
+
+
+ Delete the reach
+ Supprimer un bief
+
+
+
+ Disable the reach
+ Déactiver un bief
+
+
+
+ Enable the reach
+ Activer un bief
+
+
+
+ Reverse the reach orientation
+ Inverser l'orientation du bief
+
+
+
+ Results
+
+
+ X (m)
+
+
+
+
+ Y (m)
+
+
+
+
+ Reach name
+
+
+
+
+ Name
+ Nom
+
+
+
+ KP (m)
+
+
+
+
+ SolverParameters
+
+
+ Name
+ Nom
+
+
+
+ Value
+ Valeur
+
+
+
+ Yes
+ Oui
+
+
+
+ No
+ Non
+
+
+
+ Y
+ O
+
+
+
+ N
+ N
+
+
+
+ Initial time (jj:hh:mm:ss)
+ Temps initial (jj:hh:mm:ss)
+
+
+
+ Final time (jj:hh:mm:ss)
+ Temps final (jj:hh:mm:ss)
+
+
+
+ Timestep (second)
+ Pas de temps (en second)
+
+
+
+ Minimum timestep (second)
+ Pas de temps minimal (en second)
+
+
+
+ Time step of writing on .TRA
+ Pas de temps d'écriture dans le fichier .TRA
+
+
+
+ Time step of writing on .BIN
+ Pas de temps d'écriture dans le fichier .BIN
+
+
+
+ Implicitation parameter
+
+
+
+
+ Continuity discretization type (S/L)
+
+
+
+
+ QSJ discretization (A/B)
+
+
+
+
+ Stop criterion iterations (G/A/R)
+
+
+
+
+ Iteration type
+
+
+
+
+ Smoothing coefficient
+
+
+
+
+ Maximun accepted number of CFL
+
+
+
+
+ Minimum water height (meter)
+
+
+
+
+ Maximun number of iterations (< 100)
+
+
+
+
+ Timestep reduction factor
+
+
+
+
+ Reduction precision factor of Z
+
+
+
+
+ Reduction precision factor of Q
+
+
+
+
+ Reduction precision factor of residue
+
+
+
+
+ Number of iteration at maximum precision
+
+
+
+
+ Number of iteration before switch
+
+
+
+
+ Maximum accepted Froude number
+
+
+
+
+ Diffluence node height balance
+
+
+
+
+ Compute reach volume balance (Y/N)
+
+
+
+
+ Maximum reach volume balance
+
+
+
+
+ Minimum reach volume to check
+
+
+
+
+ Solvers
+
+
+ Generic
+ Générique
+
+
+
+ Mage version 8
+ Mage en version 8
+
+
+
+ Toolbar
+
+
+ Vue originale
+
+
+
+
+ Panoramique des axes avec la souris gauche, zoom avec la droite
+
+
+
+
+ Zoom
+
+
+
+
+ Vue globale automatique (Shift+X)
+
+
+
+
+ Enregistrer la figure
-
- Tronçons
+
+ Retour à la vue précédente
-
- Ouvrir l'éditeur des tronçons pour les frottements et Apports Latéraux
+
+ Passer à la vue suivante
-
- Ouvrir l'éditeur des frottements au fond
-
-
-
-
- Ouvrir l'éditeur des ouvrages (seuils, vannes, etc.), singularités et pompes
+
+ Vue isométrique (Shift+W)
diff --git a/src/pamhyr.py b/src/pamhyr.py
index 8a832e18..55172c78 100755
--- a/src/pamhyr.py
+++ b/src/pamhyr.py
@@ -1,4 +1,21 @@
#!/usr/bin/env python3
+
+# pamhyr.py -- Pamhyr entrypoint
+# 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 .
+
# -*- coding: utf-8 -*-
import sys, os
@@ -10,7 +27,8 @@ from PyQt5.QtWidgets import QApplication
from config import Config
from tools import (
- reset_timers, display_timers, timer
+ reset_timers, display_timers, timer,
+ logger_color_blue, logger_color_red, logger_color_green, logger_color_reset
)
from View.MainWindow import ApplicationWindow
@@ -18,17 +36,59 @@ from Model.Study import Study
logging.basicConfig(
level=logging.DEBUG,
- format='[PAMHYR][%(levelname)s] %(message)s'
+ format=(f'[{logger_color_blue()}PAMHYR{logger_color_reset()}]' +
+ f'[{logger_color_green()}%(levelname)s{logger_color_reset()}]' +
+ ' %(message)s')
)
logger = logging.getLogger()
logger.setLevel(logging.INFO)
+try:
+ log = os.path.join(
+ os.path.dirname(Config.filename()), "log.txt"
+ )
+ logfile = open(log, "w+")
+ handler = logging.StreamHandler(logfile)
+ formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s')
+ handler.setFormatter(formatter)
+ handler.setLevel(logging.DEBUG)
+ logger.addHandler(handler)
+except:
+ logger.error("Failed to create logfile...")
+
+def license():
+ blue = lambda s: logger.info(f"{logger_color_blue()}{s}{logger_color_reset()}")
+
+ blue("""`7MM\"""Mq. db `7MMM. ,MMF'`7MMF' `7MMF'`YMM' `MM'`7MM\"""Mq.""")
+ blue(""" MM `MM. ;MM: MMMb dPMM MM MM VMA ,V MM `MM.""")
+ blue(""" MM ,M9 ,V^MM. M YM ,M MM MM MM VMA ,V MM ,M9 pd*"*b.""")
+ blue(""" MMmmdM9 ,M `MM M Mb M' MM MMmmmmmmMM VMMP MMmmdM9 (O) j8""")
+ blue(""" MM AbmmmqMA M YM.P' MM MM MM MM MM YM. ,;j9""")
+ blue(""" MM A' VML M `YM' MM MM MM MM MM `Mb. ,-='""")
+ blue(""".JMML. .AMA. .AMMA..JML. `' .JMML..JMML. .JMML. .JMML. .JMML. .JMM. Ammmmmmm""")
+
+ with open(os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__),
+ "VERSION"
+ )
+ ), "r") as f:
+ version = f.readline().strip()
+ logger.info(f"version: {logger_color_green()}{version}{logger_color_reset()}")
+
+ logger.info("license: pamhyr Copyright (C) 2023 INRAE")
+ logger.info("license: This program comes with ABSOLUTELY NO WARRANTY.")
+ logger.info("license: This is free software, and you are welcome to redistribute it")
+ logger.info("license: under certain conditions.")
+
def main():
conf = Config.load()
app = QApplication(sys.argv)
translator = QTranslator()
+ license()
+
lang_file = ""
if conf.lang == "":
# System language
diff --git a/src/tools.py b/src/tools.py
index c71c91d1..c345fb7f 100644
--- a/src/tools.py
+++ b/src/tools.py
@@ -1,3 +1,19 @@
+# tools.py -- Pamhyr tools function collection
+# 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 .
+
# -*- coding: utf-8 -*-
import os
@@ -23,6 +39,30 @@ from functools import (
logger = logging.getLogger()
+def logger_color_blue():
+ posix = os.name == "posix"
+ if posix:
+ return f"{Style.BRIGHT}{Fore.BLUE}"
+ return ""
+
+def logger_color_red():
+ posix = os.name == "posix"
+ if posix:
+ return f"{Style.BRIGHT}{Fore.RED}"
+ return ""
+
+def logger_color_green():
+ posix = os.name == "posix"
+ if posix:
+ return f"{Style.BRIGHT}{Fore.GREEN}"
+ return ""
+
+def logger_color_reset():
+ posix = os.name == "posix"
+ if posix:
+ return f"{Style.RESET_ALL}"
+ return ""
+
##########
# TIMERS #
##########
diff --git a/tools/license.el b/tools/license.el
new file mode 100644
index 00000000..a35e4308
--- /dev/null
+++ b/tools/license.el
@@ -0,0 +1,41 @@
+;; license.el -- 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 .
+
+;; -*- coding: utf-8 -*-
+
+(defun pamhyr-current-filename ()
+ (car (last (file-name-split (buffer-file-name)))))
+
+(defun pamhyr-insert-license ()
+ (interactive)
+ (let ((filename (pamhyr-current-filename)))
+ (insert (format
+ "# %s -- 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 .
+" filename))))
diff --git a/tools/ssh-run.sh b/tools/ssh-run.sh
index 9c59bb9f..a7ca1af7 100755
--- a/tools/ssh-run.sh
+++ b/tools/ssh-run.sh
@@ -1,10 +1,14 @@
#! /bin/sh
-# > ssh-run.sh SERVER DESTDIR SOLVER INPUT
+# > ssh-run.sh SERVER DESTDIR SOLVER ARGS INPUT
# First argument is the server name/addr
# The second argument is the destination directory to copy input data
# The third argument is the solver path
-# The fourth argument is the input name
+# The fourth argument is an solver args separate by ',' or input name
+# The sixth argument is the input name or nothing
-ssh $1 "cd $2; $3 $4"
+args=$(echo $4 | tr ',' ' ')
+
+echo "ssh $1 \"cd $2; $3 $args $5\""
+ssh $1 "cd $2; $3 $args $5"