Commit c7d6605c authored by Pierre-Antoine Rouby's avatar Pierre-Antoine Rouby
Browse files

Mage: Add connectivity and cycle network checker.

Showing with 226 additions and 2 deletions
+226 -2
# -*- 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 = []
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment