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
|
@classmethod
|
||||||
def default_parameters(cls):
|
def default_parameters(cls):
|
||||||
lst = [
|
lst = [
|
||||||
("all_init_time", "00:00:00:00"),
|
("all_init_time", "000:00:00:00"),
|
||||||
("all_final_time", "999:99:00:00"),
|
("all_final_time", "999:99:00:00"),
|
||||||
("all_timestep", "300.0"),
|
("all_timestep", "300.0"),
|
||||||
]
|
]
|
||||||
|
|
@ -122,6 +122,17 @@ class AbstractSolver(object):
|
||||||
def export(self, study, repertory, qlog = None):
|
def export(self, study, repertory, qlog = None):
|
||||||
raise NotImplementedMethodeError(self, self.export)
|
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 #
|
# Run #
|
||||||
#######
|
#######
|
||||||
|
|
@ -137,8 +148,10 @@ class AbstractSolver(object):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cmd = self._cmd_solver
|
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]
|
exe = cmd[0]
|
||||||
args = cmd[1:]
|
args = cmd[1:]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import os
|
||||||
from tools import timer
|
from tools import timer
|
||||||
|
|
||||||
from Solver.ASolver import AbstractSolver
|
from Solver.ASolver import AbstractSolver
|
||||||
|
from Checker.Mage import MageNetworkGraphChecker
|
||||||
|
|
||||||
class Mage(AbstractSolver):
|
class Mage(AbstractSolver):
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
|
|
@ -49,10 +50,22 @@ class Mage(AbstractSolver):
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def checkers(cls):
|
||||||
|
lst = [
|
||||||
|
MageNetworkGraphChecker(connectivity = True),
|
||||||
|
MageNetworkGraphChecker(connectivity = False)
|
||||||
|
]
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
##########
|
##########
|
||||||
# Export #
|
# Export #
|
||||||
##########
|
##########
|
||||||
|
|
||||||
|
def input_param(self):
|
||||||
|
return "0.REP"
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def _export_ST(self, study, repertory, qlog):
|
def _export_ST(self, study, repertory, qlog):
|
||||||
files = []
|
files = []
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue