pamhyr: Add just-in-time database geometry loading.

setup.py
Pierre-Antoine Rouby 2023-10-10 15:17:53 +02:00
parent a603c3a63f
commit ab9ebc6400
9 changed files with 140 additions and 77 deletions

View File

@ -85,9 +85,7 @@ class Friction(SQLSubModel):
sec.begin_strickler = bs sec.begin_strickler = bs
sec.end_strickler = es sec.end_strickler = es
new[ind] = sec yield ind, sec
return new
def _sql_save(self, execute, data = None): def _sql_save(self, execute, data = None):
ind = data["ind"] ind = data["ind"]

View File

@ -68,6 +68,26 @@ class FrictionList(PamhyrModelList):
return ok return ok
def _get_frictions_list(self):
# Frictions list generator is type (int, Point) with the first
# element the index of the Point in list
return list(
map(
lambda p: p[1],
sorted(
self._lst,
key = lambda p: p[0]
)
)
)
@property
def lst(self):
if not isinstance(self._lst, list):
self._lst = self._get_frictions_list()
return self._lst
@property @property
def frictions(self): def frictions(self):
return self.lst return self.lst

View File

@ -70,8 +70,6 @@ class PointXYZ(Point, SQLSubModel):
@classmethod @classmethod
def _sql_load(cls, execute, data = None): def _sql_load(cls, execute, data = None):
points = []
status = data["status"] status = data["status"]
profile = data["profile"] profile = data["profile"]
@ -81,10 +79,6 @@ class PointXYZ(Point, SQLSubModel):
f"WHERE profile = {profile.id}" f"WHERE profile = {profile.id}"
) )
# Create points list
for _ in table:
points.append(None)
# Fill points list with new point # Fill points list with new point
for row in table: for row in table:
ind = row[0] ind = row[0]
@ -111,9 +105,7 @@ class PointXYZ(Point, SQLSubModel):
) )
) )
points[ind] = new yield ind, new
return points
def _sql_save(self, execute, data = None): def _sql_save(self, execute, data = None):
profile = data["profile"] profile = data["profile"]

View File

@ -57,18 +57,34 @@ class Profile(object):
self._profile_type = _type self._profile_type = _type
def __len__(self): def __len__(self):
return len(self._points) return len(self.points)
@property @property
def number_points(self): def number_points(self):
return len(self._points) return len(self.points)
def _get_points_list(self):
# Points list generator is type (int, Point) with the first
# element the index of the Point in list
return list(
map(
lambda p: p[1],
sorted(
self._points,
key = lambda p: p[0]
)
)
)
@property @property
def points(self): def points(self):
return self._points.copy() if not isinstance(self._points, list):
self._points = self._get_points_list()
return self._points
def point(self, index): def point(self, index):
return self._points[index] return self.points[index]
@property @property
def reach(self): def reach(self):
@ -115,7 +131,7 @@ class Profile(object):
@property @property
def nb_points(self): def nb_points(self):
return len(self._points) return len(self.points)
@property @property
def kp(self): def kp(self):
@ -170,8 +186,8 @@ class Profile(object):
self._status.modified() self._status.modified()
def point(self, i:int): def point(self, i:int):
if i < len(self._points): if i < len(self.points):
return self._points[i] return self.points[i]
return None return None
@ -181,7 +197,7 @@ class Profile(object):
Returns: Returns:
The list of named point The list of named point
""" """
return [point for point in self._points return [point for point in self.points
if point.point_is_named()] if point.point_is_named()]
@ -195,7 +211,7 @@ class Profile(object):
Returns: Returns:
Nothing. Nothing.
""" """
self._points.insert(index, point) self.points.insert(index, point)
self._status.modified() self._status.modified()
@ -218,7 +234,7 @@ class Profile(object):
) )
) )
self._points = list( self.points = list(
filter( filter(
lambda p: p not in points, lambda p: p not in points,
self.points self.points
@ -235,7 +251,7 @@ class Profile(object):
Returns: Returns:
Nothing. Nothing.
""" """
self._points = list( self.points = list(
filter( filter(
lambda p: p not in points, lambda p: p not in points,
self.points self.points
@ -246,10 +262,10 @@ class Profile(object):
# Move # Move
def move_up_point(self, index: int): def move_up_point(self, index: int):
if index < len(self._points): if index < len(self.points):
next = index - 1 next = index - 1
p = self._points p = self.points
p[index], p[next] = p[next], p[index] p[index], p[next] = p[next], p[index]
self._status.modified() self._status.modified()
@ -257,7 +273,7 @@ class Profile(object):
if index >= 0: if index >= 0:
prev = index + 1 prev = index + 1
p = self._points p = self.points
p[index], p[prev] = p[prev], p[index] p[index], p[prev] = p[prev], p[index]
self._status.modified() self._status.modified()
@ -271,8 +287,8 @@ class Profile(object):
elif column == 'z': elif column == 'z':
predicate = lambda p: p.z predicate = lambda p: p.z
self._points = sorted( self.points = sorted(
self._points, self.points,
key=predicate, key=predicate,
reverse=is_reversed reverse=is_reversed
) )
@ -280,10 +296,10 @@ class Profile(object):
@timer @timer
def sort_with_indexes(self, indexes: list): def sort_with_indexes(self, indexes: list):
if len(self._points) != len(indexes): if len(self.points) != len(indexes):
logger.critical("Indexes list do not correspond to point list") logger.critical("Indexes list do not correspond to point list")
self._points = list( self.points = list(
map( map(
lambda x: x[1], lambda x: x[1],
sorted( sorted(

View File

@ -16,6 +16,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging
import numpy as np import numpy as np
from typing import List from typing import List
@ -27,6 +28,8 @@ from Model.Geometry.Profile import Profile
from Model.Geometry.PointXYZ import PointXYZ from Model.Geometry.PointXYZ import PointXYZ
from Model.Geometry.Vector_1d import Vector1d from Model.Geometry.Vector_1d import Vector1d
logger = logging.getLogger()
class ProfileXYZ(Profile, SQLSubModel): class ProfileXYZ(Profile, SQLSubModel):
_sub_classes = [ _sub_classes = [
PointXYZ, PointXYZ,
@ -108,7 +111,7 @@ class ProfileXYZ(Profile, SQLSubModel):
table = execute( table = execute(
"SELECT id, ind, name, kp, num, code1, code2, sl " + "SELECT id, ind, name, kp, num, code1, code2, sl " +
"FROM geometry_profileXYZ " + "FROM geometry_profileXYZ " +
f"WHERE reach = {reach}" f"WHERE reach = {reach.id}"
) )
for _ in table: for _ in table:
@ -145,9 +148,11 @@ class ProfileXYZ(Profile, SQLSubModel):
data["profile"] = new data["profile"] = new
new._points = PointXYZ._sql_load(execute, data) new._points = PointXYZ._sql_load(execute, data)
profiles[ind] = new yield ind, new
return profiles # profiles[ind] = new
# return profiles
def _sql_save(self, execute, data = None): def _sql_save(self, execute, data = None):
ok = True ok = True
@ -170,7 +175,7 @@ class ProfileXYZ(Profile, SQLSubModel):
execute(f"DELETE FROM geometry_pointXYZ WHERE profile = {self.id}") execute(f"DELETE FROM geometry_pointXYZ WHERE profile = {self.id}")
ind = 0 ind = 0
for point in self._points: for point in self.points:
data["ind"] = ind data["ind"] = ind
ok &= point._sql_save(execute, data) ok &= point._sql_save(execute, data)
ind += 1 ind += 1
@ -222,16 +227,16 @@ class ProfileXYZ(Profile, SQLSubModel):
def x(self): def x(self):
return [point.x for point in self._points] return [point.x for point in self.points]
def y(self): def y(self):
return [point.y for point in self._points] return [point.y for point in self.points]
def z(self): def z(self):
return [point.z for point in self._points] return [point.z for point in self.points]
def names(self): def names(self):
return [point.name for point in self._points] return [point.name for point in self.points]
def x_max(self): def x_max(self):
return max(self.filter_isnan(self.x())) return max(self.filter_isnan(self.x()))
@ -262,7 +267,7 @@ class ProfileXYZ(Profile, SQLSubModel):
""" """
for point in list_points: for point in list_points:
pt = PointXYZ(*point, profile=self, status=self._status) pt = PointXYZ(*point, profile=self, status=self._status)
self._points.append(pt) self.points.append(pt)
self._status.modified() self._status.modified()
def get_point_i(self, index: int) -> PointXYZ: def get_point_i(self, index: int) -> PointXYZ:
@ -275,7 +280,7 @@ class ProfileXYZ(Profile, SQLSubModel):
The point. The point.
""" """
try: try:
return self._points[index] return self.points[index]
except IndexError: except IndexError:
raise IndexError(f"Invalid point index: {index}") raise IndexError(f"Invalid point index: {index}")
@ -286,7 +291,7 @@ class ProfileXYZ(Profile, SQLSubModel):
Nothing. Nothing.
""" """
point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status) point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status)
self._points.append(point_xyz) self.points.append(point_xyz)
self._status.modified() self._status.modified()
def insert(self, index: int): def insert(self, index: int):
@ -299,7 +304,7 @@ class ProfileXYZ(Profile, SQLSubModel):
The new point. The new point.
""" """
point = PointXYZ(0., 0., 0., profile=self, status=self._status) point = PointXYZ(0., 0., 0., profile=self, status=self._status)
self._points.insert(index, point) self.points.insert(index, point)
self._status.modified() self._status.modified()
return point return point
@ -315,9 +320,9 @@ class ProfileXYZ(Profile, SQLSubModel):
return [x for x in lst if not np.isnan(x)] return [x for x in lst if not np.isnan(x)]
def _first_point_not_nan(self): def _first_point_not_nan(self):
first_point = self._points[0] first_point = self.points[0]
for point in self._points: for point in self.points:
if not point.is_nan(): if not point.is_nan():
first_point = point first_point = point
break break
@ -325,9 +330,9 @@ class ProfileXYZ(Profile, SQLSubModel):
return first_point return first_point
def _last_point_not_nan(self): def _last_point_not_nan(self):
last_point = self._points[-1] last_point = self.points[-1]
for point in self._points[::-1]: for point in self.points[::-1]:
if not point.is_nan(): if not point.is_nan():
last_point = point last_point = point
break break
@ -354,13 +359,13 @@ class ProfileXYZ(Profile, SQLSubModel):
first_point_not_nan = self._first_point_not_nan() first_point_not_nan = self._first_point_not_nan()
last_point_not_nan = self._last_point_not_nan() last_point_not_nan = self._last_point_not_nan()
for index, point in enumerate(self._points): for index, point in enumerate(self.points):
if point.point_is_named(): if point.point_is_named():
index_first_named_point = index index_first_named_point = index
first_named_point = point first_named_point = point
break break
for point in reversed(self._points): for point in reversed(self.points):
if point.point_is_named(): if point.point_is_named():
last_named_point = point last_named_point = point
break break
@ -378,7 +383,7 @@ class ProfileXYZ(Profile, SQLSubModel):
vector = Vector1d(first_point_not_nan, last_point_not_nan) vector = Vector1d(first_point_not_nan, last_point_not_nan)
normalized_direction_vec = vector.normalized_direction_vector() normalized_direction_vec = vector.normalized_direction_vector()
for point in self._points: for point in self.points:
xi = point.x - first_named_point.x xi = point.x - first_named_point.x
yi = point.y - first_named_point.y yi = point.y - first_named_point.y
station_i = (normalized_direction_vec[0] * xi + station_i = (normalized_direction_vec[0] * xi +
@ -390,7 +395,7 @@ class ProfileXYZ(Profile, SQLSubModel):
vector = Vector1d(first_point_not_nan, last_point_not_nan) vector = Vector1d(first_point_not_nan, last_point_not_nan)
normalized_direction_vec = vector.normalized_direction_vector() normalized_direction_vec = vector.normalized_direction_vector()
for point in self._points: for point in self.points:
xi = point.x - first_point_not_nan.x xi = point.x - first_point_not_nan.x
yi = point.y - first_point_not_nan.y yi = point.y - first_point_not_nan.y
station_i = (normalized_direction_vec[0] * xi + station_i = (normalized_direction_vec[0] * xi +

View File

@ -94,8 +94,8 @@ class Reach(SQLSubModel):
Returns: Returns:
The profile at index i The profile at index i
""" """
if i < len(self._profiles): if i < len(self.profiles):
return self._profiles[i] return self.profiles[i]
return None return None
@ -106,12 +106,32 @@ class Reach(SQLSubModel):
return self._parent.name return self._parent.name
def _get_profiles_list(self):
# Profiles list generator is type (int, Point) with the first
# element the index of the Point in list
logger.info(f"Load profiles from reach {self.name}")
return list(
map(
lambda p: p[1],
sorted(
self._profiles,
key = lambda p: p[0]
)
)
)
def __len__(self): def __len__(self):
if not isinstance(self._profiles, list):
self._profiles = self._get_profiles_list()
return len(self._profiles) return len(self._profiles)
@property @property
def profiles(self): def profiles(self):
return self._profiles.copy() if not isinstance(self._profiles, list):
self._profiles = self._get_profiles_list()
return self._profiles
def get_profiles_from_kp(self, kp): def get_profiles_from_kp(self, kp):
return list( return list(
@ -126,14 +146,14 @@ class Reach(SQLSubModel):
Returns: Returns:
Number of profiles Number of profiles
""" """
return len(self._profiles) return len(self.profiles)
def get_geometry(self) -> List[Profile]: def get_geometry(self) -> List[Profile]:
""" """
Returns: Returns:
The profiles list. The profiles list.
""" """
return self._profiles return self.profiles
def _update_profile_numbers(self): def _update_profile_numbers(self):
"""Update profiles index """Update profiles index
@ -155,7 +175,7 @@ class Reach(SQLSubModel):
""" """
profile = ProfileXYZ(reach=self, status=self._status) profile = ProfileXYZ(reach=self, status=self._status)
self._profiles.insert(index, profile) self.profiles.insert(index, profile)
self._update_profile_numbers() self._update_profile_numbers()
self._status.modified() self._status.modified()
@ -171,7 +191,7 @@ class Reach(SQLSubModel):
Returns: Returns:
Nothing. Nothing.
""" """
self._profiles.insert(index, profile) self.profiles.insert(index, profile)
self._update_profile_numbers() self._update_profile_numbers()
self._status.modified() self._status.modified()
@ -195,7 +215,7 @@ class Reach(SQLSubModel):
) )
) )
self._profiles = list( self.profiles = list(
filter( filter(
lambda p: p not in profiles, lambda p: p not in profiles,
self.profiles self.profiles
@ -213,7 +233,7 @@ class Reach(SQLSubModel):
Returns: Returns:
Nothing. Nothing.
""" """
self._profiles = list( self.profiles = list(
filter( filter(
lambda p: p not in profiles, lambda p: p not in profiles,
self.profiles self.profiles
@ -227,7 +247,7 @@ class Reach(SQLSubModel):
if index < len(self.profiles): if index < len(self.profiles):
next = index - 1 next = index - 1
p = self._profiles p = self.profiles
p[index], p[next] = p[next], p[index] p[index], p[next] = p[next], p[index]
self._status.modified() self._status.modified()
@ -235,7 +255,7 @@ class Reach(SQLSubModel):
if index >= 0: if index >= 0:
prev = index + 1 prev = index + 1
p = self._profiles p = self.profiles
p[index], p[prev] = p[prev], p[index] p[index], p[prev] = p[prev], p[index]
self._status.modified() self._status.modified()
@ -347,7 +367,7 @@ class Reach(SQLSubModel):
Tuple of complete and incomplete guidelines name. Tuple of complete and incomplete guidelines name.
""" """
# Get all point contains into a guideline # Get all point contains into a guideline
named_points = [profile.named_points() for profile in self._profiles] named_points = [profile.named_points() for profile in self.profiles]
points_name = list( points_name = list(
map( map(
lambda lst: list(map(lambda p: p.name, lst)), lambda lst: list(map(lambda p: p.name, lst)),
@ -422,8 +442,8 @@ class Reach(SQLSubModel):
@timer @timer
def sort(self, is_reversed: bool = False): def sort(self, is_reversed: bool = False):
self._profiles = sorted( self.profiles = sorted(
self._profiles, self.profiles,
key=lambda profile: profile.kp, key=lambda profile: profile.kp,
reverse=is_reversed reverse=is_reversed
) )
@ -431,10 +451,10 @@ class Reach(SQLSubModel):
@timer @timer
def sort_with_indexes(self, indexes: list): def sort_with_indexes(self, indexes: list):
if len(self._profiles) != len(indexes): if len(self.profiles) != len(indexes):
logger.critical("Indexes list do not correspond to profile list") logger.critical("Indexes list do not correspond to profile list")
self._profiles = list( self.profiles = list(
map( map(
lambda x: x[1], lambda x: x[1],
sorted( sorted(
@ -474,7 +494,7 @@ class Reach(SQLSubModel):
**d, reach=self, status=self._status **d, reach=self, status=self._status
) )
prof.import_points(profile) prof.import_points(profile)
self._profiles.append(prof) self.profiles.append(prof)
self._update_profile_numbers() self._update_profile_numbers()
self._status.modified() self._status.modified()
@ -538,8 +558,8 @@ class Reach(SQLSubModel):
# TODO: Move this function to model reach # TODO: Move this function to model reach
def export_reach(self, filename): def export_reach(self, filename):
with open(f"{filename}", "w") as file_st: with open(f"{filename}", "w") as file_st:
for index in range(len(self._profiles)): for index in range(len(self.profiles)):
profile = self._profiles[index] profile = self.profiles[index]
for v in profile.header: for v in profile.header:
file_st.write(f"{v:>6}") file_st.write(f"{v:>6}")

View File

@ -244,10 +244,8 @@ class InitialConditions(SQLSubModel):
data = data data = data
) )
if new._data is None: if new._data is not None:
return None yield new
return new
def _sql_save(self, execute, data = None): def _sql_save(self, execute, data = None):
ok = True ok = True

View File

@ -16,6 +16,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import types
from copy import copy from copy import copy
from tools import trace, timer from tools import trace, timer
@ -57,6 +58,19 @@ class InitialConditionsDict(PamhyrModelDict):
return ok return ok
def get(self, key):
if key in self._dict:
v = self._dict[key]
if isinstance(v, types.GeneratorType):
self._dict[key] = list(v)[0]
return self._dict[key]
new = self.new(key)
self.set(key, new)
return new
def new(self, reach): def new(self, reach):
new = InitialConditions(reach = reach, status = self._status) new = InitialConditions(reach = reach, status = self._status)
self.set(reach, new) self.set(reach, new)

View File

@ -59,12 +59,12 @@ class PamhyrModelList(SQLSubModel):
# MODEL METHOD # # MODEL METHOD #
################ ################
def __len__(self):
return len(self._lst)
@property @property
def lst(self): def lst(self):
return self._lst.copy() return self._lst
def __len__(self):
return len(self.lst)
def get(self, row): def get(self, row):
return self._lst[row] return self._lst[row]