diff --git a/src/Model/D90AdisTS/D90AdisTS.py b/src/Model/D90AdisTS/D90AdisTS.py
new file mode 100644
index 00000000..e4953cd8
--- /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 .
+
+# -*- 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 00000000..a9c8e7f5
--- /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 .
+
+# -*- 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 00000000..d1ab2c8d
--- /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 .
+
+# -*- 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 e45aba04..8ff24cf2 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 45286f63..81fad351 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 5eabb932..4cc2c5e4 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 f94c4d07..12d9af67 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 20ec6283..842e220a 100644
--- a/src/View/ui/MainWindow.ui
+++ b/src/View/ui/MainWindow.ui
@@ -219,6 +219,7 @@
+
@@ -761,6 +762,11 @@
Pollutants
+
+
+ D90
+
+
diff --git a/tests_cases/Enlargement/Enlargement.pamhyr b/tests_cases/Enlargement/Enlargement.pamhyr
index 7cbb7e4f..9aa6c32e 100644
Binary files a/tests_cases/Enlargement/Enlargement.pamhyr and b/tests_cases/Enlargement/Enlargement.pamhyr differ