# Friction.py -- Pamhyr # Copyright (C) 2023-2024 INRAE # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -*- coding: utf-8 -*- import logging from tools import trace, timer from Model.Tools.PamhyrDB import SQLSubModel from numpy import interp logger = logging.getLogger() class Friction(SQLSubModel): _id_cnt = 0 def __init__(self, id: int = -1, name: str = "", status=None): super(Friction, self).__init__() self._status = status if id == -1: self.id = Friction._id_cnt else: self.id = id Friction._id_cnt = max(self.id, Friction._id_cnt+1) self._name = name self._edge = None self._begin_rk = 0.0 self._end_rk = 0.0 self._begin_strickler = None self._end_strickler = None @classmethod def _db_create(cls, execute): execute(""" CREATE TABLE friction( id INTEGER NOT NULL PRIMARY KEY, ind INTEGER NOT NULL, begin_rk REAL NOT NULL, end_rk REAL NOT NULL, reach INTEGER NOT NULL, begin_strickler INTEGER NOT NULL, end_strickler INTEGER NOT NULL, FOREIGN KEY(reach) REFERENCES river_reach(id), FOREIGN KEY(begin_strickler) REFERENCES stricklers(id), FOREIGN KEY(end_strickler) REFERENCES stricklers(id) ) """) return True @classmethod def _db_update(cls, execute, version): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 11: execute("ALTER TABLE friction " + "RENAME COLUMN begin_kp TO begin_rk") execute("ALTER TABLE friction RENAME COLUMN end_kp TO end_rk") return True @classmethod def _db_load(cls, execute, data=None): new = [] reach = data["reach"] status = data["status"] stricklers = data["stricklers"].stricklers table = execute( "SELECT id, ind, begin_rk, end_rk, " + "begin_strickler, end_strickler " + f"FROM friction WHERE reach = {reach.id}" ) for row in table: id = row[0] ind = row[1] # Get stricklers if int(row[4]) == -1: bs = None else: bs = next(filter(lambda s: s.id == row[4], stricklers)) if int(row[5]) == -1: es = None else: es = next(filter(lambda s: s.id == row[5], stricklers)) # Create friction sec = cls(status=status) sec.edge = reach sec.begin_rk = row[2] sec.end_rk = row[3] sec.begin_strickler = bs sec.end_strickler = es new.append((ind, sec)) return new def _db_save(self, execute, data=None): ind = data["ind"] b_s_id = -1 e_s_id = -1 if self._begin_strickler is not None: b_s_id = self._begin_strickler.id if self._end_strickler is not None: e_s_id = self._end_strickler.id execute( "INSERT INTO " + "friction(id, ind, begin_rk, end_rk, " + "reach, begin_strickler, end_strickler) " + "VALUES (" + f"{self.id}, {ind}, " + f"{self._begin_rk}, {self._end_rk}, " + f"{self._edge.id}, " + f"{b_s_id}, {e_s_id}" + ")" ) return True @property def name(self): return self._name @name.setter def name(self, name): self._name = name self._status.modified() @property def edge(self): return self._edge @property def reach(self): return self._edge @edge.setter def edge(self, edge): self._edge = edge if (edge is not None and self._begin_rk == 0.0 and self._end_rk == 0.0): self._begin_rk = self._edge.reach.get_rk_min() self._end_rk = self._edge.reach.get_rk_max() self._status.modified() def has_edge(self): return self._edge is not None def has_coefficient(self): return ( self._begin_strickler is not None ) def is_full_defined(self): return self.has_edge() and self.has_coefficient() @property def begin_rk(self): return self._begin_rk @begin_rk.setter def begin_rk(self, begin_rk): if self._edge is None: self._begin_rk = begin_rk else: _min = self._edge.reach.get_rk_min() _max = self._edge.reach.get_rk_max() if _min <= begin_rk <= _max: self._begin_rk = begin_rk self._status.modified() @property def end_rk(self): return self._end_rk @end_rk.setter def end_rk(self, end_rk): if self._edge is None: self._end_rk = end_rk else: _min = self._edge.reach.get_rk_min() _max = self._edge.reach.get_rk_max() if _min <= end_rk <= _max: self._end_rk = end_rk self._status.modified() def __contains__(self, rk): return self.contains_rk(rk) def contains_rk(self, rk): return ( self._begin_rk <= rk <= self._end_rk ) @property def begin_strickler(self): return self._begin_strickler @begin_strickler.setter def begin_strickler(self, strickler): self._begin_strickler = strickler self._status.modified() @property def end_strickler(self): # return self._end_strickler return self._begin_strickler @end_strickler.setter def end_strickler(self, strickler): self._end_strickler = strickler self._status.modified() def get_friction(self, rk): if not self.contains_rk(rk): return None minor = self.begin_strickler.minor medium = self.begin_strickler.medium # minor = interp(rk, # [self.begin_rk, self.end_rk], # [self.begin_strickler.minor, # self.end_strickler.minor]) # medium = interp(rk, # [self.begin_rk, self.end_rk], # [self.begin_strickler.medium, # self.end_strickler.medium]) return minor, medium