diff --git a/src/Model/River.py b/src/Model/River.py
index 7eeafa8d..70b625d2 100644
--- a/src/Model/River.py
+++ b/src/Model/River.py
@@ -66,8 +66,8 @@ from Model.InitialConditionsTemperature.InitialConditionsTemperatureList \
from Model.BoundaryConditionsTemperature.BoundaryConditionsTemperatureList \
import BoundaryConditionsTemperatureList
-from Model.WeatherParameters.AirTemperatureList \
- import AirTemperatureList
+from Model.WeatherParameters.WeatherParametersList \
+ import WeatherParametersList
from Model.GeoTIFF.GeoTIFFList import GeoTIFFList
from Model.Results.Results import Results
@@ -487,7 +487,7 @@ class River(Graph):
DIFAdisTSList,
InitialConditionsTemperatureList,
BoundaryConditionsTemperatureList,
- AirTemperatureList,
+ WeatherParametersList,
GeoTIFFList,
Results
]
@@ -531,7 +531,7 @@ class River(Graph):
self._BoundaryConditionsTemperature = (
BoundaryConditionsTemperatureList(status=self._status)
)
- self._AirTemperature = (AirTemperatureList(status=self._status))
+ self._WeatherParameters = (WeatherParametersList(status=self._status))
self._geotiff = GeoTIFFList(status=self._status)
@@ -653,7 +653,7 @@ class River(Graph):
new._BoundaryConditionsTemperature = \
BoundaryConditionsTemperatureList._db_load(execute, data)
- new._AirTemperature = AirTemperatureList._db_load(execute, data)
+ new._WeatherParameters = WeatherParametersList._db_load(execute, data)
new._geotiff = GeoTIFFList._db_load(execute, data)
@@ -692,7 +692,7 @@ class River(Graph):
objs.append(self._InitialConditionsTemperature)
objs.append(self._BoundaryConditionsTemperature)
- objs.append(self._AirTemperature)
+ objs.append(self._WeatherParameters)
objs.append(self._geotiff)
@@ -774,7 +774,7 @@ class River(Graph):
self._D90AdisTS, self._DIFAdisTS,
self._InitialConditionsTemperature,
self._BoundaryConditionsTemperature,
- self._AirTemperature,
+ self._WeatherParameters,
self._geotiff,
]
@@ -917,8 +917,8 @@ Last export at: @date."""
return self._BoundaryConditionsTemperature
@property
- def air_temperature(self):
- return self._AirTemperature
+ def weather_parameters(self):
+ return self._WeatherParameters
def get_params(self, solver):
if solver in self._parameters:
diff --git a/src/Model/WeatherParameters/AirTemperature.py b/src/Model/WeatherParameters/AirTemperature.py
deleted file mode 100644
index 212ea52c..00000000
--- a/src/Model/WeatherParameters/AirTemperature.py
+++ /dev/null
@@ -1,406 +0,0 @@
-# AirTemperature.py -- Pamhyr
-# Copyright (C) 2023-2025 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,
- date_iso_to_timestamp,
- date_dmy_to_timestamp,
-)
-
-from Model.Tools.PamhyrDB import SQLSubModel
-from Model.Except import NotImplementedMethodeError
-from Model.Scenario import Scenario
-
-logger = logging.getLogger()
-
-
-class Data(SQLSubModel):
- _sub_classes = []
-
- def __init__(self,
- data0, data1,
- id: int = -1,
- types=[float, float],
- status=None,
- owner_scenario=-1):
- super(Data, self).__init__(
- id=id, status=status,
- owner_scenario=owner_scenario
- )
-
- self._types = types
- self._data = [data0, data1]
-
- @classmethod
- def _db_create(cls, execute, ext=""):
- execute(f"""
- CREATE TABLE air_temperature_data{ext}(
- {cls.create_db_add_pamhyr_id()},
- deleted BOOLEAN NOT NULL DEFAULT FALSE,
- data0 TEXT NOT NULL,
- data1 TEXT NOT NULL,
- {Scenario.create_db_add_scenario()},
- {Scenario.create_db_add_scenario_fk()},
- )
- """)
-
- @classmethod
- def _db_update(cls, execute, version, data=None):
- major, minor, release = version.strip().split(".")
- created = False
-
- if major == "0" and int(minor) < 2:
- if cls.is_table_exists(
- execute, "air_temperature_data"):
- cls._db_update_to_0_2_0(execute, data)
- else:
- cls._db_create(execute)
-
- return True
-
- @classmethod
- def _db_load(cls, execute, data=None):
- new = []
- status = data['status']
- scenario = data["scenario"]
- loaded = data['loaded_pid']
-
- if scenario is None:
- return new
-
- table = execute(
- "SELECT pamhyr_id, deleted, data0, data1, scenario " +
- "FROM air_temperature_data " +
- f"WHERE scenario = {scenario.id} " +
- f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
- )
-
- if table is not None:
- for row in table:
- it = iter(row)
-
- pid = next(it)
- deleted = (next(it) == 1)
- data0 = next(it)
- data1 = next(it)
- owner_scenario = next(it)
-
- lc = cls(
- data0, data1,
- id=pid, status=status,
- owner_scenario=owner_scenario
- )
- if deleted:
- lc.set_as_deleted()
-
- loaded.add(pid)
- new.append(lc)
-
- data["scenario"] = scenario.parent
- new += cls._db_load(execute, data)
- data["scenario"] = scenario
-
- return new
-
- def _db_save(self, execute, data=None):
- if not self.must_be_saved():
- return True
-
- execute(
- "INSERT INTO " +
- "air_temperature_data(pamhyr_id, deleted," +
- "data0, data1, scenario) " +
- "VALUES (" +
- f"{self.id}, {self._db_format(self.is_deleted())}, " +
- f"{self._data[0]}, {self._data[1]}, " +
- f"{self._status.scenario_id}" +
- ")"
- )
-
- return True
-
- def __getitem__(self, key):
- return self._types[key](self._data[key])
-
- def __setitem__(self, key, value):
- self._data[key] = self._types[key](value)
-
-
-class AirTemperature(SQLSubModel):
- _sub_classes = [Data]
-
- def __init__(self, id: int = -1, int = -1,
- name: str = "", status=None,
- owner_scenario=-1):
- super(AirTemperature, self).__init__(
- id=id, status=status,
- owner_scenario=owner_scenario
- )
-
- self._status = status
-
- self._reach = None
- self._begin_rk = 0.0
- self._end_rk = 0.0
- self._data = []
- self._header = ["time", "rate"]
- self._types = [self.time_convert, float]
-
- @classmethod
- def _db_create(cls, execute, ext=""):
- execute(f"""
- CREATE TABLE air_temperature{ext}(
- {cls.create_db_add_pamhyr_id()},
- deleted BOOLEAN NOT NULL DEFAULT FALSE,
- reach INTEGER NOT NULL,
- begin_rk REAL NOT NULL,
- end_rk REAL NOT NULL,
- {Scenario.create_db_add_scenario()},
- {Scenario.create_db_add_scenario_fk()},
- FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id)
- )
- """)
-
- if ext != "":
- return True
-
- return cls._create_submodel(execute)
-
- @classmethod
- def _db_update(cls, execute, version, data=None):
- major, minor, release = version.strip().split(".")
- created = False
-
- if major == "0" and int(minor) < 2:
- if cls.is_table_exists(execute, "air_temperature"):
- cls._db_update_to_0_2_0(execute, data)
- else:
- cls._db_create(execute)
- created = True
-
- if not created:
- return cls._update_submodel(execute, version, data)
-
- return True
-
- @classmethod
- def _db_load(cls, execute, data=None):
- new = []
- status = data['status']
- scenario = data["scenario"]
- loaded = data['loaded_pid']
-
- if scenario is None:
- return new
-
- table = execute(
- "SELECT pamhyr_id, deleted, reach, " +
- "begin_rk, end_rk, scenario " +
- "FROM air_temperature " +
- f"WHERE scenario = {scenario.id} " +
- f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
- )
-
- if table is not None:
- for row in table:
- it = iter(row)
-
- pid = next(it)
- deleted = (next(it) == 1)
- reach = next(it)
- brk = next(it)
- erk = next(it)
- owner_scenario = next(it)
-
- data["scenario"] = scenario.parent
- new += cls._db_load(execute, data)
- data["scenario"] = scenario
-
- return new
-
- def _db_save(self, execute, data=None):
- if not self.must_be_saved():
- return True
-
- execute(
- f"DELETE FROM air_temperature " +
- f"WHERE pamhyr_id = {self.id} " +
- f"AND scenario = {self._status.scenario_id}"
- )
- execute(
- f"DELETE FROM air_temperature_data " +
- f"WHERE scenario = {self._status.scenario_id}"
- )
-
- execute(
- "INSERT INTO " +
- "air_temperature(pamhyr_id, deleted, " +
- "reach, begin_rk, end_rk, scenario) " +
- "VALUES (" +
- f"{self.id}, {self._db_format(self.is_deleted())}, {self.reach}, " +
- f"{self._begin_rk}, {self._end_rk}, " +
- f"{self._status.scenario_id}" +
- ")"
- )
- ind = 0
- for d in self._data:
- data["ind"] = ind
-
- d._db_save(execute, data)
-
- ind += 1
-
- return True
-
- def _data_traversal(self,
- predicate=lambda obj, data: True,
- modifier=lambda obj, data: None,
- data={}):
- if predicate(self, data):
- modifier(self, data)
-
- for d in self._data:
- d._data_traversal(predicate, modifier, data)
-
- def __len__(self):
- return len(
- list(
- filter(
- lambda el: el is not None and not el.is_deleted(),
- self._data
- )
- )
- )
-
- @classmethod
- def time_convert(cls, data):
- if type(data) is str:
- if data.count("-") == 2:
- return date_iso_to_timestamp(data)
- if data.count("/") == 2:
- return date_dmy_to_timestamp(data)
- if data.count(":") == 3:
- return old_pamhyr_date_to_timestamp(data)
- if data.count(":") == 2:
- return old_pamhyr_date_to_timestamp("00:" + data)
- if data.count(".") == 1:
- return round(float(data))
-
- return int(data)
-
- @property
- def reach(self):
- return self._reach
-
- @reach.setter
- def reach(self, reach):
- self._reach = reach
- self.modified()
-
- @property
- def header(self):
- return self._header.copy()
-
- @header.setter
- def header(self, header):
- self._header = header
- self.modified()
-
- @property
- def data(self):
- return list(
- filter(
- lambda el: el is not None and not el.is_deleted(),
- self._data
- )
- )
-
- @property
- def begin_rk(self):
- return self._begin_rk
-
- @begin_rk.setter
- def begin_rk(self, begin_rk):
- self._begin_rk = begin_rk
- self.modified()
-
- @property
- def end_rk(self):
- return self._end_rk
-
- @end_rk.setter
- def end_rk(self, end_rk):
- self._end_rk = end_rk
- self.modified()
-
- @property
- def _default_0(self):
- return self._types[0](0)
-
- @property
- def _default_1(self):
- return self._types[1](0.0)
-
- def add(self, index: int):
- value = Data(self._default_0, self._default_1, status=self._status)
- self._data.insert(index, value)
- self.modified()
- return value
-
- def insert(self, index: int, data: Data):
- self._data.insert(index, data)
- self.modified()
-
- def delete_i(self, indexes):
- self._data = list(
- map(
- lambda e: e[1].set_as_deleted(),
- filter(
- lambda e: e[0] not in indexes,
- enumerate(self.data)
- )
- )
- )
- self.modified()
-
- def index(self, bc):
- self._data.index(bc)
-
- def get_i(self, index: int):
- return self._data[index]
-
- def get_range(self, _range):
- lst = []
- for r in _range:
- lst.append(r)
- return lst
-
- def _set_i_c_v(self, index: int, column: int, value):
- v = self._data[index]
- v[column] = self._types[column](value)
- self._data[index] = v
- self.modified()
-
- def set_i_0(self, index: int, value):
- self._set_i_c_v(index, 0, value)
-
- def set_i_1(self, index: int, value):
- self._set_i_c_v(index, 1, value)
diff --git a/src/Model/WeatherParameters/AirTemperatureList.py b/src/Model/WeatherParameters/AirTemperatureList.py
deleted file mode 100644
index 3875125d..00000000
--- a/src/Model/WeatherParameters/AirTemperatureList.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# AirTemperatureList.py -- Pamhyr
-# Copyright (C) 2023-2025 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.PamhyrListExt import PamhyrModelList
-from Model.Except import NotImplementedMethodeError
-
-from Model.WeatherParameters.AirTemperature \
- import AirTemperature
-
-
-class AirTemperatureList(PamhyrModelList):
- _sub_classes = [
- AirTemperature,
- ]
-
- @classmethod
- def _db_load(cls, execute, data=None):
- new = cls(status=data['status'])
-
- if data is None:
- data = {}
-
- new._lst = AirTemperature._db_load(
- execute, data
- )
-
- return new
-
- def _db_save(self, execute, data=None):
- execute(
- "DELETE FROM air_temperature " +
- f"WHERE scenario = {self._status.scenario_id}"
- )
- execute(
- "DELETE FROM air_temperature_data " +
- f"WHERE scenario = {self._status.scenario_id}"
- )
-
- if data is None:
- data = {}
-
- for lc in self._lst:
- lc._db_save(execute, data=data)
-
- return True
-
- def new(self, index, pollutant):
- n = AirTemperature(pollutant=pollutant, status=self._status)
- self._lst.insert(index, n)
- self._status.modified()
- return n
-
- @property
- def Air_Temperature_List(self):
- return self.lst
diff --git a/src/Model/WeatherParameters/WeatherParameters.py b/src/Model/WeatherParameters/WeatherParameters.py
new file mode 100644
index 00000000..8fac0025
--- /dev/null
+++ b/src/Model/WeatherParameters/WeatherParameters.py
@@ -0,0 +1,615 @@
+# WeatherParameters.py -- Pamhyr
+# Copyright (C) 2023-2025 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,
+ date_iso_to_timestamp,
+ date_dmy_to_timestamp,
+)
+
+from Model.Tools.PamhyrDB import SQLSubModel
+from Model.Except import NotImplementedMethodeError
+from Model.Scenario import Scenario
+
+logger = logging.getLogger()
+
+
+class Data(SQLSubModel):
+ _sub_classes = []
+
+ def __init__(self,
+ data0, data1,
+ id: int = -1,
+ types=[float, float],
+ status=None,
+ owner_scenario=-1):
+ super(Data, self).__init__(
+ id=id, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._types = types
+ self._data = [data0, data1]
+
+ @classmethod
+ def _db_create(cls, execute, ext=""):
+ execute(f"""
+ CREATE TABLE weather_parameters_data{ext} (
+ {cls.create_db_add_pamhyr_id()},
+ deleted BOOLEAN NOT NULL DEFAULT FALSE,
+ ind INTEGER NOT NULL,
+ data0 TEXT NOT NULL,
+ data1 TEXT NOT NULL,
+ wp INTEGER,
+ {Scenario.create_db_add_scenario()},
+ {Scenario.create_db_add_scenario_fk()},
+ FOREIGN KEY(wp) REFERENCES weather_parameters(pamhyr_id),
+ PRIMARY KEY(pamhyr_id, scenario)
+ )
+ """)
+
+ return cls._create_submodel(execute)
+
+ @classmethod
+ def _db_update(cls, execute, version, data=None):
+ major, minor, release = version.strip().split(".")
+
+ if major == "0" and (int(minor) < 2 or
+ (int(minor) == 2 and int(release) < 7)):
+ if not cls.is_table_exists(execute, "air_temperature_data"):
+ cls._db_create(execute)
+
+ return cls._update_submodel(execute, version, data)
+
+ @classmethod
+ def _db_load(cls, execute, data=None):
+ new = []
+ wp = data["wp"]
+ status = data['status']
+ scenario = data["scenario"]
+ loaded = data['loaded_pid']
+
+ if scenario is None:
+ return new
+
+ values = execute(
+ "SELECT pamhyr_id, deleted, " +
+ "data0, data1, scenario " +
+ "FROM weather_parameters_data " +
+ f"WHERE wp = {wp._pamhyr_id} " +
+ f"AND scenario = {scenario.id} " +
+ f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
+ "ORDER BY ind ASC"
+ )
+
+ for v in values:
+ it = iter(v)
+
+ pid = next(it)
+ deleted = next(it)
+ data0 = wp._types[0](next(it))
+ data1 = wp._types[1](next(it))
+ owner_scenario = next(it)
+
+ nd = cls(
+ data0, data1,
+ id=pid,
+ types=wp._types,
+ status=status,
+ owner_scenario=owner_scenario
+ )
+ if deleted:
+ nd.set_as_deleted()
+
+ loaded.add(pid)
+ new.append(nd)
+
+ data["scenario"] = scenario.parent
+ new += cls._db_load(execute, data)
+ data["scenario"] = scenario
+
+ return new
+
+ def _db_save(self, execute, data=None):
+ pid = self._pamhyr_id
+ ind = data["ind"]
+ data0 = self._db_format(str(self[0]))
+ data1 = self._db_format(str(self[1]))
+ wp = data["wp"]
+
+ execute(
+ "INSERT INTO " +
+ "weather_parameters_data (pamhyr_id, deleted, ind, " +
+ "data0, data1, wp, scenario) " +
+ f"VALUES ({pid}, {self._db_format(self.is_deleted())}, " +
+ f"{ind}, '{self._db_format(data0)}', {self._db_format(data1)}, " +
+ f"{wp._pamhyr_id}, {self._status.scenario_id}" +
+ ")"
+ )
+
+ return True
+
+ def __getitem__(self, key):
+ return self._types[key](self._data[key])
+
+ def __setitem__(self, key, value):
+ self._data[key] = self._types[key](value)
+
+
+class WeatherParameters(SQLSubModel):
+ _sub_classes = [Data]
+
+ def __init__(self, id: int = -1,
+ name: str = "",
+ status=None, owner_scenario=-1):
+ super(WeatherParameters, self).__init__(
+ id=id, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._name = name
+ self._type = ""
+ self._reach = None
+ self._begin_section = None
+ self._end_section = None
+ self._data = []
+ self._header = []
+ self._types = [float, float]
+
+ @classmethod
+ def _db_create(cls, execute, ext=""):
+ execute(f"""
+ CREATE TABLE weather_parameters{ext}(
+ {cls.create_db_add_pamhyr_id()},
+ deleted BOOLEAN NOT NULL DEFAULT FALSE,
+ name TEXT NOT NULL,
+ type TEXT NOT NULL,
+ reach INTEGER,
+ begin_section INTEGER,
+ end_section INTEGER,
+ {Scenario.create_db_add_scenario()},
+ {Scenario.create_db_add_scenario_fk()},
+ FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
+ FOREIGN KEY(begin_section)
+ REFERENCES geometry_profileXYZ(pamhyr_id),
+ FOREIGN KEY(end_section)
+ REFERENCES geometry_profileXYZ(pamhyr_id),
+ PRIMARY KEY(pamhyr_id, scenario)
+ )
+ """)
+
+ if ext == "_tmp":
+ return True
+
+ return cls._create_submodel(execute)
+
+ @classmethod
+ def _get_ctor_from_type(cls, t):
+ from Model.WeatherParameters.WeatherParametersTypes import (
+ NotDefined, WeatherParam, AirTemperature, SpecificHumidity,
+ GlobalRadiation, ReferenceWindSpeed, GroundwaterTemperature,
+ GroundwaterFlowRate, Albedo, ShadingCoefficient, CloudCoverFraction
+ )
+
+ res = NotDefined
+ if t == "WP":
+ res = WeatherParam
+ elif t == "AT":
+ res = AirTemperature
+ elif t == "SH":
+ res = SpecificHumidity
+ elif t == "GR":
+ res = GlobalRadiation
+ elif t == "RWS":
+ res = ReferenceWindSpeed
+ elif t == "GT":
+ res = GroundwaterTemperature
+ elif t == "GFR":
+ res = GroundwaterFlowRate
+ elif t == "ALB":
+ res = Albedo
+ elif t == "SC":
+ res = ShadingCoefficient
+ elif t == "CCF":
+ res = CloudCoverFraction
+ else:
+ res = NotDefined
+ return res
+
+ @classmethod
+ def _db_update(cls, execute, version, data=None):
+ major, minor, release = version.strip().split(".")
+ created = False
+
+ if major == "0" and (int(minor) < 2 or
+ (int(minor) == 2 and int(release) < 7)):
+ if not cls.is_table_exists(execute, "air_temperature"):
+ cls._db_create(execute)
+ created = True
+
+ if not created:
+ return cls._update_submodel(execute, version, data)
+
+ return True
+
+ @classmethod
+ def _db_load(cls, execute, data=None):
+ new = []
+ status = data['status']
+ edges = data["edges"]
+ scenario = data["scenario"]
+ loaded = data['loaded_pid']
+
+ if scenario is None:
+ return new
+
+ table = execute(
+ "SELECT pamhyr_id, deleted, name, type, " +
+ "reach, begin_section, end_section, scenario " +
+ "FROM weather_parameters " +
+ f"WHERE scenario = {scenario.id} " +
+ f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
+ )
+
+ for row in table:
+ it = iter(row)
+
+ pid = next(it)
+ deleted = next(it)
+ name = next(it)
+ t = next(it)
+ reach = next(it)
+ b_section = next(it)
+ e_section = next(it)
+ owner_scenario = next(it)
+
+ ctor = cls._get_ctor_from_type(t)
+ wp = ctor(
+ id=pid, name=name,
+ status=status,
+ owner_scenario=owner_scenario
+ )
+ wp.reach = None
+ wp._begin_section = None
+ wp._end_section = None
+
+ if row[3] != -1:
+ wp.reach = next(
+ filter(
+ lambda e: e.id == reach,
+ edges
+ )
+ )
+ wp._begin_section = next(
+ filter(
+ lambda p: p.id == b_section,
+ wp.reach.reach.profiles
+ )
+ )
+ wp._end_section = next(
+ filter(
+ lambda p: p.id == e_section,
+ wp.reach.reach.profiles
+ )
+ )
+
+ data["wp"] = wp
+ wp._data = Data._db_load(execute, data=data)
+
+ loaded.add(pid)
+ new.append(wp)
+
+ data["scenario"] = scenario.parent
+ new += cls._db_load(execute, data)
+ data["scenario"] = scenario
+
+ return new
+
+ def _db_save(self, execute, data=None):
+ if not self.must_be_saved():
+ return True
+
+ data["wp"] = self
+
+ execute(
+ "DELETE FROM weather_parameters_data " +
+ f"WHERE wp = {self._pamhyr_id} " +
+ f"AND scenario = {self._status.scenario_id}"
+ )
+
+ reach = -1
+ begin_section = -1
+ end_section = -1
+
+ if self._reach is not None:
+ reach = self._reach._pamhyr_id
+ begin_section = self._begin_section._pamhyr_id
+ end_section = self._end_section._pamhyr_id
+
+ execute(
+ "INSERT INTO " +
+ "weather_parameters(" +
+ "pamhyr_id, deleted, name, type, " +
+ "reach, begin_section, end_section, scenario) " +
+ "VALUES (" +
+ f"{self.id}, {self._db_format(self.is_deleted())}, " +
+ f"'{self._db_format(self._name)}', " +
+ f"'{self._db_format(self._type)}', {reach}, " +
+ f"{begin_section}, {end_section}, " +
+ f"{self._status.scenario_id}" +
+ ")"
+ )
+
+ ind = 0
+ for d in self._data:
+ data["ind"] = ind
+
+ d._db_save(execute, data)
+
+ ind += 1
+
+ return True
+
+ def _data_traversal(self,
+ predicate=lambda obj, data: True,
+ modifier=lambda obj, data: None,
+ data={}):
+ if predicate(self, data):
+ modifier(self, data)
+
+ for d in self._data:
+ d._data_traversal(predicate, modifier, data)
+
+ def __len__(self):
+ return len(
+ list(
+ filter(
+ lambda el: not el.is_deleted(),
+ self._data
+ )
+ )
+ )
+
+ @classmethod
+ def compatibility(cls):
+ return ["liquid", "solid", "suspenssion"]
+
+ @classmethod
+ def time_convert(cls, data):
+ if type(data) is str:
+ if data.count("-") == 2:
+ return date_iso_to_timestamp(data)
+ if data.count("/") == 2:
+ return date_dmy_to_timestamp(data)
+ if data.count(":") == 3:
+ return old_pamhyr_date_to_timestamp(data)
+ if data.count(":") == 2:
+ return old_pamhyr_date_to_timestamp("00:" + data)
+ if data.count(".") == 1:
+ return round(float(data))
+
+ return int(data)
+
+ @property
+ def name(self):
+ if self._name == "":
+ return f"LC #{self.id}"
+
+ return self._name
+
+ @name.setter
+ def name(self, name):
+ self._name = name
+ self.modified()
+
+ @property
+ def wptype(self):
+ return self._type
+
+ @property
+ def reach(self):
+ return self._reach
+
+ @reach.setter
+ def reach(self, reach):
+ self._reach = reach
+ if reach is not None:
+ self._begin_section = self._reach.reach.profiles[0]
+ self._end_section = self._reach.reach.profiles[-1]
+
+ self.modified()
+
+ def has_reach(self):
+ return self._reach is not None
+
+ @property
+ def begin_rk(self):
+ if self._begin_section is None:
+ return 0
+
+ return self._begin_section.rk
+
+ @property
+ def begin_section(self):
+ return self._begin_section
+
+ @begin_section.setter
+ def begin_section(self, section):
+ self._begin_section = section
+ self.modified()
+
+ @property
+ def end_rk(self):
+ if self._end_section is None:
+ return 0
+
+ return self._end_section.rk
+
+ @property
+ def end_section(self):
+ return self._end_section
+
+ @end_section.setter
+ def end_section(self, section):
+ self._end_section = section
+ self.modified()
+
+ @property
+ def header(self):
+ return self._header.copy()
+
+ @property
+ def data(self):
+ return list(
+ filter(
+ lambda el: not el.is_deleted(),
+ self._data
+ )
+ )
+
+ def get_type_column(self, column):
+ if 0 <= column < 2:
+ return self._types[column]
+ return None
+
+ @property
+ def _default_0(self):
+ return self._types[0](0)
+
+ @property
+ def _default_1(self):
+ return self._types[1](0.0)
+
+ def is_define(self):
+ return self._data is not None
+
+ def new_from_data(self, header, data):
+ new_0 = self._default_0
+ new_1 = self._default_1
+
+ if len(header) != 0:
+ for i in [0, 1]:
+ for j in range(len(header)):
+ if self._header[i] == header[j]:
+ if i == 0:
+ new_0 = self._types[i](data[j].replace(",", "."))
+ else:
+ new_1 = self._types[i](data[j].replace(",", "."))
+ else:
+ new_0 = self._types[0](data[0].replace(",", "."))
+ new_1 = self._types[1](data[1].replace(",", "."))
+
+ return Data(new_0, new_1, status=self._status)
+
+ def add(self, index: int):
+ value = Data(self._default_0, self._default_1, status=self._status)
+ self._data.insert(index, value)
+ self.modified()
+ return value
+
+ def insert(self, index: int, value):
+ self._data.insert(index, value)
+ self.modified()
+
+ def delete_i(self, indexes):
+ self._data = list(
+ map(
+ lambda e: e[1],
+ filter(
+ lambda e: e[0] not in indexes,
+ enumerate(self.data)
+ )
+ )
+ )
+ self.modified()
+
+ def delete(self, els):
+ self._data = list(
+ filter(
+ lambda e: e not in els,
+ self.data
+ )
+ )
+ self.modified()
+
+ def sort(self, _reverse=False, key=None):
+ if key is None:
+ self._data.sort(reverse=_reverse)
+ else:
+ self._data.sort(reverse=_reverse, key=key)
+ self.modified()
+
+ def get_i(self, index):
+ return self.data[index]
+
+ def get_range(self, _range):
+ lst = []
+ for r in _range:
+ lst.append(r)
+ return lst
+
+ def _set_i_c_v(self, index, column, value):
+ v = self._data[index]
+ v[column] = self._types[column](value)
+ self._data[index] = v
+ self.modified()
+
+ def set_i_0(self, index: int, value):
+ self._set_i_c_v(index, 0, value)
+
+ def set_i_1(self, index: int, value):
+ self._set_i_c_v(index, 1, value)
+
+ @timer
+ def convert(self, cls):
+ new = cls(name=self.name, status=self._status)
+ new.reach = self.reach
+ new.begin_section = self.begin_section
+ new.end_section = self.end_section
+
+ 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:
+ try:
+ new._set_i_c_v(ind, j, v[i])
+ except Exception as e:
+ logger.info(e)
+
+ self.modified()
+ return new
+
+ def move_up(self, index):
+ if index < len(self):
+ next = index - 1
+ d = self._data
+ d[index], d[next] = d[next], d[index]
+ self.modified()
+
+ def move_down(self, index):
+ if index >= 0:
+ prev = index + 1
+ d = self._data
+ d[index], d[prev] = d[prev], d[index]
+ self.modified()
diff --git a/src/Model/WeatherParameters/WeatherParametersList.py b/src/Model/WeatherParameters/WeatherParametersList.py
new file mode 100644
index 00000000..a7e2f215
--- /dev/null
+++ b/src/Model/WeatherParameters/WeatherParametersList.py
@@ -0,0 +1,96 @@
+# WeatherParametersList.py -- Pamhyr
+# Copyright (C) 2023-2025 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.PamhyrListExt import PamhyrModelList
+from Model.Except import NotImplementedMethodeError
+
+from Model.WeatherParameters.WeatherParameters import WeatherParameters
+from Model.WeatherParameters.WeatherParametersTypes import (
+ NotDefined, WeatherParam, AirTemperature, SpecificHumidity,
+ GlobalRadiation, ReferenceWindSpeed, GroundwaterTemperature,
+ GroundwaterFlowRate, Albedo, ShadingCoefficient, CloudCoverFraction
+)
+
+
+class WeatherParametersList(PamhyrModelList):
+ _sub_classes = [
+ WeatherParameters,
+ ]
+
+ @classmethod
+ def _db_load(cls, execute, data=None):
+ new = cls(status=data['status'])
+
+ if data is None:
+ data = {}
+
+ new._lst = WeatherParameters._db_load(
+ execute, data
+ )
+
+ return new
+
+ def _db_save(self, execute, data=None):
+ execute(
+ "DELETE FROM weather_parameters " +
+ f"WHERE scenario = {self._status.scenario_id}"
+ )
+ execute(
+ "DELETE FROM weather_parameters_data " +
+ f"WHERE scenario = {self._status.scenario_id}"
+ )
+
+ if data is None:
+ data = {}
+
+ for wp in self._lst:
+ wp._db_save(execute, data=data)
+
+ return True
+
+ def new(self, index, type="ND"):
+ if type == "AT":
+ n = AirTemperature(status=self._status)
+ elif type == "SH":
+ n = SpecificHumidity(status=self._status)
+ elif type == "GR":
+ n = GlobalRadiation(status=self._status)
+ elif type == "RWS":
+ n = ReferenceWindSpeed(status=self._status)
+ elif type == "GT":
+ n = GroundwaterTemperature(status=self._status)
+ elif type == "GFR":
+ n = GroundwaterFlowRate(status=self._status)
+ elif type == "ALB":
+ n = Albedo(status=self._status)
+ elif type == "SC":
+ n = ShadingCoefficient(status=self._status)
+ elif type == "CCF":
+ n = CloudCoverFraction(status=self._status)
+ else:
+ n = NotDefined(status=self._status)
+ self._lst.insert(index, n)
+ self._status.modified()
+ return n
+
+ @property
+ def Weather_Parameters_List(self):
+ return self.lst
diff --git a/src/Model/WeatherParameters/WeatherParametersTypes.py b/src/Model/WeatherParameters/WeatherParametersTypes.py
new file mode 100644
index 00000000..3db87fd6
--- /dev/null
+++ b/src/Model/WeatherParameters/WeatherParametersTypes.py
@@ -0,0 +1,171 @@
+# LateralContributionTypes.py -- Pamhyr
+# Copyright (C) 2023-2025 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
+
+from Model.WeatherParameters.WeatherParameters import WeatherParameters
+
+
+class NotDefined(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(NotDefined, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "ND"
+ self._header = ["x", "y"]
+
+ @property
+ def _default_0(self):
+ return 0.0
+
+
+class WeatherParam(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(WeatherParam, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "WP"
+ self._header = ["time", "value"]
+ self._types = [WeatherParam.time_convert, float]
+
+ @classmethod
+ def compatibility(cls):
+ return ["liquid"]
+
+
+class AirTemperature(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(AirTemperature, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "AT"
+ self._header = ["time", "temperature"]
+ self._types = [AirTemperature.time_convert, float]
+
+
+class SpecificHumidity(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(SpecificHumidity, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "SH"
+ self._header = ["time", "discharge"]
+ self._types = [SpecificHumidity.time_convert, float]
+
+
+class GlobalRadiation(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(GlobalRadiation, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "GR"
+ self._header = ["time", "discharge"]
+ self._types = [GlobalRadiation.time_convert, float]
+
+
+class ReferenceWindSpeed(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(ReferenceWindSpeed, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "RWS"
+ self._header = ["time", "discharge"]
+ self._types = [ReferenceWindSpeed.time_convert, float]
+
+
+class GroundwaterTemperature(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(GroundwaterTemperature, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "GT"
+ self._header = ["time", "discharge"]
+ self._types = [GroundwaterTemperature.time_convert, float]
+
+
+class GroundwaterFlowRate(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(GroundwaterFlowRate, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "GFR"
+ self._header = ["time", "discharge"]
+ self._types = [GroundwaterFlowRate.time_convert, float]
+
+
+class Albedo(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(Albedo, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "ALB"
+ self._header = ["time", "discharge"]
+ self._types = [Albedo.time_convert, float]
+
+
+class ShadingCoefficient(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(ShadingCoefficient, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "SC"
+ self._header = ["time", "discharge"]
+ self._types = [ShadingCoefficient.time_convert, float]
+
+
+class CloudCoverFraction(WeatherParameters):
+ def __init__(self, id: int = -1, name: str = "",
+ status=None, owner_scenario=-1):
+ super(CloudCoverFraction, self).__init__(
+ id=id, name=name, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ self._type = "CCF"
+ self._header = ["time", "discharge"]
+ self._types = [CloudCoverFraction.time_convert, float]
diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py
index 104f5c50..4105fd2b 100644
--- a/src/View/MainWindow.py
+++ b/src/View/MainWindow.py
@@ -1045,16 +1045,18 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
def open_weather_parameters(self):
river = self._study.river
-
+ weather_param = river.weather_parameters
+
if self.sub_window_exists(
WeatherParametersWindow,
- data=[self._study, None]
+ data=[self._study, None, weather_param]
):
return
bound = WeatherParametersWindow(
study=self._study,
parent=self,
+ data=weather_param
)
bound.show()
diff --git a/src/View/WeatherParameters/Table.py b/src/View/WeatherParameters/Table.py
index bc884ac7..1e2e8486 100644
--- a/src/View/WeatherParameters/Table.py
+++ b/src/View/WeatherParameters/Table.py
@@ -36,8 +36,8 @@ from PyQt5.QtWidgets import (
from View.Tools.PamhyrTable import PamhyrTableModel
from View.WeatherParameters.UndoCommand import (
- SetCommand, AddCommand, SetCommandSpec,
- DelCommand,
+ SetCommand, AddCommand, DelCommand,
+ SetEdgeCommand, SetBeginCommand, SetEndCommand,
)
logger = logging.getLogger()
@@ -46,43 +46,50 @@ _translate = QCoreApplication.translate
class ComboBoxDelegate(QItemDelegate):
- def __init__(self, data=None, _weather_param_lst=None,
+ def __init__(self, data=None, weather_param_lst=None,
trad=None, parent=None, mode="reaches"):
super(ComboBoxDelegate, self).__init__(parent)
self._data = data
self._mode = mode
self._trad = trad
- # self._weather_param_lst = _weather_param_lst
+ self._weather_param_lst = weather_param_lst
+
+ @property
+ def weather_param_lst(self):
+ return self._weather_param_lst
+
+ @weather_param_lst.setter
+ def weather_param_lst(self, weather_param_lst):
+ self._weather_param_lst = weather_param_lst
+ # self.modified()
def createEditor(self, parent, option, index):
self.editor = QComboBox(parent)
- val = []
if self._mode == "rk":
- reach_id = self._weather_param_lst[index.row()].reach
-
- reach = next(filter(lambda edge: edge.id == reach_id,
- self._data.edges()), None)
-
- if reach_id is not None:
- val = list(
- map(
- lambda rk: str(rk), reach.reach.get_rk()
+ wp = None
+ if self._weather_param_lst is not None:
+ wp = self._weather_param_lst.get(index.row())
+ if wp is None or wp.reach is None:
+ self.editor.addItems(
+ ["-"]
+ )
+ else:
+ self.editor.addItems(
+ list(
+ map(
+ lambda p: p.display_name(),
+ wp.reach.reach.profiles
+ )
)
)
else:
- val = list(
- map(
- lambda n: n.name, self._data.edges()
- )
+ self.editor.addItems(
+ [self._trad['not_associated']] +
+ self._data.edges_names()
)
- self.editor.addItems(
- [self._trad['not_associated']] +
- val
- )
-
self.editor.setCurrentText(str(index.data(Qt.DisplayRole)))
return self.editor
@@ -92,7 +99,24 @@ class ComboBoxDelegate(QItemDelegate):
def setModelData(self, editor, model, index):
text = str(editor.currentText())
- model.setData(index, text)
+
+ if self._mode == "rk":
+ value = None
+ wp = None
+ if self._weather_param_lst is not None:
+ wp = self._weather_param_lst.get(index.row())
+ if wp is not None and wp.reach is not None:
+ profiles = list(
+ filter(
+ lambda p: p.display_name() == text,
+ wp.reach.reach.profiles
+ )
+ )
+ value = profiles[0].pamhyr_id if len(profiles) > 0 else None
+ else:
+ value = text
+
+ model.setData(index, value)
editor.close()
editor.deleteLater()
@@ -115,16 +139,16 @@ class WeatherParametersTableModel(PamhyrTableModel):
super(WeatherParametersTableModel, self).__init__(data=data, **kwargs)
self._data = data
- print("self._data: ", self._data)
+ self._type = "ND"
def _setup_lst(self):
- # self._lst = list(
- # filter(
- # lambda ica: ica._deleted is False,
- # self._data._data
- # )
- # )
- self._lst = self._data._data
+ self._lst = self._data.lst
+
+ def update_tab_spec(self, type="ND"):
+ # self._data = data
+ self._type = type
+ self._setup_lst()
+ self.layoutChanged.emit()
def rowCount(self, parent):
return len(self._lst)
@@ -136,34 +160,21 @@ class WeatherParametersTableModel(PamhyrTableModel):
row = index.row()
column = index.column()
- if self._headers[column] == "name":
- n = self._lst[row].name
- if n is None or n == "":
+ if self._headers[column] == "reach":
+ reach = self._lst[row].reach
+ if reach is None:
return self._trad['not_associated']
- return n
- elif self._headers[column] == "reach":
- n = self._lst[row].reach
- if n is None:
- return self._trad['not_associated']
- return next(filter(
- lambda edge: edge.id == n, self._river.edges()
- )).name
+ return reach.name
elif self._headers[column] == "start_rk":
- n = self._lst[row].start_rk
- if n is None:
+ section = self._lst[row].begin_section
+ if section is None:
return self._trad['not_associated']
- return n
+ return section.display_name()
elif self._headers[column] == "end_rk":
- n = self._lst[row].end_rk
- if n is None:
+ section = self._lst[row].end_section
+ if section is None:
return self._trad['not_associated']
- return n
- elif self._headers[column] == "value":
- n = self._lst[row].value
- if n is None:
- return self._trad['not_associated']
- return n
- return n
+ return section.display_name()
return QVariant()
@@ -178,17 +189,32 @@ class WeatherParametersTableModel(PamhyrTableModel):
column = index.column()
try:
- if self._headers[column] != "reach":
+ if self._headers[column] == "start_rk":
+ _edge = self._data.get(row).reach
+ _begin_rk = next(
+ p for p in _edge.reach.profiles
+ if p.pamhyr_id == value
+ )
self._undo.push(
- SetCommandSpec(
- self._lst, row, self._headers[column], value
+ SetBeginCommand(
+ self._data, row, _begin_rk
+ )
+ )
+ elif self._headers[column] == "end_rk":
+ _edge = self._data.get(row).reach
+ _end_rk = next(
+ p for p in _edge.reach.profiles
+ if p.pamhyr_id == value
+ )
+ self._undo.push(
+ SetEndCommand(
+ self._data, row, _end_rk
)
)
elif self._headers[column] == "reach":
self._undo.push(
- SetCommandSpec(
- self._lst, row, self._headers[column],
- self._river.edge(value).id
+ SetEdgeCommand(
+ self._data, row, self._river.edge(value)
)
)
except Exception as e:
@@ -203,7 +229,7 @@ class WeatherParametersTableModel(PamhyrTableModel):
self._undo.push(
AddCommand(
- self._data, self._lst, row
+ self._data, self._type, self._lst, row
)
)
diff --git a/src/View/WeatherParameters/UndoCommand.py b/src/View/WeatherParameters/UndoCommand.py
index 984be6e7..85c628cb 100644
--- a/src/View/WeatherParameters/UndoCommand.py
+++ b/src/View/WeatherParameters/UndoCommand.py
@@ -28,6 +28,8 @@ from Model.InitialConditionsAdisTS.InitialConditionsAdisTS \
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSList \
import InitialConditionsAdisTSList
+from Model.River import RiverReach
+
class SetCommand(QUndoCommand):
def __init__(self, data, row, column, new_value):
@@ -79,88 +81,61 @@ class SetCommand(QUndoCommand):
self._data[self._row].ed = self._new
-class SetCommandSpec(QUndoCommand):
- def __init__(self, data, row, column, new_value):
+class SetBeginCommand(QUndoCommand):
+ def __init__(self, wps, index, new_value):
QUndoCommand.__init__(self)
- self._data = data
- self._row = row
- self._column = column
-
- if self._column == "name":
- self._old = self._data[self._row].name
- elif self._column == "reach":
- self._old = self._data[self._row].reach
- elif self._column == "start_rk":
- self._old = self._data[self._row].start_rk
- elif self._column == "end_rk":
- self._old = self._data[self._row].end_rk
- elif self._column == "concentration":
- self._old = self._data[self._row].concentration
- elif self._column == "eg":
- self._old = self._data[self._row].eg
- elif self._column == "em":
- self._old = self._data[self._row].em
- elif self._column == "ed":
- self._old = self._data[self._row].ed
- elif self._column == "rate":
- self._old = self._data[self._row].rate
-
- _type = float
- if column == "name":
- _type = str
- elif column == "reach":
- _type = int
-
- self._new = _type(new_value)
+ self._wps = wps
+ self._index = index
+ self._old = self._wps.get(self._index).begin_section
+ self._new = new_value
def undo(self):
- if self._column == "name":
- self._data[self._row].name = self._old
- elif self._column == "reach":
- self._data[self._row].reach = self._old
- elif self._column == "start_rk":
- self._data[self._row].start_rk = self._old
- elif self._column == "end_rk":
- self._data[self._row].end_rk = self._old
- elif self._column == "concentration":
- self._data[self._row].concentration = self._old
- elif self._column == "eg":
- self._data[self._row].eg = self._old
- elif self._column == "em":
- self._data[self._row].em = self._old
- elif self._column == "ed":
- self._data[self._row].ed = self._old
- elif self._column == "rate":
- self._data[self._row].rate = self._old
+ self._wps.get(self._index).begin_section = self._old
def redo(self):
- if self._column == "name":
- self._data[self._row].name = self._new
- elif self._column == "reach":
- self._data[self._row].reach = self._new
- elif self._column == "start_rk":
- self._data[self._row].start_rk = self._new
- elif self._column == "end_rk":
- self._data[self._row].end_rk = self._new
- elif self._column == "concentration":
- self._data[self._row].concentration = self._new
- elif self._column == "eg":
- self._data[self._row].eg = self._new
- elif self._column == "em":
- self._data[self._row].em = self._new
- elif self._column == "ed":
- self._data[self._row].ed = self._new
- elif self._column == "rate":
- self._data[self._row].rate = self._new
+ self._wps.get(self._index).begin_section = self._new
+
+
+class SetEndCommand(QUndoCommand):
+ def __init__(self, wps, index, new_value):
+ QUndoCommand.__init__(self)
+
+ self._wps = wps
+ self._index = index
+ self._old = self._wps.get(self._index).end_section
+ self._new = new_value
+
+ def undo(self):
+ self._wps.get(self._index).end_section = self._old
+
+ def redo(self):
+ self._wps.get(self._index).end_section = self._new
+
+
+class SetEdgeCommand(QUndoCommand):
+ def __init__(self, wps, index, edge):
+ QUndoCommand.__init__(self)
+
+ self._wps = wps
+ self._index = index
+ self._old = self._wps.get(self._index).reach
+ self._new = edge
+
+ def undo(self):
+ self._wps.get(self._index).reach = self._old
+
+ def redo(self):
+ self._wps.get(self._index).reach = self._new
class AddCommand(QUndoCommand):
- def __init__(self, data, ics_spec, index):
+ def __init__(self, data, type, wps_spec, index):
QUndoCommand.__init__(self)
self._data = data
- self._ics_spec = ics_spec
+ self._type = type
+ self._wps_spec = wps_spec
self._index = index
self._new = None
@@ -169,22 +144,22 @@ class AddCommand(QUndoCommand):
def redo(self):
if self._new is None:
- self._new = self._data.new(self._index)
+ self._new = self._data.new(self._index, self._type)
else:
self._data.insert(self._index, self._new)
class DelCommand(QUndoCommand):
- def __init__(self, data, ics_spec, rows):
+ def __init__(self, data, wps_spec, rows):
QUndoCommand.__init__(self)
self._data = data
- self._ics_spec = ics_spec
+ self._wps_spec = wps_spec
self._rows = rows
self._ic = []
for row in rows:
- self._ic.append((row, self._ics_spec[row]))
+ self._ic.append((row, self._wps_spec[row]))
self._ic.sort()
def undo(self):
diff --git a/src/View/WeatherParameters/Window.py b/src/View/WeatherParameters/Window.py
index 4aa0c7ab..4a721691 100644
--- a/src/View/WeatherParameters/Window.py
+++ b/src/View/WeatherParameters/Window.py
@@ -68,15 +68,14 @@ class WeatherParametersWindow(PamhyrWindow):
_pamhyr_ui = "WeatherParameters"
_pamhyr_name = "Weather parameters"
-
def __init__(self, data=None, study=None,
config=None, parent=None):
- self._data = []
- # self._data.append(data)
+ # self._data = []
+ self._data = data
trad = WeatherParametersTranslate()
- self.weather_params = [trad.get_dict("weather_parameters")[k] for k in trad.get_dict("weather_parameters").keys()]
- print(f"Weather parameters: {self.weather_params}")
+ self.weather_params = [trad.get_dict("weather_parameters")[k] for
+ k in trad.get_dict("weather_parameters").keys()]
name = (
trad[self._pamhyr_name] +
" - " + study.name
@@ -92,14 +91,15 @@ class WeatherParametersWindow(PamhyrWindow):
self._hash_data.append(data)
- # self._ics_adists_lst = study.river.ic_adists
-
+ self._wp_acronyms = [
+ "AT", "SH", "GR", "RWS", "GT", "GFR", "ALB", "SC", "CCF"
+ ]
self.setup_table()
def setup_table(self):
path_icons = os.path.join(self._get_ui_directory(), f"ressources")
- table_default = self.find(QTableView, f"tableView")
+ self.table_default = self.find(QTableView, f"tableView")
if self._study.is_editable():
editable_headers = self._trad.get_dict("table_headers")
@@ -107,7 +107,7 @@ class WeatherParametersWindow(PamhyrWindow):
editable_headers = []
self._table = WeatherParametersTableDefaultModel(
- table_view=table_default,
+ table_view=self.table_default,
table_headers=self._trad.get_dict("table_headers"),
editable_headers=editable_headers,
delegates={},
@@ -116,12 +116,15 @@ class WeatherParametersWindow(PamhyrWindow):
trad=self._trad
)
- table_default.setModel(self._table)
- table_default.setSelectionBehavior(QAbstractItemView.SelectRows)
- table_default.horizontalHeader().setSectionResizeMode(
+ self.table_default.setModel(self._table)
+ self.table_default.setSelectionBehavior(QAbstractItemView.SelectRows)
+ self.table_default.horizontalHeader().setSectionResizeMode(
QHeaderView.Stretch
)
- table_default.setAlternatingRowColors(True)
+ self.table_default.setAlternatingRowColors(True)
+ self.table_default.selectionModel().selectionChanged.connect(
+ self.on_table_default_selection_changed
+ )
layout = self.find(QVBoxLayout, f"verticalLayout_1")
toolBar = QToolBar()
@@ -147,12 +150,14 @@ class WeatherParametersWindow(PamhyrWindow):
self._delegate_reach = ComboBoxDelegate(
trad=self._trad,
data=self._study.river,
+ weather_param_lst=None,
parent=self,
mode="reaches"
)
self._delegate_rk = ComboBoxDelegate(
trad=self._trad,
data=self._study.river,
+ weather_param_lst=self._study.river.weather_parameters,
parent=self,
mode="rk"
)
@@ -171,7 +176,7 @@ class WeatherParametersWindow(PamhyrWindow):
"start_rk": self._delegate_rk,
"end_rk": self._delegate_rk
},
- data=self._data,
+ data=self._study.river.weather_parameters,
undo=self._undo_stack,
trad=self._trad,
river=self._study.river
@@ -195,6 +200,25 @@ class WeatherParametersWindow(PamhyrWindow):
)
self.table_spec.scrollTo(index)
+ def on_table_default_selection_changed(self, selected, deselected):
+ rows = self.table_default.selectionModel().selectedRows()
+ if len(rows) == 0:
+ self._selected_default_row_index = None
+ return None
+
+ self._selected_default_row_index = rows[0].row()
+
+ self._table_spec.update_tab_spec(
+ type=self._wp_acronyms[
+ self._selected_default_row_index
+ ]
+ )
+ # self._data = self._study.river.weather_parameters
+ # self._delegate_rk.weather_param_lst = (
+ # self._study.river.weather_parameters)
+
+ return self._selected_default_row_index
+
def index_selected_row(self):
# table = self.find(QTableView, f"tableView")
table = self.table_spec
@@ -208,7 +232,7 @@ class WeatherParametersWindow(PamhyrWindow):
def index_selected_rows(self):
# table = self.find(QTableView, f"tableView")
- table = self.table_spec
+ table = self.table_default
return list(
# Delete duplicate
set(
@@ -301,10 +325,11 @@ class WeatherParametersWindow(PamhyrWindow):
def add(self):
rows = self.index_selected_rows()
- if len(self._data[0]._data) == 0 or len(rows) == 0:
- self._table_spec.add(0)
- else:
- self._table_spec.add(rows[0])
+ if rows is not None and len(rows) > 0:
+ if len(self._data.lst) == 0 or len(rows) == 0:
+ self._table_spec.add(0)
+ else:
+ self._table_spec.add(rows[0])
def delete(self):
rows = self.index_selected_rows()
diff --git a/src/View/WeatherParameters/translate.py b/src/View/WeatherParameters/translate.py
index 4da9de4f..ca72e52d 100644
--- a/src/View/WeatherParameters/translate.py
+++ b/src/View/WeatherParameters/translate.py
@@ -38,13 +38,27 @@ class WeatherParametersTranslate(MainTranslate):
}
self._sub_dict["table_headers_spec"] = {
- "name": self._dict["name"],
"reach": self._dict["reach"],
"start_rk": _translate("Unit", "Start_RK (m)"),
"end_rk": _translate("Unit", "End_RK (m)"),
- "value": self._dict["value"]
}
self._sub_dict["weather_parameters"] = {
- "air_temperature": _translate("WeatherParameters", "Air temperature")
- }
\ No newline at end of file
+ "air_temperature": _translate("WeatherParameters",
+ "Air Temperature (°C)"),
+ "specific_humidity": _translate("WeatherParameters",
+ "Specific Humidity (%)"),
+ "global_radiation": _translate("WeatherParameters",
+ "Global Radiation (W/m²)"),
+ "reference_wind_speed": _translate("WeatherParameters",
+ "Reference Wind Speed (m/s)"),
+ "surface_temperature": _translate("WeatherParameters",
+ "Groundwater Temperature (°C)"),
+ "surface_flow_rate": _translate("WeatherParameters",
+ "Groundwater Flow Rate (m³/s)"),
+ "albedo": _translate("WeatherParameters", "Albedo"),
+ "shading_coefficient": _translate("WeatherParameters",
+ "Shading Coefficient"),
+ "cloud_cover_fraction": _translate("WeatherParameters",
+ "Cloud Cover Fraction"),
+ }