diff --git a/src/Model/SolverParameters/SolverParametersList.py b/src/Model/SolverParameters/SolverParametersList.py index 5837d552..eae18bf2 100644 --- a/src/Model/SolverParameters/SolverParametersList.py +++ b/src/Model/SolverParameters/SolverParametersList.py @@ -21,75 +21,34 @@ from tools import trace, timer from Solver.Solvers import solver_type_list from Model.Scenario import Scenario +from Model.Tools.PamhyrDB import SQLSubModel from Model.Tools.PamhyrList import PamhyrModelList -class Parameter(): - def __init__(self, +class Parameter(SQLSubModel): + def __init__(self, id: int = -1, name="", value="", - status=None): - self._status = status + status=None, owner_scenario=-1): + super(Parameter, self).__init__( + id=id, status=status, + owner_scenario=owner_scenario + ) self._name = name self._value = value - @property - def name(self): - return self._name - - @property - def value(self): - return self._value - - def __getitem__(self, key): - if key == "name": - return self._name - elif key == "value": - return self._value - - return None - - def __setitem__(self, key, value): - if key == "name": - self._name = str(value) - elif key == "value": - self._value = str(value) - - self._status.modified() - @classmethod - def from_tuple(cls, data, status): - new = cls(status=status) - new["name"] = data[0] - new["value"] = data[1] - - return new - - -class SolverParametersList(PamhyrModelList): - def __init__(self, solver_type=None, status=None): - super(SolverParametersList, self).__init__() - - self._status = status - self._solver = solver_type - self._lst = list( - map( - lambda t: Parameter.from_tuple(t, self._status), - solver_type.default_parameters() - ) - ) - - @classmethod - def _db_create(cls, execute): + def _db_create(cls, execute, ext=""): execute(f""" - CREATE TABLE solver_parameter( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + CREATE TABLE solver_parameter{ext} ( + pamhyr_id INTEGER NOT NULL, ind INTEGER NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL, solver TEXT NOT NULL, {Scenario.create_db_add_scenario()}, - {Scenario.create_db_add_scenario_fk()} + {Scenario.create_db_add_scenario_fk()}, + PRIMARY KEY(pamhyr_id, scenario) ) """) @@ -130,7 +89,7 @@ class SolverParametersList(PamhyrModelList): cls._db_update_to_0_0_7(execute, insert) if release < 14: - cls._db_update_to_0_0_14(execute) + cls._db_update_to_0_0_14(execute, data) return cls._update_submodel(execute, version, data) @@ -193,15 +152,153 @@ class SolverParametersList(PamhyrModelList): ind += 1 @classmethod - def _db_update_to_0_0_14(cls, execute): - Scenario.update_db_add_scenario(execute, "solver_parameter") + def _db_update_to_0_0_14(cls, execute, data): + table = "solver_parameter" + + cls.update_db_add_pamhyr_id(execute, table, data) + Scenario.update_db_add_scenario(execute, table) + + cls._db_create(execute, ext="_tmp") + execute( + f"INSERT INTO {table}_tmp " + + "(pamhyr_id, ind, name, value, solver, scenario) " + + "SELECT pamhyr_id, ind, name, value, solver, scenario " + + f"FROM {table}" + ) + + execute(f"DROP TABLE {table}") + execute(f"ALTER TABLE {table}_tmp RENAME TO {table}") @classmethod def _db_load(cls, execute, data=None): status = data["status"] + scenario = data["scenario"] + loaded = data['loaded_pid'] + solver = data['solver'] + + new = [] + if scenario is None: + return new + + table = execute( + "SELECT pamhyr_id, ind, name, value, scenario " + + "FROM solver_parameter " + + f"WHERE solver = '{solver}' " + + f"AND scenario = {scenario.id} " + + f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})" + ) + + for row in table: + it = iter(row) + + pid = next(it) + ind = next(it) + name = next(it) + value = next(it) + owner = next(it) + + new.append( + ( + ind, + cls( + id=pid, name=name, value=value, + status=status, owner_scenario=owner + ) + ) + ) + + loaded.add(pid) + + data["scenario"] = scenario.parent + new += cls._db_load(execute, data) + data["scenario"] = scenario + + return new + + def _db_save(self, execute, data=None): + ind = data["ind"] + solver = data["solver"] + + execute( + "INSERT INTO " + + "solver_parameter(pamhyr_id, ind, " + + "name, value, solver, scenario) " + + "VALUES (" + + f"{self.pamhyr_id}, " + + f"{ind}, " + + f"'{self._db_format(self.name)}', " + + f"'{self._db_format(self.value)}', " + + f"'{self._db_format(solver)}', " + + f"{self._status.scenario_id}" + + ")" + ) + + return True + + @property + def name(self): + return self._name + + @property + def value(self): + return self._value + + def __getitem__(self, key): + if key == "name": + return self._name + elif key == "value": + return self._value + + return None + + def __setitem__(self, key, value): + if key == "name": + self._name = str(value) + elif key == "value": + self._value = str(value) + + self.modified() + + @classmethod + def from_tuple(cls, data, status): + new = cls(status=status) + new["name"] = data[0] + new["value"] = data[1] + + return new + + +class SolverParametersList(PamhyrModelList): + _sub_classes = [Parameter] + + def __init__(self, solver_type=None, status=None): + super(SolverParametersList, self).__init__() + + self._status = status + self._solver = solver_type + self._lst = list( + map( + lambda t: Parameter.from_tuple(t, self._status), + solver_type.default_parameters() + ) + ) + + @classmethod + def _db_create(cls, execute, ext=""): + return cls._create_submodel(execute) + + @classmethod + def _db_load(cls, execute, data=None): + status = data["status"] + scenario = data["scenario"] + loaded = data['loaded_pid'] + solvers = execute("SELECT DISTINCT solver FROM solver_parameter") new = {} + if scenario is None: + return new + for solver in solvers: solver = solver[0] if solver not in solver_type_list: @@ -210,18 +307,10 @@ class SolverParametersList(PamhyrModelList): st = solver_type_list[solver] n = cls(solver_type=st, status=status) - table = execute( - "SELECT ind, name, value " + - "FROM solver_parameter " + - f"WHERE solver = '{solver}'" - ) + data['solver'] = solver + lst = Parameter._db_load(execute, data) - for row in table: - ind = row[0] - name = row[1] - value = row[2] - - n.set_value(name, value) + n._lst = list(map(lambda t: t[1], sorted(lst))) new[solver] = n @@ -231,22 +320,16 @@ class SolverParametersList(PamhyrModelList): t = self._solver._type execute( "DELETE FROM solver_parameter " + - f"WHERE solver = '{t}'" + f"WHERE solver = '{t}' " + + f"AND scenario = {self._status.scenario_id}" ) + data["solver"] = t + ind = 0 for param in self._lst: - sql = ( - "INSERT INTO " + - "solver_parameter(ind, name, value, solver) " + - "VALUES (" + - f"{ind}, " + - f"'{self._db_format(param.name)}', " + - f"'{self._db_format(param.value)}', " + - f"'{self._db_format(t)}'" + - ")" - ) - execute(sql) + data["ind"] = ind + param._db_save(execute, data) ind += 1 return True @@ -271,9 +354,9 @@ class SolverParametersList(PamhyrModelList): def set(self, index, new): self._lst[index] = new - self._status.modified() + new.modified() - def set_value(self, key, value): + def set_value(self, pid, key, value, owner): for p in self._lst: if p["name"] == key: p["value"] = value @@ -282,9 +365,11 @@ class SolverParametersList(PamhyrModelList): self._lst.append( Parameter( + id=-1, name=key, value=value, - status=self._status + status=self._status, + owner_scenario=self._status.scenario_id ) ) self._status.modified()