mirror of https://gitlab.com/pamhyr/pamhyr2
Weather params: Dual tab for parameters with add functionnality
parent
b2ca1c2ab7
commit
246b411114
|
|
@ -66,8 +66,8 @@ from Model.InitialConditionsTemperature.InitialConditionsTemperatureList \
|
||||||
from Model.BoundaryConditionsTemperature.BoundaryConditionsTemperatureList \
|
from Model.BoundaryConditionsTemperature.BoundaryConditionsTemperatureList \
|
||||||
import BoundaryConditionsTemperatureList
|
import BoundaryConditionsTemperatureList
|
||||||
|
|
||||||
from Model.WeatherParameters.AirTemperatureList \
|
from Model.WeatherParameters.WeatherParametersList \
|
||||||
import AirTemperatureList
|
import WeatherParametersList
|
||||||
|
|
||||||
from Model.GeoTIFF.GeoTIFFList import GeoTIFFList
|
from Model.GeoTIFF.GeoTIFFList import GeoTIFFList
|
||||||
from Model.Results.Results import Results
|
from Model.Results.Results import Results
|
||||||
|
|
@ -487,7 +487,7 @@ class River(Graph):
|
||||||
DIFAdisTSList,
|
DIFAdisTSList,
|
||||||
InitialConditionsTemperatureList,
|
InitialConditionsTemperatureList,
|
||||||
BoundaryConditionsTemperatureList,
|
BoundaryConditionsTemperatureList,
|
||||||
AirTemperatureList,
|
WeatherParametersList,
|
||||||
GeoTIFFList,
|
GeoTIFFList,
|
||||||
Results
|
Results
|
||||||
]
|
]
|
||||||
|
|
@ -531,7 +531,7 @@ class River(Graph):
|
||||||
self._BoundaryConditionsTemperature = (
|
self._BoundaryConditionsTemperature = (
|
||||||
BoundaryConditionsTemperatureList(status=self._status)
|
BoundaryConditionsTemperatureList(status=self._status)
|
||||||
)
|
)
|
||||||
self._AirTemperature = (AirTemperatureList(status=self._status))
|
self._WeatherParameters = (WeatherParametersList(status=self._status))
|
||||||
|
|
||||||
self._geotiff = GeoTIFFList(status=self._status)
|
self._geotiff = GeoTIFFList(status=self._status)
|
||||||
|
|
||||||
|
|
@ -653,7 +653,7 @@ class River(Graph):
|
||||||
new._BoundaryConditionsTemperature = \
|
new._BoundaryConditionsTemperature = \
|
||||||
BoundaryConditionsTemperatureList._db_load(execute, data)
|
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)
|
new._geotiff = GeoTIFFList._db_load(execute, data)
|
||||||
|
|
||||||
|
|
@ -692,7 +692,7 @@ class River(Graph):
|
||||||
|
|
||||||
objs.append(self._InitialConditionsTemperature)
|
objs.append(self._InitialConditionsTemperature)
|
||||||
objs.append(self._BoundaryConditionsTemperature)
|
objs.append(self._BoundaryConditionsTemperature)
|
||||||
objs.append(self._AirTemperature)
|
objs.append(self._WeatherParameters)
|
||||||
|
|
||||||
objs.append(self._geotiff)
|
objs.append(self._geotiff)
|
||||||
|
|
||||||
|
|
@ -774,7 +774,7 @@ class River(Graph):
|
||||||
self._D90AdisTS, self._DIFAdisTS,
|
self._D90AdisTS, self._DIFAdisTS,
|
||||||
self._InitialConditionsTemperature,
|
self._InitialConditionsTemperature,
|
||||||
self._BoundaryConditionsTemperature,
|
self._BoundaryConditionsTemperature,
|
||||||
self._AirTemperature,
|
self._WeatherParameters,
|
||||||
self._geotiff,
|
self._geotiff,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -917,8 +917,8 @@ Last export at: @date."""
|
||||||
return self._BoundaryConditionsTemperature
|
return self._BoundaryConditionsTemperature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def air_temperature(self):
|
def weather_parameters(self):
|
||||||
return self._AirTemperature
|
return self._WeatherParameters
|
||||||
|
|
||||||
def get_params(self, solver):
|
def get_params(self, solver):
|
||||||
if solver in self._parameters:
|
if solver in self._parameters:
|
||||||
|
|
|
||||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# -*- 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)
|
|
||||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# -*- 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
|
|
||||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- 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()
|
||||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- 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
|
||||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# -*- 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]
|
||||||
|
|
@ -1045,16 +1045,18 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||||
|
|
||||||
def open_weather_parameters(self):
|
def open_weather_parameters(self):
|
||||||
river = self._study.river
|
river = self._study.river
|
||||||
|
weather_param = river.weather_parameters
|
||||||
|
|
||||||
if self.sub_window_exists(
|
if self.sub_window_exists(
|
||||||
WeatherParametersWindow,
|
WeatherParametersWindow,
|
||||||
data=[self._study, None]
|
data=[self._study, None, weather_param]
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
bound = WeatherParametersWindow(
|
bound = WeatherParametersWindow(
|
||||||
study=self._study,
|
study=self._study,
|
||||||
parent=self,
|
parent=self,
|
||||||
|
data=weather_param
|
||||||
)
|
)
|
||||||
bound.show()
|
bound.show()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ from PyQt5.QtWidgets import (
|
||||||
from View.Tools.PamhyrTable import PamhyrTableModel
|
from View.Tools.PamhyrTable import PamhyrTableModel
|
||||||
|
|
||||||
from View.WeatherParameters.UndoCommand import (
|
from View.WeatherParameters.UndoCommand import (
|
||||||
SetCommand, AddCommand, SetCommandSpec,
|
SetCommand, AddCommand, DelCommand,
|
||||||
DelCommand,
|
SetEdgeCommand, SetBeginCommand, SetEndCommand,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
@ -46,41 +46,48 @@ _translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class ComboBoxDelegate(QItemDelegate):
|
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"):
|
trad=None, parent=None, mode="reaches"):
|
||||||
super(ComboBoxDelegate, self).__init__(parent)
|
super(ComboBoxDelegate, self).__init__(parent)
|
||||||
|
|
||||||
self._data = data
|
self._data = data
|
||||||
self._mode = mode
|
self._mode = mode
|
||||||
self._trad = trad
|
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):
|
def createEditor(self, parent, option, index):
|
||||||
self.editor = QComboBox(parent)
|
self.editor = QComboBox(parent)
|
||||||
|
|
||||||
val = []
|
|
||||||
if self._mode == "rk":
|
if self._mode == "rk":
|
||||||
reach_id = self._weather_param_lst[index.row()].reach
|
wp = None
|
||||||
|
if self._weather_param_lst is not None:
|
||||||
reach = next(filter(lambda edge: edge.id == reach_id,
|
wp = self._weather_param_lst.get(index.row())
|
||||||
self._data.edges()), None)
|
if wp is None or wp.reach is None:
|
||||||
|
self.editor.addItems(
|
||||||
if reach_id is not None:
|
["-"]
|
||||||
val = list(
|
)
|
||||||
|
else:
|
||||||
|
self.editor.addItems(
|
||||||
|
list(
|
||||||
map(
|
map(
|
||||||
lambda rk: str(rk), reach.reach.get_rk()
|
lambda p: p.display_name(),
|
||||||
|
wp.reach.reach.profiles
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
val = list(
|
|
||||||
map(
|
|
||||||
lambda n: n.name, self._data.edges()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.editor.addItems(
|
self.editor.addItems(
|
||||||
[self._trad['not_associated']] +
|
[self._trad['not_associated']] +
|
||||||
val
|
self._data.edges_names()
|
||||||
)
|
)
|
||||||
|
|
||||||
self.editor.setCurrentText(str(index.data(Qt.DisplayRole)))
|
self.editor.setCurrentText(str(index.data(Qt.DisplayRole)))
|
||||||
|
|
@ -92,7 +99,24 @@ class ComboBoxDelegate(QItemDelegate):
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
text = str(editor.currentText())
|
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.close()
|
||||||
editor.deleteLater()
|
editor.deleteLater()
|
||||||
|
|
||||||
|
|
@ -115,16 +139,16 @@ class WeatherParametersTableModel(PamhyrTableModel):
|
||||||
super(WeatherParametersTableModel, self).__init__(data=data, **kwargs)
|
super(WeatherParametersTableModel, self).__init__(data=data, **kwargs)
|
||||||
|
|
||||||
self._data = data
|
self._data = data
|
||||||
print("self._data: ", self._data)
|
self._type = "ND"
|
||||||
|
|
||||||
def _setup_lst(self):
|
def _setup_lst(self):
|
||||||
# self._lst = list(
|
self._lst = self._data.lst
|
||||||
# filter(
|
|
||||||
# lambda ica: ica._deleted is False,
|
def update_tab_spec(self, type="ND"):
|
||||||
# self._data._data
|
# self._data = data
|
||||||
# )
|
self._type = type
|
||||||
# )
|
self._setup_lst()
|
||||||
self._lst = self._data._data
|
self.layoutChanged.emit()
|
||||||
|
|
||||||
def rowCount(self, parent):
|
def rowCount(self, parent):
|
||||||
return len(self._lst)
|
return len(self._lst)
|
||||||
|
|
@ -136,34 +160,21 @@ class WeatherParametersTableModel(PamhyrTableModel):
|
||||||
row = index.row()
|
row = index.row()
|
||||||
column = index.column()
|
column = index.column()
|
||||||
|
|
||||||
if self._headers[column] == "name":
|
if self._headers[column] == "reach":
|
||||||
n = self._lst[row].name
|
reach = self._lst[row].reach
|
||||||
if n is None or n == "":
|
if reach is None:
|
||||||
return self._trad['not_associated']
|
return self._trad['not_associated']
|
||||||
return n
|
return reach.name
|
||||||
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
|
|
||||||
elif self._headers[column] == "start_rk":
|
elif self._headers[column] == "start_rk":
|
||||||
n = self._lst[row].start_rk
|
section = self._lst[row].begin_section
|
||||||
if n is None:
|
if section is None:
|
||||||
return self._trad['not_associated']
|
return self._trad['not_associated']
|
||||||
return n
|
return section.display_name()
|
||||||
elif self._headers[column] == "end_rk":
|
elif self._headers[column] == "end_rk":
|
||||||
n = self._lst[row].end_rk
|
section = self._lst[row].end_section
|
||||||
if n is None:
|
if section is None:
|
||||||
return self._trad['not_associated']
|
return self._trad['not_associated']
|
||||||
return n
|
return section.display_name()
|
||||||
elif self._headers[column] == "value":
|
|
||||||
n = self._lst[row].value
|
|
||||||
if n is None:
|
|
||||||
return self._trad['not_associated']
|
|
||||||
return n
|
|
||||||
return n
|
|
||||||
|
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
||||||
|
|
@ -178,17 +189,32 @@ class WeatherParametersTableModel(PamhyrTableModel):
|
||||||
column = index.column()
|
column = index.column()
|
||||||
|
|
||||||
try:
|
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(
|
self._undo.push(
|
||||||
SetCommandSpec(
|
SetBeginCommand(
|
||||||
self._lst, row, self._headers[column], value
|
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":
|
elif self._headers[column] == "reach":
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
SetCommandSpec(
|
SetEdgeCommand(
|
||||||
self._lst, row, self._headers[column],
|
self._data, row, self._river.edge(value)
|
||||||
self._river.edge(value).id
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -203,7 +229,7 @@ class WeatherParametersTableModel(PamhyrTableModel):
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
AddCommand(
|
AddCommand(
|
||||||
self._data, self._lst, row
|
self._data, self._type, self._lst, row
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ from Model.InitialConditionsAdisTS.InitialConditionsAdisTS \
|
||||||
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSList \
|
from Model.InitialConditionsAdisTS.InitialConditionsAdisTSList \
|
||||||
import InitialConditionsAdisTSList
|
import InitialConditionsAdisTSList
|
||||||
|
|
||||||
|
from Model.River import RiverReach
|
||||||
|
|
||||||
|
|
||||||
class SetCommand(QUndoCommand):
|
class SetCommand(QUndoCommand):
|
||||||
def __init__(self, data, row, column, new_value):
|
def __init__(self, data, row, column, new_value):
|
||||||
|
|
@ -79,88 +81,61 @@ class SetCommand(QUndoCommand):
|
||||||
self._data[self._row].ed = self._new
|
self._data[self._row].ed = self._new
|
||||||
|
|
||||||
|
|
||||||
class SetCommandSpec(QUndoCommand):
|
class SetBeginCommand(QUndoCommand):
|
||||||
def __init__(self, data, row, column, new_value):
|
def __init__(self, wps, index, new_value):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
self._data = data
|
self._wps = wps
|
||||||
self._row = row
|
self._index = index
|
||||||
self._column = column
|
self._old = self._wps.get(self._index).begin_section
|
||||||
|
self._new = new_value
|
||||||
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)
|
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
if self._column == "name":
|
self._wps.get(self._index).begin_section = self._old
|
||||||
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
|
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
if self._column == "name":
|
self._wps.get(self._index).begin_section = self._new
|
||||||
self._data[self._row].name = self._new
|
|
||||||
elif self._column == "reach":
|
|
||||||
self._data[self._row].reach = self._new
|
class SetEndCommand(QUndoCommand):
|
||||||
elif self._column == "start_rk":
|
def __init__(self, wps, index, new_value):
|
||||||
self._data[self._row].start_rk = self._new
|
QUndoCommand.__init__(self)
|
||||||
elif self._column == "end_rk":
|
|
||||||
self._data[self._row].end_rk = self._new
|
self._wps = wps
|
||||||
elif self._column == "concentration":
|
self._index = index
|
||||||
self._data[self._row].concentration = self._new
|
self._old = self._wps.get(self._index).end_section
|
||||||
elif self._column == "eg":
|
self._new = new_value
|
||||||
self._data[self._row].eg = self._new
|
|
||||||
elif self._column == "em":
|
def undo(self):
|
||||||
self._data[self._row].em = self._new
|
self._wps.get(self._index).end_section = self._old
|
||||||
elif self._column == "ed":
|
|
||||||
self._data[self._row].ed = self._new
|
def redo(self):
|
||||||
elif self._column == "rate":
|
self._wps.get(self._index).end_section = self._new
|
||||||
self._data[self._row].rate = 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):
|
class AddCommand(QUndoCommand):
|
||||||
def __init__(self, data, ics_spec, index):
|
def __init__(self, data, type, wps_spec, index):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
self._data = data
|
self._data = data
|
||||||
self._ics_spec = ics_spec
|
self._type = type
|
||||||
|
self._wps_spec = wps_spec
|
||||||
self._index = index
|
self._index = index
|
||||||
self._new = None
|
self._new = None
|
||||||
|
|
||||||
|
|
@ -169,22 +144,22 @@ class AddCommand(QUndoCommand):
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
if self._new is None:
|
if self._new is None:
|
||||||
self._new = self._data.new(self._index)
|
self._new = self._data.new(self._index, self._type)
|
||||||
else:
|
else:
|
||||||
self._data.insert(self._index, self._new)
|
self._data.insert(self._index, self._new)
|
||||||
|
|
||||||
|
|
||||||
class DelCommand(QUndoCommand):
|
class DelCommand(QUndoCommand):
|
||||||
def __init__(self, data, ics_spec, rows):
|
def __init__(self, data, wps_spec, rows):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
self._data = data
|
self._data = data
|
||||||
self._ics_spec = ics_spec
|
self._wps_spec = wps_spec
|
||||||
self._rows = rows
|
self._rows = rows
|
||||||
|
|
||||||
self._ic = []
|
self._ic = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
self._ic.append((row, self._ics_spec[row]))
|
self._ic.append((row, self._wps_spec[row]))
|
||||||
self._ic.sort()
|
self._ic.sort()
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
|
|
|
||||||
|
|
@ -68,15 +68,14 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
_pamhyr_ui = "WeatherParameters"
|
_pamhyr_ui = "WeatherParameters"
|
||||||
_pamhyr_name = "Weather parameters"
|
_pamhyr_name = "Weather parameters"
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, data=None, study=None,
|
def __init__(self, data=None, study=None,
|
||||||
config=None, parent=None):
|
config=None, parent=None):
|
||||||
self._data = []
|
# self._data = []
|
||||||
# self._data.append(data)
|
self._data = data
|
||||||
trad = WeatherParametersTranslate()
|
trad = WeatherParametersTranslate()
|
||||||
|
|
||||||
self.weather_params = [trad.get_dict("weather_parameters")[k] for k in trad.get_dict("weather_parameters").keys()]
|
self.weather_params = [trad.get_dict("weather_parameters")[k] for
|
||||||
print(f"Weather parameters: {self.weather_params}")
|
k in trad.get_dict("weather_parameters").keys()]
|
||||||
name = (
|
name = (
|
||||||
trad[self._pamhyr_name] +
|
trad[self._pamhyr_name] +
|
||||||
" - " + study.name
|
" - " + study.name
|
||||||
|
|
@ -92,14 +91,15 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
|
|
||||||
self._hash_data.append(data)
|
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()
|
self.setup_table()
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
path_icons = os.path.join(self._get_ui_directory(), f"ressources")
|
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():
|
if self._study.is_editable():
|
||||||
editable_headers = self._trad.get_dict("table_headers")
|
editable_headers = self._trad.get_dict("table_headers")
|
||||||
|
|
@ -107,7 +107,7 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
editable_headers = []
|
editable_headers = []
|
||||||
|
|
||||||
self._table = WeatherParametersTableDefaultModel(
|
self._table = WeatherParametersTableDefaultModel(
|
||||||
table_view=table_default,
|
table_view=self.table_default,
|
||||||
table_headers=self._trad.get_dict("table_headers"),
|
table_headers=self._trad.get_dict("table_headers"),
|
||||||
editable_headers=editable_headers,
|
editable_headers=editable_headers,
|
||||||
delegates={},
|
delegates={},
|
||||||
|
|
@ -116,12 +116,15 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
trad=self._trad
|
trad=self._trad
|
||||||
)
|
)
|
||||||
|
|
||||||
table_default.setModel(self._table)
|
self.table_default.setModel(self._table)
|
||||||
table_default.setSelectionBehavior(QAbstractItemView.SelectRows)
|
self.table_default.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
table_default.horizontalHeader().setSectionResizeMode(
|
self.table_default.horizontalHeader().setSectionResizeMode(
|
||||||
QHeaderView.Stretch
|
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")
|
layout = self.find(QVBoxLayout, f"verticalLayout_1")
|
||||||
toolBar = QToolBar()
|
toolBar = QToolBar()
|
||||||
|
|
@ -147,12 +150,14 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
self._delegate_reach = ComboBoxDelegate(
|
self._delegate_reach = ComboBoxDelegate(
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
data=self._study.river,
|
data=self._study.river,
|
||||||
|
weather_param_lst=None,
|
||||||
parent=self,
|
parent=self,
|
||||||
mode="reaches"
|
mode="reaches"
|
||||||
)
|
)
|
||||||
self._delegate_rk = ComboBoxDelegate(
|
self._delegate_rk = ComboBoxDelegate(
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
data=self._study.river,
|
data=self._study.river,
|
||||||
|
weather_param_lst=self._study.river.weather_parameters,
|
||||||
parent=self,
|
parent=self,
|
||||||
mode="rk"
|
mode="rk"
|
||||||
)
|
)
|
||||||
|
|
@ -171,7 +176,7 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
"start_rk": self._delegate_rk,
|
"start_rk": self._delegate_rk,
|
||||||
"end_rk": self._delegate_rk
|
"end_rk": self._delegate_rk
|
||||||
},
|
},
|
||||||
data=self._data,
|
data=self._study.river.weather_parameters,
|
||||||
undo=self._undo_stack,
|
undo=self._undo_stack,
|
||||||
trad=self._trad,
|
trad=self._trad,
|
||||||
river=self._study.river
|
river=self._study.river
|
||||||
|
|
@ -195,6 +200,25 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
)
|
)
|
||||||
self.table_spec.scrollTo(index)
|
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):
|
def index_selected_row(self):
|
||||||
# table = self.find(QTableView, f"tableView")
|
# table = self.find(QTableView, f"tableView")
|
||||||
table = self.table_spec
|
table = self.table_spec
|
||||||
|
|
@ -208,7 +232,7 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
|
|
||||||
def index_selected_rows(self):
|
def index_selected_rows(self):
|
||||||
# table = self.find(QTableView, f"tableView")
|
# table = self.find(QTableView, f"tableView")
|
||||||
table = self.table_spec
|
table = self.table_default
|
||||||
return list(
|
return list(
|
||||||
# Delete duplicate
|
# Delete duplicate
|
||||||
set(
|
set(
|
||||||
|
|
@ -301,7 +325,8 @@ class WeatherParametersWindow(PamhyrWindow):
|
||||||
|
|
||||||
def add(self):
|
def add(self):
|
||||||
rows = self.index_selected_rows()
|
rows = self.index_selected_rows()
|
||||||
if len(self._data[0]._data) == 0 or len(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)
|
self._table_spec.add(0)
|
||||||
else:
|
else:
|
||||||
self._table_spec.add(rows[0])
|
self._table_spec.add(rows[0])
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,27 @@ class WeatherParametersTranslate(MainTranslate):
|
||||||
}
|
}
|
||||||
|
|
||||||
self._sub_dict["table_headers_spec"] = {
|
self._sub_dict["table_headers_spec"] = {
|
||||||
"name": self._dict["name"],
|
|
||||||
"reach": self._dict["reach"],
|
"reach": self._dict["reach"],
|
||||||
"start_rk": _translate("Unit", "Start_RK (m)"),
|
"start_rk": _translate("Unit", "Start_RK (m)"),
|
||||||
"end_rk": _translate("Unit", "End_RK (m)"),
|
"end_rk": _translate("Unit", "End_RK (m)"),
|
||||||
"value": self._dict["value"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self._sub_dict["weather_parameters"] = {
|
self._sub_dict["weather_parameters"] = {
|
||||||
"air_temperature": _translate("WeatherParameters", "Air temperature")
|
"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"),
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue