diff --git a/src/Model/Results/Results.py b/src/Model/Results/Results.py
index f44c9c20..dd04dfb6 100644
--- a/src/Model/Results/Results.py
+++ b/src/Model/Results/Results.py
@@ -14,7 +14,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+import struct
import logging
+import itertools
import numpy as np
from copy import deepcopy
@@ -28,12 +30,10 @@ logger = logging.getLogger()
class Results(SQLSubModel):
- _SQL_TABLE = "solver_results"
-
- def __init__(self, study=None, solver=None,
+ def __init__(self, id=-1, study=None, solver=None,
repertory="", name="0"):
super(Results, self).__init__(
- status=study.status,
+ id=id, status=study.status,
owner_scenario=study.status.scenario.id
)
@@ -78,3 +78,122 @@ class Results(SQLSubModel):
self._repertory,
qlog=None,
)
+
+ def timestamps_to_struct(self):
+ ts = self._meta_data["timestamps"]
+ sf = ">" + ''.join(itertools.repeat("d", len(ts)))
+
+ return struct.pack(sf, ts)
+
+ @classmethod
+ def _db_create(cls, execute, ext=""):
+ execute(f"""
+ CREATE TABLE results{ext} (
+ {cls.create_db_add_pamhyr_id()},
+ solver TEXT NOT NULL,
+ study_revision INTEGER NOT NULL,
+ creation_data DATE NOT NULL,
+ nb_timestamps INTEGER NOT NULL,
+ timestamps BLOB NOT NULL,
+ {Scenario.create_db_add_scenario()},
+ {Scenario.create_db_add_scenario_fk()},
+ 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:
+ cls._db_create(execute)
+
+ return cls._update_submodel(execute, version, data)
+
+ @classmethod
+ def _db_load(cls, execute, data=None):
+ new = []
+
+ study = data['study']
+ status = data['status']
+ scenario = data["scenario"]
+ loaded = data['loaded_pid']
+
+ values = execute(
+ "SELECT pamhyr_id, solver_name, solver_type, " +
+ "study_revision, creation_data, nb_timestamps, timestamps, " +
+ "scenario " +
+ "FROM results " +
+ f"WHERE 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)
+ solver = next(it)
+ revision = next(it)
+ creation_date = next(it)
+ nb_timestamps = next(it)
+ timestamps_bytes = next(it)
+ owner_scenario = next(it)
+
+ new_results = cls(
+ id=pid, status=status,
+ owner_scenario=owner_scenario
+ )
+ new_results.set("solver_name", solver_name)
+ new_results.set("solver_type", solver_type)
+ new_results.set("study_revision", revision)
+ new_results.set("creation_date", creation_date)
+
+ sf = ">" + ''.join(itertools.repeat("d", len(nb_timestamps)))
+ ts = struct.unpack(sf, timestamp_bytes)
+ new_results.set("timestamps", ts)
+
+ new_results._river = River._db_load(execute, data)
+
+ loaded.add(pid)
+ new.append(new_results)
+
+ return new
+
+ def _db_save(self, execute, data=None):
+ execute(
+ "DELETED FROM results " +
+ f"WHERE scenario = {self._owner_scenario}"
+ )
+ execute(
+ "DELETED FROM results_data " +
+ f"WHERE scenario = {self._owner_scenario}"
+ )
+
+ pid = self._pamhyr_id
+ if self._solver is None:
+ solver_name = self.get("solver_name")
+ solver_type = self.get("solver_type")
+ else:
+ solver_name = self._solver._name
+ solver_type = self._solver._type
+
+ ts = self.get("timestamps")
+ sf = ">" + ''.join(itertools.repeat("d", len(ts)))
+
+ execute(
+ "INSERT INTO " +
+ "results (pamhyr_id, solver_name, solver_type, " +
+ "study_revision, creation_data, nb_timestamps, timestamps, " +
+ "scenario) VALUES (?, ?, ?, ?, ?, ?, ?)",
+ self._pamhyr_id, solver_name, solver_type,
+ self._owner_scenario.revision, self.get("creation_data"),
+ len(ts), struct.pack(sf, ts), self._owner_scenario
+ )
+
+ data["result"] = self._pamhyr_id
+ self._river._db_save(execute, data)
+
+ return True
diff --git a/src/Model/Results/River/River.py b/src/Model/Results/River/River.py
index d068ec1b..7f89a7af 100644
--- a/src/Model/Results/River/River.py
+++ b/src/Model/Results/River/River.py
@@ -14,15 +14,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+import struct
import logging
+import itertools
+from functools import reduce
from datetime import datetime
+from Model.Tools.PamhyrDB import SQLSubModel
+
logger = logging.getLogger()
-class Profile(object):
+class Profile(SQLSubModel):
def __init__(self, profile, study):
+ super(Profile, self).__init__(
+ id=-1, status=study.status,
+ owner_scenario=study.status.scenario.id
+ )
+
self._study = study
self._profile = profile # Source profile in the study
self._data = {} # Dict of dict {: {: , ...}, ...}
@@ -65,9 +75,122 @@ class Profile(object):
def has_sediment(self):
return any(map(lambda ts: "sl" in self._data[ts], self._data))
+ @classmethod
+ def _db_create(cls, execute, ext=""):
+ execute(f"""
+ CREATE TABLE results_data{ext}(
+ {cls.create_db_add_pamhyr_id()},
+ result INTEGER NOT NULL,
+ key TEXT NOT NULL,
+ reach INTEGER NOT NULL,
+ section INTEGER NOT NULL,
+ len_data INTEGER NOT NULL,
+ data BLOB NOT NULL,
+ {Scenario.create_db_add_scenario()},
+ {Scenario.create_db_add_scenario_fk()},
+ FOREIGN KEY(result) REFERENCES results(pamhyr_id),
+ FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
+ FOREIGN KEY(section)
+ REFERENCES geometry_profileXYZ(pamhyr_id),
+ PRIMARY KEY(pamhyr_id, result, key, scenario)
+ )
+ """)
-class Reach(object):
+ if ext == "_tmp":
+ return True
+
+ 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:
+ cls._db_create(execute)
+
+ return cls._update_submodel(execute, version, data)
+
+ @classmethod
+ def _db_load(cls, execute, data=None):
+ new = []
+
+ study = data['study']
+ status = data['status']
+ scenario = data["scenario"]
+ loaded = data['loaded_pid']
+ timestamps = data['timestamps']
+
+ values = execute(
+ "SELECT pamhyr_id, result, key, " +
+ "reach, section, len_data, data, scenario " +
+ "FROM results_data " +
+ f"WHERE scenario = {scenario.id} " +
+ f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
+ )
+
+ for v in values:
+ it = iter(v)
+
+ pid = next(it)
+ result = next(it)
+ key = next(it)
+ reach = next(it)
+ section = next(it)
+ len_data = next(it)
+ data = next(it)
+ owner_scenario = next(it)
+
+ new_data = cls(
+ id=pid, status=status,
+ owner_scenario=owner_scenario
+ )
+
+ sf = ">" + ''.join(itertools.repeat("f", len_data))
+ values = struct.unpack(sf, data)
+
+ for timestamp, value in zip(timestamps, values):
+ new_data.set(timestamp, key, value)
+
+ loaded.add(pid)
+ new.append(new_data)
+
+ return new
+
+ def get_keys(self):
+ return reduce(
+ lambda acc, ts: acc.union(d[ts].keys())
+ )
+
+ def _db_save(self, execute, data=None):
+ pid = self._pamhyr_id
+ result = data["result"]
+
+ for key in self.get_keys():
+ data = self.get_key(key)
+
+ sf = ">" + ''.join(itertools.repeat("f", len(data)))
+ data_bytes = struct.pack(sf, data)
+
+ execute(
+ "INSERT INTO " +
+ "results_data (pamhyr_id, result, , " +
+ "study_revision, key, len_data, data, " +
+ "scenario) VALUES (?, ?, ?, ?, ?, ?, ?)",
+ pid, result, self._owner_scenario.revision,
+ key, len(data), data_bytes,
+ self._owner_scenario
+ )
+
+ return True
+
+
+class Reach(SQLSubModel):
def __init__(self, reach, study):
+ super(Reach, self).__init__(
+ id=-1, status=study.status,
+ owner_scenario=study.status.scenario.id
+ )
+
self._study = study
self._reach = reach # Source reach in the study
self._profiles = list(
@@ -101,9 +224,31 @@ class Reach(object):
def has_sediment(self):
return any(map(lambda profile: profile.has_sediment(), self._profiles))
+ @classmethod
+ def _db_create(cls, execute, ext=""):
+ return cls._create_submodel(execute)
-class River(object):
+ @classmethod
+ def _db_update(cls, execute, version, data=None):
+ return cls._update_submodel(execute, version, data)
+
+ @classmethod
+ def _db_load(cls, execute, data=None):
+ return cls._db_load(execute, data)
+
+ def _db_save(self, execute, data=None):
+ for profile in self._profiles:
+ data["profile"] = profile.geometry.pamhyr_id
+ profile._db_save(execute, data)
+
+
+class River(SQLSubModel):
def __init__(self, study):
+ super(River, self).__init__(
+ id=-1, status=study.status,
+ owner_scenario=study.status.scenario.id
+ )
+
self._study = study
# Dict with timestamps as key
@@ -137,3 +282,20 @@ class River(object):
self._reachs
)
)
+
+ @classmethod
+ def _db_create(cls, execute, ext=""):
+ return cls._create_submodel(execute)
+
+ @classmethod
+ def _db_update(cls, execute, version, data=None):
+ return cls._update_submodel(execute, version, data)
+
+ @classmethod
+ def _db_load(cls, execute, data=None):
+ return cls._db_load(execute, data)
+
+ def _db_save(self, execute, data=None):
+ for reach in self._reachs:
+ data["reach"] = reach.geometry.pamhyr_id
+ reach._db_save(execute, data)