mirror of https://gitlab.com/pamhyr/pamhyr2
Mage: Add connectivity and cycle network checker.
parent
6250b0e1b0
commit
c7d6605cd6
|
|
@ -0,0 +1,198 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import time
|
||||
|
||||
from queue import Queue
|
||||
from tools import flatten
|
||||
from functools import reduce
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from Checker.Checker import AbstractModelChecker, STATUS
|
||||
|
||||
_translate = QCoreApplication.translate
|
||||
|
||||
class MageNetworkGraphChecker(AbstractModelChecker):
|
||||
def __init__(self, connectivity = True):
|
||||
super(MageNetworkGraphChecker, self).__init__()
|
||||
|
||||
self._mode_conn = connectivity
|
||||
|
||||
if connectivity:
|
||||
mode = "connectivity"
|
||||
else:
|
||||
mode = "cycle"
|
||||
|
||||
self._name = _translate("Checker", f"Mage network graph {mode} checker")
|
||||
self._description = _translate("Checker", "Check if the network graph is valid")
|
||||
|
||||
def _connectivity(self, summary, status, graph):
|
||||
# Keep only enabled edges
|
||||
edges = list(
|
||||
filter(
|
||||
lambda e: e.is_enable(),
|
||||
graph.edges()
|
||||
)
|
||||
)
|
||||
# Get all related nodes
|
||||
nodes = list(
|
||||
set(
|
||||
flatten(
|
||||
map(
|
||||
lambda e: [e.node1, e.node2],
|
||||
edges
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Visite graph
|
||||
q = Queue()
|
||||
for node in nodes:
|
||||
if graph.is_upstream_node(node):
|
||||
q.put(node)
|
||||
break # We take only one node
|
||||
|
||||
if q.qsize() == 0:
|
||||
summary = "no_upstream_node"
|
||||
status = STATUS.ERROR
|
||||
return summary, status
|
||||
|
||||
visited = set()
|
||||
while q.qsize() != 0:
|
||||
current = q.get()
|
||||
if current is None:
|
||||
continue
|
||||
|
||||
if current in visited:
|
||||
continue
|
||||
|
||||
related_edges = list(
|
||||
filter(
|
||||
lambda e: e.node1 == current or e.node2 == current,
|
||||
edges
|
||||
)
|
||||
)
|
||||
|
||||
# Get next node(s) to visite
|
||||
nexts = flatten(
|
||||
map(
|
||||
lambda e: [e.node1, e.node2],
|
||||
related_edges
|
||||
)
|
||||
)
|
||||
|
||||
for n in nexts:
|
||||
q.put(n)
|
||||
|
||||
# Visited node
|
||||
visited.add(current)
|
||||
|
||||
if len(visited) != len(nodes):
|
||||
if "ok" in summary:
|
||||
summary = "network_connectivity"
|
||||
else:
|
||||
summary = summary + "|" + "network_connectivity"
|
||||
status = STATUS.ERROR
|
||||
return summary, status
|
||||
|
||||
return summary, status
|
||||
|
||||
def _cycle(self, summary, status, graph):
|
||||
# Keep only enabled edges
|
||||
edges = list(
|
||||
filter(
|
||||
lambda e: e.is_enable(),
|
||||
graph.edges()
|
||||
)
|
||||
)
|
||||
# Get all related nodes
|
||||
nodes = list(
|
||||
set(
|
||||
flatten(
|
||||
map(
|
||||
lambda e: [e.node1, e.node2],
|
||||
edges
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
for edge in edges:
|
||||
# Visite graph
|
||||
q = Queue()
|
||||
initial = edge.node1
|
||||
q.put(initial)
|
||||
|
||||
visited = set()
|
||||
while q.qsize() != 0:
|
||||
current = q.get()
|
||||
if current is None:
|
||||
continue
|
||||
|
||||
if current in visited:
|
||||
continue
|
||||
|
||||
related_edges = list(
|
||||
filter(
|
||||
lambda e: e.node1 == current,
|
||||
edges
|
||||
)
|
||||
)
|
||||
|
||||
# Get next node(s) to visite
|
||||
nexts = list(
|
||||
map(
|
||||
lambda e: e.node2,
|
||||
related_edges
|
||||
)
|
||||
)
|
||||
|
||||
# The initial node cannot be visited a second time where visite
|
||||
# started by this node, otherelse there is a cycle in the graph
|
||||
if initial in nexts:
|
||||
if "ok" in summary:
|
||||
summary = "cycle_detected"
|
||||
else:
|
||||
summary = summary + "|" + "cycle_detected"
|
||||
status = STATUS.ERROR
|
||||
return summary, status
|
||||
|
||||
for n in nexts:
|
||||
q.put(n)
|
||||
|
||||
# Visited node
|
||||
visited.add(current)
|
||||
|
||||
return summary, status
|
||||
|
||||
def run(self, study):
|
||||
summary = "ok"
|
||||
status = STATUS.OK
|
||||
|
||||
if study is None:
|
||||
self._status = STATUS.ERROR
|
||||
self._summary = "invalid_study"
|
||||
return False
|
||||
|
||||
river = study.river
|
||||
if river is None:
|
||||
self._status = STATUS.ERROR
|
||||
self._summary = "no_river_found"
|
||||
return False
|
||||
|
||||
edges = list(filter(lambda e: e.is_enable(), river.edges()))
|
||||
if len(edges) == 0:
|
||||
self._status = STATUS.ERROR
|
||||
self._summary = "no_reach_defined"
|
||||
return False
|
||||
|
||||
if self._mode_conn:
|
||||
summary, status = self._connectivity(summary, status, river)
|
||||
else:
|
||||
summary, status = self._cycle(summary, status, river)
|
||||
|
||||
self._summary = summary
|
||||
self._status = status
|
||||
return True
|
||||
|
|
@ -52,7 +52,7 @@ class AbstractSolver(object):
|
|||
@classmethod
|
||||
def default_parameters(cls):
|
||||
lst = [
|
||||
("all_init_time", "00:00:00:00"),
|
||||
("all_init_time", "000:00:00:00"),
|
||||
("all_final_time", "999:99:00:00"),
|
||||
("all_timestep", "300.0"),
|
||||
]
|
||||
|
|
@ -122,6 +122,17 @@ class AbstractSolver(object):
|
|||
def export(self, study, repertory, qlog = None):
|
||||
raise NotImplementedMethodeError(self, self.export)
|
||||
|
||||
def input_param(self):
|
||||
"""Return input command line parameter(s)
|
||||
|
||||
Args:
|
||||
study: The study object
|
||||
|
||||
Returns:
|
||||
Returns input parameter(s) string
|
||||
"""
|
||||
raise NotImplementedMethodeError(self, self.input_param)
|
||||
|
||||
#######
|
||||
# Run #
|
||||
#######
|
||||
|
|
@ -137,8 +148,10 @@ class AbstractSolver(object):
|
|||
return True
|
||||
|
||||
cmd = self._cmd_solver
|
||||
cmd = cmd.replace("@path", self._path_solver).split()
|
||||
cmd = cmd.replace("@path", self._path_solver)
|
||||
cmd = cmd.replace("@input", self.input_param())
|
||||
|
||||
cmd = cmd.split()
|
||||
exe = cmd[0]
|
||||
args = cmd[1:]
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import os
|
|||
from tools import timer
|
||||
|
||||
from Solver.ASolver import AbstractSolver
|
||||
from Checker.Mage import MageNetworkGraphChecker
|
||||
|
||||
class Mage(AbstractSolver):
|
||||
def __init__(self, name):
|
||||
|
|
@ -49,10 +50,22 @@ class Mage(AbstractSolver):
|
|||
|
||||
return lst
|
||||
|
||||
@classmethod
|
||||
def checkers(cls):
|
||||
lst = [
|
||||
MageNetworkGraphChecker(connectivity = True),
|
||||
MageNetworkGraphChecker(connectivity = False)
|
||||
]
|
||||
|
||||
return lst
|
||||
|
||||
##########
|
||||
# Export #
|
||||
##########
|
||||
|
||||
def input_param(self):
|
||||
return "0.REP"
|
||||
|
||||
@timer
|
||||
def _export_ST(self, study, repertory, qlog):
|
||||
files = []
|
||||
|
|
|
|||
Loading…
Reference in New Issue