mirror of https://gitlab.com/pamhyr/pamhyr2
Results: Add TableData pamhyr object for np table.
parent
1adf24ce77
commit
e8f1f0ac43
|
|
@ -157,8 +157,185 @@ class AdditionalData(SQLSubModel):
|
|||
return True
|
||||
|
||||
|
||||
class TableData(SQLSubModel):
|
||||
_sub_classes = []
|
||||
|
||||
def __init__(self, id=-1, study=None,
|
||||
legend="", data=None,
|
||||
owner_scenario=-1):
|
||||
super(TableData, self).__init__(
|
||||
id=id, status=study.status,
|
||||
owner_scenario=owner_scenario
|
||||
)
|
||||
|
||||
self._study = study
|
||||
self._legend = legend
|
||||
self._data = data
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._data
|
||||
|
||||
@classmethod
|
||||
def _db_create(cls, execute, ext=""):
|
||||
execute(f"""
|
||||
CREATE TABLE results_table_data{ext} (
|
||||
{cls.create_db_add_pamhyr_id()},
|
||||
result INTEGER NOT NULL,
|
||||
legend TEXT NOT NULL,
|
||||
unit TEXT NOT NULL,
|
||||
data_shape_x INTEGER NOT NULL,
|
||||
data_shape_y INTEGER NOT NULL,
|
||||
data_shape_z INTEGER DEFAULT -1,
|
||||
data BLOB NOT NULL,
|
||||
{Scenario.create_db_add_scenario()},
|
||||
{Scenario.create_db_add_scenario_fk()},
|
||||
FOREIGN KEY(result) REFERENCES results(pamhyr_id),
|
||||
PRIMARY KEY(pamhyr_id, result, legend, scenario)
|
||||
)
|
||||
""")
|
||||
|
||||
if ext != "":
|
||||
return True
|
||||
|
||||
return cls._create_submodel(execute)
|
||||
|
||||
@classmethod
|
||||
def _db_update(cls, execute, version, data=None):
|
||||
major, minor, release = version.strip().split(".")
|
||||
create = False
|
||||
|
||||
if major == "0" and int(minor) == 2:
|
||||
if int(release) < 7 and not create:
|
||||
cls._db_create(execute)
|
||||
create = True
|
||||
|
||||
return cls._update_submodel(execute, version, data)
|
||||
|
||||
@classmethod
|
||||
def _db_load(cls, execute, data=None):
|
||||
res = {}
|
||||
|
||||
study = data['study']
|
||||
status = data['status']
|
||||
scenario = data["scenario"]
|
||||
result = data["result"]
|
||||
rid = data["result_pid"]
|
||||
|
||||
table = execute(
|
||||
"SELECT pamhyr_id, " +
|
||||
"legend, unit, " +
|
||||
"data_shape_x, data_shape_y, data_shape_z, " +
|
||||
"data, " +
|
||||
"scenario " +
|
||||
"FROM results_table_data " +
|
||||
f"WHERE scenario = {scenario.id} " +
|
||||
f"AND result = {rid}"
|
||||
)
|
||||
|
||||
for v in table:
|
||||
it = iter(v)
|
||||
|
||||
pid = next(it)
|
||||
legend = next(it)
|
||||
unit = next(it)
|
||||
data_shape_x = next(it)
|
||||
data_shape_y = next(it)
|
||||
data_shape_z = next(it)
|
||||
data = next(it)
|
||||
owner_scenario = next(it)
|
||||
|
||||
dtype = cls._unit_to_dtype(unit)
|
||||
|
||||
np_data = np.frombuffer(data, dtype=dtype)
|
||||
if data_shape_y == -1:
|
||||
np_data = np.reshape(np_data, data_shape_x)
|
||||
elif data_shape_z == -1:
|
||||
np_data = np.reshape(np_data, (data_shape_x,
|
||||
data_shape_y))
|
||||
else:
|
||||
np_data = np.reshape(np_data, (data_shape_x,
|
||||
data_shape_y,
|
||||
data_shape_z))
|
||||
|
||||
new_table = cls(study=study,
|
||||
legend=legend, data=np_data,
|
||||
owner_scenario=owner_scenario)
|
||||
|
||||
res[legend] = new_table
|
||||
|
||||
return res
|
||||
|
||||
def _db_save(self, execute, data=None):
|
||||
if self._status.scenario.id != self._owner_scenario:
|
||||
return
|
||||
|
||||
shape_x = -1
|
||||
shape_y = -1
|
||||
shape_z = -1
|
||||
shape = self._data.shape
|
||||
|
||||
if len(shape) == 2:
|
||||
shape_x, shape_y = shape
|
||||
elif len(shape == 1):
|
||||
shape_x, = shape
|
||||
elif len(shape == 3):
|
||||
shape_x, shape_y, shape_z = shape
|
||||
else:
|
||||
logger.error(
|
||||
f"Failed to parse numpy shape: {shape}"
|
||||
)
|
||||
|
||||
execute(
|
||||
"INSERT INTO " +
|
||||
"results_table_data (pamhyr_id, result, " +
|
||||
"legend, unit, " +
|
||||
"data_shape_x, data_shape_y, data_shape_z, " +
|
||||
"data, " +
|
||||
"scenario) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
self._pamhyr_id, data["result"],
|
||||
self._legend, self._dtype_to_unit(self._data.dtype),
|
||||
shape_x, shape_y, shape_z,
|
||||
self._data,
|
||||
self._owner_scenario
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _unit_to_dtype(cls, unit):
|
||||
t = {
|
||||
"i32": np.int32, "i64": np.int64,
|
||||
"u32": np.uint32, "u64": np.uint64,
|
||||
"f32": np.float32, "f64": np.float64,
|
||||
}
|
||||
|
||||
return t[unit]
|
||||
|
||||
def _dtype_to_unit(self, dtype):
|
||||
t = {
|
||||
np.dtype(np.int32): "i32", np.dtype(np.int64): "i64",
|
||||
np.dtype(np.uint32): "u32", np.dtype(np.uint64): "u64",
|
||||
np.dtype(np.float32): "f32", np.dtype(np.float64): "f64",
|
||||
}
|
||||
|
||||
return t[dtype]
|
||||
|
||||
def table(self):
|
||||
return self._data
|
||||
|
||||
def __len__(self):
|
||||
return len(self._data)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, tuple):
|
||||
return self._data[key[0], key[1]]
|
||||
|
||||
self._date[key]
|
||||
|
||||
|
||||
class Results(SQLSubModel):
|
||||
_sub_classes = [River, AdditionalData]
|
||||
_sub_classes = [River, TableData, AdditionalData]
|
||||
|
||||
def __init__(self, id=-1, study=None, solver=None,
|
||||
repertory="", name="0"):
|
||||
|
|
@ -179,8 +356,11 @@ class Results(SQLSubModel):
|
|||
"creation_date": datetime.now(),
|
||||
"study_revision": study.status.version,
|
||||
"additional_data": [],
|
||||
"table": {},
|
||||
}
|
||||
|
||||
self._ts_index = {}
|
||||
|
||||
if solver is not None:
|
||||
self.set("solver_type", solver._type)
|
||||
|
||||
|
|
@ -221,6 +401,10 @@ class Results(SQLSubModel):
|
|||
def get_timestamp_id(self, ts):
|
||||
return self._ts_index[ts]
|
||||
|
||||
def compute_timestamp_index(self):
|
||||
for i, ts in enumerate(self._meta_data["timestamps"]):
|
||||
self._ts_index[ts] = i
|
||||
|
||||
def reload(self):
|
||||
return self._solver.results(
|
||||
self._study,
|
||||
|
|
@ -318,11 +502,19 @@ class Results(SQLSubModel):
|
|||
new_results.set("study_revision", revision)
|
||||
new_results.set("creation_date", creation_date)
|
||||
|
||||
data["result_pid"] = pid
|
||||
data["result"] = new_results
|
||||
|
||||
table_data = TableData._db_load(execute, data)
|
||||
new_results.set("table", table_data)
|
||||
|
||||
sf = ">" + ''.join(itertools.repeat("d", nb_timestamps))
|
||||
ts = struct.unpack(sf, timestamps_bytes)
|
||||
new_results.set("timestamps", ts)
|
||||
|
||||
data["timestamps"] = sorted(ts)
|
||||
new_results.compute_timestamp_index()
|
||||
|
||||
data["parent"] = new_results
|
||||
new_results._river = River._db_load(execute, data)
|
||||
|
||||
|
|
@ -331,6 +523,20 @@ class Results(SQLSubModel):
|
|||
AdditionalData._db_load(execute, data)
|
||||
)
|
||||
|
||||
# Update global index
|
||||
i = 0
|
||||
for reach in new_results._river.reachs:
|
||||
nb = len(reach.profiles)
|
||||
reach.set_global_index(range(i, i + nb + 1))
|
||||
i += nb
|
||||
|
||||
if "Z" in table_data:
|
||||
for ts in data["timestamps"]:
|
||||
new_results._river.update_water_limits(
|
||||
ts,
|
||||
table_data["Z"][new_results.get_timestamp_id(ts), :]
|
||||
)
|
||||
|
||||
yield (solver_type, new_results)
|
||||
|
||||
def _db_save_clear(self, execute, solver_type, data=None):
|
||||
|
|
@ -353,6 +559,11 @@ class Results(SQLSubModel):
|
|||
f"WHERE scenario = {self._owner_scenario} " +
|
||||
f"AND result = {pid}"
|
||||
)
|
||||
execute(
|
||||
"DELETE FROM results_table_data " +
|
||||
f"WHERE scenario = {self._owner_scenario} " +
|
||||
f"AND result = {pid}"
|
||||
)
|
||||
execute(
|
||||
"DELETE FROM results_add_data " +
|
||||
f"WHERE scenario = {self._owner_scenario} " +
|
||||
|
|
@ -396,7 +607,19 @@ class Results(SQLSubModel):
|
|||
data["result"] = self._pamhyr_id
|
||||
self._river._db_save(execute, data)
|
||||
|
||||
tables = self.get("table")
|
||||
for legend in tables:
|
||||
tables[legend]._db_save(execute, data)
|
||||
|
||||
for add_data in self.get("additional_data"):
|
||||
add_data._db_save(execute, data)
|
||||
|
||||
return True
|
||||
|
||||
def new_table_data(self, legend, data):
|
||||
return TableData(
|
||||
study=self._study,
|
||||
legend=legend,
|
||||
data=data,
|
||||
owner_scenario=self._owner_scenario
|
||||
)
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ class Profile(SQLSubModel):
|
|||
|
||||
@classmethod
|
||||
def _db_load(cls, execute, data=None):
|
||||
new = {}
|
||||
status = data['status']
|
||||
|
||||
parent = data['parent']
|
||||
|
|
@ -148,6 +147,8 @@ class Profile(SQLSubModel):
|
|||
loaded = data['loaded_pid']
|
||||
timestamps = data['timestamps']
|
||||
|
||||
new = cls(profile, study, parent)
|
||||
|
||||
values = execute(
|
||||
"SELECT pamhyr_id, result, key, " +
|
||||
"len_data, data, scenario " +
|
||||
|
|
@ -167,12 +168,6 @@ class Profile(SQLSubModel):
|
|||
data = next(it)
|
||||
owner_scenario = next(it)
|
||||
|
||||
if profile not in new:
|
||||
new_data = cls(profile, study, parent)
|
||||
new[profile] = new_data
|
||||
else:
|
||||
new_data = new[profile]
|
||||
|
||||
if key in ["Z", "Q", "V"]:
|
||||
sf = ">" + ''.join(itertools.repeat("f", len_data))
|
||||
len_values = len(values)
|
||||
|
|
@ -185,11 +180,11 @@ class Profile(SQLSubModel):
|
|||
)
|
||||
|
||||
for timestamp, value in zip(timestamps, values):
|
||||
new_data.set(timestamp, key, value)
|
||||
new.set(timestamp, key, value)
|
||||
if key == "Z":
|
||||
new_data.update_water_limits(timestamp, value)
|
||||
new.update_water_limits(timestamp, value)
|
||||
|
||||
return list(new.values())
|
||||
return new
|
||||
|
||||
@classmethod
|
||||
def _db_load_data_sl_format(cls, values, len_data, timestamps):
|
||||
|
|
@ -361,6 +356,10 @@ class Reach(SQLSubModel):
|
|||
for i, p in enumerate(self._profiles):
|
||||
self._buffers[key][:, i] = p.get_key(key)
|
||||
|
||||
def update_water_limits(self, timestamp, z_data):
|
||||
for profile, z in zip(self._profiles, z_data):
|
||||
profile.update_water_limits(timestamp, z)
|
||||
|
||||
@classmethod
|
||||
def _db_create(cls, execute, ext=""):
|
||||
return cls._create_submodel(execute)
|
||||
|
|
@ -380,7 +379,7 @@ class Reach(SQLSubModel):
|
|||
|
||||
for i, profile in enumerate(reach.profiles):
|
||||
data["profile"] = profile
|
||||
new_reach._profiles += Profile._db_load(execute, data)
|
||||
new_reach._profiles += [Profile._db_load(execute, data)]
|
||||
|
||||
return new_reach
|
||||
|
||||
|
|
@ -435,6 +434,15 @@ class River(SQLSubModel):
|
|||
)
|
||||
)
|
||||
|
||||
def update_water_limits(self, timestamp, data):
|
||||
for reach in self._reachs:
|
||||
ind = reach.global_index
|
||||
|
||||
reach.update_water_limits(
|
||||
timestamp,
|
||||
data[ind[0]:ind[1]]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _db_create(cls, execute, ext=""):
|
||||
return cls._create_submodel(execute)
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ logger = logging.getLogger()
|
|||
|
||||
|
||||
class Study(SQLModel):
|
||||
_version = "0.2.6"
|
||||
_version = "0.2.7"
|
||||
|
||||
_sub_classes = [
|
||||
Scenario,
|
||||
|
|
|
|||
|
|
@ -1206,6 +1206,12 @@ class Mage8(Mage):
|
|||
j += 1
|
||||
|
||||
table["V"] = velocity_arr
|
||||
|
||||
for legend in table:
|
||||
table[legend] = results.new_table_data(
|
||||
legend, table[legend]
|
||||
)
|
||||
|
||||
results.set("table", table)
|
||||
|
||||
logger.info(f"read_bin: ... end with {len(ts)} timestamp read")
|
||||
|
|
|
|||
Loading…
Reference in New Issue