Network: Add scenario support.

scenarios
Pierre-Antoine Rouby 2024-09-20 18:35:43 +02:00
parent 4199eb6ac5
commit 48c389a27c
4 changed files with 155 additions and 67 deletions

View File

@ -24,10 +24,8 @@ class Edge(PamhyrID):
def __init__(self, id: int, name: str,
node1: Node = None,
node2: Node = None,
status=None):
super(Edge, self).__init__(id)
self._status = status
status=None, **kwargs):
super(Edge, self).__init__(id=id, status=status, **kwargs)
self._name = name
self.node1 = node1
@ -63,7 +61,7 @@ class Edge(PamhyrID):
elif name == "enable":
self._enable = value
self._status.modified()
self.modified()
@property
def id(self):
@ -79,16 +77,19 @@ class Edge(PamhyrID):
def is_enable(self):
return self._enable
def is_deleted(self):
return False
def enable(self, enable=True):
self._enable = enable
self._status.modified()
self.modified()
def disable(self):
self._enable = False
self._status.modified()
self.modified()
def reverse(self):
tmp = self.node1
self.node1 = self.node2
self.node2 = tmp
self._status.modified()
self.modified()

View File

@ -23,10 +23,8 @@ from Model.Network.Edge import Edge
class Graph(object):
def __init__(self, status=None):
super(Graph, self).__init__()
self._status = status
def __init__(self, **kwargs):
super(Graph, self).__init__(**kwargs)
self._node_ctor = Node
self._edge_ctor = Edge
@ -38,13 +36,13 @@ class Graph(object):
return f"Graph {{nodes: {self._nodes}, edges: {self._edges}}}"
def nodes(self):
return self._nodes
return list(filter(lambda n: not n.is_deleted(), self._nodes))
def nodes_names(self):
return list(map(lambda n: n.name, self._nodes))
return list(map(lambda n: n.name, self.nodes()))
def edges(self):
return self._edges
return list(filter(lambda e: not e.is_deleted(), self._edges))
def enable_edges(self):
return list(
@ -55,43 +53,43 @@ class Graph(object):
"""Return a generator"""
return filter(
lambda e: e.is_enable(),
self._edges
self.edges()
)
def edges_names(self):
return list(map(lambda e: e.name, self._edges))
return list(map(lambda e: e.name, self.edges()))
def nodes_counts(self):
return len(self._nodes)
return len(self.nodes())
def edges_counts(self):
return len(self._edges)
return len(self.edges())
def enable_nodes_counts(self):
return reduce(
lambda acc, n: acc + 1 if self.is_enable_node(n) else acc,
self._nodes,
self.nodes(),
0
)
def enable_edges_counts(self):
return reduce(
lambda acc, e: acc + 1 if e.is_enable() else acc,
self._edges,
self.edges(),
0
)
def is_node_exists(self, node_name):
return reduce(
lambda acc, n: (acc or (n.name == node_name)),
self._nodes,
self.nodes(),
False
)
def is_edge_exists(self, edge_name):
return reduce(
lambda acc, e: (acc or (e.name == edge_name)),
self._edges,
self.edges(),
False
)
@ -99,7 +97,7 @@ class Graph(object):
node = list(
filter(
lambda n: n.name == node_name,
self._nodes
self.nodes()
)
)
@ -112,7 +110,7 @@ class Graph(object):
edge = list(
filter(
lambda e: e.name == edge_name,
self._edges
self.edges()
)
)
@ -123,16 +121,18 @@ class Graph(object):
def _create_node(self, x: float, y: float):
node = self._node_ctor(
-1,
"",
x=x, y=y,
id=-1, name="", x=x, y=y,
status=self._status
)
return node
def _add_node(self, node):
self._nodes.append(node)
self._status.modified()
if node in self._nodes:
node.set_as_not_deleted()
else:
self._nodes.append(node)
self.modified()
return node
def add_node(self, x: float = 0.0, y: float = 0.0):
@ -143,9 +143,9 @@ class Graph(object):
return self._add_node(node)
def remove_node(self, node):
self._nodes.remove(node)
node.set_as_deleted()
self._remove_associated_edge(node)
self._status.modified()
self.modified()
def _remove_associated_edge(self, node: str):
edges = list(
@ -176,10 +176,12 @@ class Graph(object):
# e.node2 == edge.node2),
# self._edges)):
# return None
if edge in self._edges:
edge.set_as_not_deleted()
else:
self._edges.append(edge)
self._edges.append(edge)
self._status.modified()
self.modified()
return edge
def add_edge(self, n1: Node, n2: Node):
@ -193,8 +195,8 @@ class Graph(object):
return self._create_edge(n1, n2)
def remove_edge(self, edge):
self._edges.remove(edge)
self._status.modified()
edge.set_as_deleted()
self.modified()
def is_upstream_node(self, node):
return reduce(

View File

@ -23,7 +23,7 @@ from Model.Network.Point import Point
class Node(PamhyrID):
def __init__(self, id: int, name: str,
x: float = 0.0, y: float = 0.0,
status=None):
status=None, **kwargs):
super(Node, self).__init__(id)
self._status = status
@ -55,6 +55,9 @@ class Node(PamhyrID):
self._status.modified()
def is_deleted(self):
return False
@property
def name(self):
return self._name

View File

@ -54,15 +54,13 @@ logger = logging.getLogger()
class RiverNode(Node, SQLSubModel):
_sub_classes = []
def __init__(self, id: int, name: str,
x: float, y: float,
status=None):
self._pamhyr_id = self.get_new_pamhyr_id(id)
def __init__(self, id: int = -1, name: str = "",
x: float = 0.0, y: float = 0.0,
status=None, owner_scenario=-1):
super(RiverNode, self).__init__(
id, name,
x, y,
status=status
id, name, x, y,
status=status,
owner_scenario=owner_scenario
)
self._locker = None
@ -72,6 +70,7 @@ class RiverNode(Node, SQLSubModel):
execute(f"""
CREATE TABLE river_node{ext}(
{cls.create_db_add_pamhyr_id()},
deleted BOOLEAN NOT NULL DEFAULT FALSE,
name TEXT NOT NULL,
x REAL NOT NULL,
y REAL NOT NULL,
@ -93,6 +92,13 @@ class RiverNode(Node, SQLSubModel):
if major == minor == "0":
cls._db_update_to_0_1_0(execute, data=data)
if major == "0" and minor == "1":
if int(release) < 2:
execute(
"ALTER TABLE river_node " +
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
)
return cls._update_submodel(execute, version, data)
@classmethod
@ -118,27 +124,65 @@ class RiverNode(Node, SQLSubModel):
@classmethod
def _db_load(cls, execute, data=None):
nodes = []
scenario = data["scenario"]
loaded = data['loaded_pid']
if scenario is None:
return nodes
table = execute(
"SELECT pamhyr_id, deleted, name, x, y, scenario " +
"FROM river_node " +
f"WHERE scenario = {scenario.id} " +
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) "
)
table = execute("SELECT pamhyr_id, name, x, y FROM river_node")
for row in table:
nodes.append(
cls(*row, status=data["status"])
it = iter(row)
pid = next(it)
deleted = (next(it) == 1)
name = next(it)
x = next(it)
y = next(it)
owner_scenario = next(it)
node = cls(
id=pid,
name=name, x=x, y=y,
status=data["status"],
owner_scenario=owner_scenario
)
if deleted:
node.set_as_deleted()
loaded.add(pid)
nodes.append(node)
data["scenario"] = scenario.parent
nodes += cls._db_load(execute, data)
data["scenario"] = scenario
return nodes
def _db_save(self, execute, data=None):
execute(
"INSERT OR REPLACE INTO river_node(pamhyr_id, name, x, y) " +
"INSERT OR REPLACE INTO river_node(" +
"pamhyr_id, deleted, name, x, y, scenario" +
") " +
"VALUES (" +
f"{self._pamhyr_id}, " +
f"{self._pamhyr_id}, {self._db_format(self.is_deleted())}, " +
f"'{self._db_format(self.name)}', " +
f"{self.x}, {self.y}" +
f"{self.x}, {self.y}, {self._status.scenario_id}" +
")"
)
return True
def is_deleted(self):
return self._deleted
@property
def locker(self):
return self._locker
@ -154,16 +198,15 @@ class RiverReach(Edge, SQLSubModel):
FrictionList,
]
def __init__(self, id: str, name: str,
def __init__(self, id: str = -1, name: str = "",
node1: RiverNode = None,
node2: RiverNode = None,
status=None):
# self._pamhyr_id = self.get_new_pamhyr_id(id)
status=None, owner_scenario=-1):
super(RiverReach, self).__init__(
id, name,
node1, node2,
status=status
status=status,
owner_scenario=owner_scenario
)
self._reach = Reach(status=self._status, parent=self)
@ -174,6 +217,7 @@ class RiverReach(Edge, SQLSubModel):
execute(f"""
CREATE TABLE river_reach{ext} (
{cls.create_db_add_pamhyr_id()},
deleted BOOLEAN NOT NULL DEFAULT FALSE,
name TEXT NOT NULL,
enabled BOOLEAN NOT NULL,
node1 INTEGER,
@ -198,6 +242,13 @@ class RiverReach(Edge, SQLSubModel):
if major == minor == "0":
cls._db_update_to_0_1_0(execute, data)
if major == "0" and minor == "1":
if int(release) < 2:
execute(
"ALTER TABLE river_reach " +
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
)
return cls._update_submodel(execute, version, data)
@classmethod
@ -246,20 +297,30 @@ class RiverReach(Edge, SQLSubModel):
@classmethod
def _db_load(cls, execute, data=None):
reachs = []
scenario = data["scenario"]
loaded = data['loaded_pid']
if scenario is None:
return reachs
table = execute(
"SELECT pamhyr_id, name, enabled, node1, node2 FROM river_reach"
"SELECT pamhyr_id, deleted, name, enabled, " +
"node1, node2, scenario " +
"FROM river_reach " +
f"WHERE scenario = {scenario.id} " +
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))})"
)
for row in table:
it = iter(row)
# Create new reach
pid = next(it)
deleted = (next(it) == 1)
name = next(it)
enabled = (next(it) == 1)
node1_pid = next(it)
node2_pid = next(it)
owner_scenario = next(it)
# Get nodes corresponding to db foreign key id
node1 = next(
@ -273,26 +334,41 @@ class RiverReach(Edge, SQLSubModel):
)
)
new = cls(pid, name, node1, node2, status=data["status"])
new = cls(
id=pid, name=name, node1=node1, node2=node2,
status=data["status"],
owner_scenario=owner_scenario
)
new.enable(enable=enabled)
if deleted:
nd.set_as_deleted()
data["reach"] = new
new._reach = Reach._db_load(execute, data)
new._frictions = FrictionList._db_load(execute, data)
loaded.add(pid)
reachs.append(new)
data["scenario"] = scenario.parent
reachs += cls._db_load(execute, data)
data["scenario"] = scenario
return reachs
def _db_save(self, execute, data=None):
execute(
"INSERT OR REPLACE INTO " +
"river_reach(pamhyr_id, name, enabled, node1, node2) " +
"river_reach(" +
"pamhyr_id, deleted, name, enabled, " +
"node1, node2, scenario" +
") " +
"VALUES (" +
f"{self.pamhyr_id}, '{self._db_format(self._name)}', " +
f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " +
f"'{self._db_format(self._name)}', " +
f"{self._db_format(self.is_enable())},"
f"{self.node1.pamhyr_id}, {self.node2.pamhyr_id}" +
f"{self.node1.pamhyr_id}, {self.node2.pamhyr_id}, " +
f"{self._status.scenario_id}" +
")"
)
@ -301,6 +377,9 @@ class RiverReach(Edge, SQLSubModel):
objs = [self._reach, self._frictions]
return self._save_submodel(execute, objs, data)
def is_deleted(self):
return self._deleted
@property
def reach(self):
return self._reach
@ -327,7 +406,9 @@ class River(Graph, SQLSubModel):
]
def __init__(self, status=None):
super(River, self).__init__(status=status)
super(River, self).__init__(
status=status
)
# Replace Node and Edge ctor by custom ctor
self._node_ctor = RiverNode
@ -359,7 +440,7 @@ class River(Graph, SQLSubModel):
@classmethod
def _db_load(cls, execute, data=None):
new = cls(data["status"])
new = cls(status=data["status"])
# Stricklers (Stricklers is load in first because it's needed
# for reachs)
@ -462,12 +543,13 @@ class River(Graph, SQLSubModel):
execute(
f"DELETE FROM {table} " +
"WHERE " +
f"scenario = {self._status.scenario_id} AND (" +
" OR ".join(
map(
lambda n: f"( pamhyr_id <> {n.pamhyr_id} )",
els
)
)
) + ")"
)
except Exception as e:
logger_exception(e)