diff --git a/src/Model/D90AdisTS/D90AdisTS.py b/src/Model/D90AdisTS/D90AdisTS.py new file mode 100644 index 0000000000000000000000000000000000000000..e4953cd85b9f4ac5139ef82302dc394fb3177936 --- /dev/null +++ b/src/Model/D90AdisTS/D90AdisTS.py @@ -0,0 +1,201 @@ +# D90AdisTS.py -- Pamhyr +# Copyright (C) 2023-2024 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +import logging +from functools import reduce + +from tools import trace, timer, old_pamhyr_date_to_timestamp + +from Model.Tools.PamhyrDB import SQLSubModel +from Model.Except import NotImplementedMethodeError + +from Model.D90AdisTS.D90AdisTSSpec import D90AdisTSSpec + +logger = logging.getLogger() + +class D90AdisTS(SQLSubModel): + _sub_classes = [ + D90AdisTSSpec, + ] + _id_cnt = 0 + + def __init__(self, id: int = -1, name: str = "default", + status=None): + super(D90AdisTS, self).__init__() + + self._status = status + + if id == -1: + self.id = D90AdisTS._id_cnt + else: + self.id = id + + self._name = name + self._d90 = None + self._enabled = True + self._data = [] + + D90AdisTS._id_cnt = max( + D90AdisTS._id_cnt + 1, + self.id + ) + + @classmethod + def _db_create(cls, execute): + execute(""" + CREATE TABLE d90_adists( + id INTEGER NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + d90 REAL NOT NULL, + enabled BOOLEAN NOT NULL, + ) + """) + + return cls._create_submodel(execute) + + @classmethod + def _db_update(cls, execute, version): + major, minor, release = version.strip().split(".") + if major == minor == "0": + if int(release) < 6: + cls._db_create(execute) + + return True + + @classmethod + def _db_load(cls, execute, data=None): + new = [] + + table = execute( + "SELECT id, name, d90, enabled " + + "FROM d90_adists" + ) + + if table is not None: + for row in table: + d90_id = row[0] + name = row[1] + d90 = row[2] + enabled = (row[3] == 1) + + D90 = cls( + id=d90_id, + name=name, + status=data['status'] + ) + + D90.d90 = d90 + D90.enabled = enabled + + data['d90_default_id'] = d90_id + D90._data = D90AdisTSSpec._db_load(execute, data) + + new.append(D90) + + return new + + def _db_save(self, execute, data=None): + execute(f"DELETE FROM d90_adists WHERE id = {self.id}") + + d90 = -1. + if self.d90 is not None: + d90 = self.d90 + + sql = ( + "INSERT INTO " + + "d90_adists(" + + "id, name, d90, enabled" + + ") " + + "VALUES (" + + f"{self.id}, '{self._db_format(self._name)}', " + + f"{d90}, {self._enabled}" + + ")" + ) + + execute(sql) + + data['d90_default_id'] = self.id + execute( + "DELETE FROM d90_spec " + + f"WHERE d90_default = {self.id}" + ) + + for d90_spec in self._data: + d90_spec._db_save(execute, data) + + return True + + def __len__(self): + return len(self._data) + + @property + def name(self): + return self._name + + @name.setter + def name(self, name): + self._name = name + self._status.modified() + + @property + def d90(self): + return self._d90 + + @d90.setter + def d90(self, d90): + self._d90 = d90 + self._status.modified() + + @property + def enabled(self): + return self._enabled + + @enabled.setter + def enabled(self, enabled): + self._enabled = enabled + self._status.modified() + + def new(self, index): + n = D90AdisTSSpec(status=self._status) + self._data.insert(index, n) + self._status.modified() + return n + + def delete(self, data): + self._data = list( + filter( + lambda x: x not in data, + self._data + ) + ) + self._status.modified() + + def delete_i(self, indexes): + for ind in indexes: + del self._data[ind] + self._status.modified() + + def insert(self, index, data): + self._data.insert(index, data) + self._status.modified() + + + + + + diff --git a/src/Model/D90AdisTS/D90AdisTSList.py b/src/Model/D90AdisTS/D90AdisTSList.py new file mode 100644 index 0000000000000000000000000000000000000000..a9c8e7f5e179be6e94811828dd9095b73224f41e --- /dev/null +++ b/src/Model/D90AdisTS/D90AdisTSList.py @@ -0,0 +1,62 @@ +# D90AdisTSList.py -- Pamhyr +# Copyright (C) 2023-2024 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +from copy import copy +from tools import trace, timer + +from Model.Tools.PamhyrList import PamhyrModelList +from Model.D90AdisTS.D90AdisTS import D90AdisTS + +class D90AdisTSList(PamhyrModelList): + _sub_classes = [ + D90AdisTS, + ] + + @classmethod + def _db_load(cls, execute, data=None): + new = cls(status=data['status']) + + if data is None: + data = {} + + new._lst = D90AdisTS._db_load( + execute, data + ) + + return new + + def _db_save(self, execute, data=None): + execute("DELETE FROM d90_adists") + + if data is None: + data = {} + + for d90 in self._lst: + d90._db_save(execute, data=data) + + return True + + def new(self, index): + n = D90AdisTS(status=self._status) + self._lst.insert(index, n) + self._status.modified() + return n + + + + diff --git a/src/Model/D90AdisTS/D90AdisTSSpec.py b/src/Model/D90AdisTS/D90AdisTSSpec.py new file mode 100644 index 0000000000000000000000000000000000000000..d1ab2c8d65ccd80cb793394ae5cd972d8a634d75 --- /dev/null +++ b/src/Model/D90AdisTS/D90AdisTSSpec.py @@ -0,0 +1,200 @@ +# D90AdisTSSpec.py -- Pamhyr +# Copyright (C) 2023-2024 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +import logging + +from tools import trace, timer + +from Model.Tools.PamhyrDB import SQLSubModel +from Model.Except import NotImplementedMethodeError + +logger = logging.getLogger() + +class D90AdisTSSpec(SQLSubModel): + _sub_classes = [ + ] + _id_cnt = 0 + + def __init__(self, id: int = -1, name: str = "", + status=None): + super(D90AdisTSSpec, self).__init__() + + self._status = status + + if id == -1: + self.id = D90AdisTSSpec._id_cnt + else: + self.id = id + + self._name_section = name + self._reach = None + self._start_kp = None + self._end_kp = None + self._d90 = None + self._enabled = True + + D90AdisTSSpec._id_cnt = max(D90AdisTSSpec._id_cnt + 1, self.id) + + @classmethod + def _db_create(cls, execute): + execute(""" + CREATE TABLE d90_spec( + id INTEGER NOT NULL PRIMARY KEY, + d90_default INTEGER NOT NULL, + name TEXT NOT NULL, + reach INTEGER NOT NULL, + start_kp REAL NOT NULL, + end_kp REAL NOT NULL, + d90 REAL NOT NULL, + enabled BOOLEAN NOT NULL, + FOREIGN KEY(d90_default) REFERENCES d90_adists(id), + FOREIGN KEY(reach) REFERENCES river_reach(id) + ) + """) + + return cls._create_submodel(execute) + + @classmethod + def _db_update(cls, execute, version): + major, minor, release = version.strip().split(".") + if major == minor == "0": + if int(release) < 6: + cls._db_create(execute) + + return True + + @classmethod + def _db_load(cls, execute, data=None): + new = [] + + table = execute( + "SELECT id, d90_default, name, reach, start_kp, end_kp, " + + "d90, enabled " + + "FROM d90_spec " + + f"WHERE d90_default = {data['d90_default_id']} " + ) + + for row in table: + id = row[0] + name = row[2] + reach = row[3] + start_kp = row[4] + end_kp = row[5] + d90 = row[6] + enabled = (row[7] == 1) + + new_spec = cls( + id=id, + name=name, + status=data['status'] + ) + + new_spec.reach = reach + new_spec.start_kp = start_kp + new_spec.end_kp = end_kp + new_spec.d90 = d90 + new_spec.enabled = enabled + + new.append(new_spec) + + return new + + def _db_save(self, execute, data=None): + d90_default = data['d90_default_id'] + + sql = ( + "INSERT INTO " + + "d90_spec(id, d90_default, name, reach, " + + "start_kp, end_kp, d90, enabled) " + + "VALUES (" + + f"{self.id}, " + + f"{d90_default}, " + + f"'{self._db_format(self._name_section)}', " + + f"{self._reach}, " + + f"{self._start_kp}, " + + f"{self._end_kp}, " + + f"{self._d90}, " + + f"{self._enabled}" + + ")" + ) + execute(sql) + + return True + + @property + def name(self): + return self._name_section + + @name.setter + def name(self, name): + self._name_section = name + self._status.modified() + + @property + def reach(self): + return self._reach + + @reach.setter + def reach(self, reach): + self._reach = reach + self._status.modified() + + @property + def start_kp(self): + return self._start_kp + + @start_kp.setter + def start_kp(self, start_kp): + self._start_kp = start_kp + self._status.modified() + + @property + def end_kp(self): + return self._end_kp + + @end_kp.setter + def end_kp(self, end_kp): + self._end_kp = end_kp + self._status.modified() + + @property + def d90(self): + return self._d90 + + @d90.setter + def d90(self, concentration): + self._d90 = d90 + self._status.modified() + + @property + def enabled(self): + return self._enabled + + @enabled.setter + def enabled(self, enabled): + self._enabled = enabled + self._status.modified() + + + + + + + + + diff --git a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSList.py b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSList.py index e45aba048da24c1e082d114572a5a148532c68fc..8ff24cf2d8b34d92c48052b21afef71f3b5b9af9 100644 --- a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSList.py +++ b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSList.py @@ -41,7 +41,7 @@ class InitialConditionsAdisTSList(PamhyrModelList): return new def _db_save(self, execute, data=None): - execute("DELETE FROM initial_conditions") + execute("DELETE FROM initial_conditions_adists") if data is None: data = {} diff --git a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py index 45286f635c603bb8ced715ebb93ff9d6aeb9e4b8..81fad351a94885a19ddcd69a5949ed0924b10be7 100644 --- a/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py +++ b/src/Model/InitialConditionsAdisTS/InitialConditionsAdisTSSpec.py @@ -70,7 +70,7 @@ class ICAdisTSSpec(SQLSubModel): ed REAL NOT NULL, rate REAL NOT NULL, enabled BOOLEAN NOT NULL, - FOREIGN KEY(ic_default) REFERENCES initial_conditions(id), + FOREIGN KEY(ic_default) REFERENCES initial_conditions_adists(id), FOREIGN KEY(reach) REFERENCES river_reach(id) ) """) diff --git a/src/Model/River.py b/src/Model/River.py index 5eabb932144a3775e72354e21944a4d07cae3fbb..4cc2c5e44b1f3b6001af16943e3f8100e3e79d14 100644 --- a/src/Model/River.py +++ b/src/Model/River.py @@ -50,6 +50,7 @@ from Model.Pollutants.PollutantsList import PollutantsList from Model.InitialConditionsAdisTS.InitialConditionsAdisTSList import InitialConditionsAdisTSList from Model.BoundaryConditionsAdisTS.BoundaryConditionsAdisTSList import BoundaryConditionsAdisTSList from Model.LateralContributionsAdisTS.LateralContributionsAdisTSList import LateralContributionsAdisTSList +from Model.D90AdisTS.D90AdisTSList import D90AdisTSList class RiverNode(Node, SQLSubModel): @@ -239,6 +240,7 @@ class River(Graph, SQLSubModel): InitialConditionsAdisTSList, BoundaryConditionsAdisTSList, LateralContributionsAdisTSList, + D90AdisTSList, ] def __init__(self, status=None): @@ -267,6 +269,7 @@ class River(Graph, SQLSubModel): self._InitialConditionsAdisTS = InitialConditionsAdisTSList(status=self._status) self._BoundaryConditionsAdisTS = BoundaryConditionsAdisTSList(status=self._status) self._LateralContributionsAdisTS = LateralContributionsAdisTSList(status=self._status) + self._D90AdisTS = D90AdisTSList(status=self._status) @classmethod def _db_create(cls, execute): @@ -353,6 +356,8 @@ class River(Graph, SQLSubModel): new._LateralContributionsAdisTS = LateralContributionsAdisTSList._db_load(execute, data) + new._D90AdisTS = D90AdisTSList._db_load(execute, data) + return new def _db_save(self, execute, data=None): @@ -377,6 +382,7 @@ class River(Graph, SQLSubModel): objs.append(self._InitialConditionsAdisTS) objs.append(self._BoundaryConditionsAdisTS) objs.append(self._LateralContributionsAdisTS) + objs.append(self._D90AdisTS) self._save_submodel(execute, objs, data) return True @@ -520,6 +526,10 @@ Last export at: @date.""" def lateral_contributions_adists(self): return self._LateralContributionsAdisTS + @property + def d90_adists(self): + return self._D90AdisTS + def get_params(self, solver): if solver in self._parameters: return self._parameters[solver] diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index f94c4d0700fe86a13f7140662af3946f817a2d50..12d9af6798387b768f78f877e3bc8a282b4327d0 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -122,6 +122,7 @@ define_model_action = [ "action_menu_boundary_conditions_sediment", "action_menu_rep_additional_lines", "action_menu_output_kp", "action_menu_run_adists", "action_menu_pollutants", + "action_menu_d90", ] action = ( @@ -235,6 +236,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): """ actions = { # Menu action + "action_menu_d90": self.open_d90, "action_menu_pollutants": self.open_pollutants, "action_menu_run_adists":self.run_solver_adists, "action_menu_output_kp": self.open_output_kp_adists, @@ -866,6 +868,19 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): # SUB WINDOWS # ############### + def open_d90(self): + if self.sub_window_exists( + PollutantsWindow, + data=[self._study, None] + ): + return + + Pollutants = PollutantsWindow( + study=self._study, + parent=self + ) + Pollutants.show() + def open_pollutants(self): if self.sub_window_exists( PollutantsWindow, diff --git a/src/View/ui/MainWindow.ui b/src/View/ui/MainWindow.ui index 20ec62838e96adfa73da8ff1324b78a08c3d4b50..842e220a6ea27679719f9ddcbe2890e64f8db161 100644 --- a/src/View/ui/MainWindow.ui +++ b/src/View/ui/MainWindow.ui @@ -219,6 +219,7 @@ </property> <addaction name="action_menu_output_kp"/> <addaction name="action_menu_pollutants"/> + <addaction name="action_menu_d90"/> </widget> <addaction name="menu_File"/> <addaction name="menu_network"/> @@ -761,6 +762,11 @@ <string>Pollutants</string> </property> </action> + <action name="action_menu_d90"> + <property name="text"> + <string>D90</string> + </property> + </action> </widget> <resources/> <connections> diff --git a/tests_cases/Enlargement/Enlargement.pamhyr b/tests_cases/Enlargement/Enlargement.pamhyr index 7cbb7e4ffefc175307429c2d8af87987164093b8..9aa6c32eaddadc52309022f8de7ef26e5bb9a78a 100644 Binary files a/tests_cases/Enlargement/Enlargement.pamhyr and b/tests_cases/Enlargement/Enlargement.pamhyr differ