From b46943e17a7889b18da69bcfdb5691a4a4216ed2 Mon Sep 17 00:00:00 2001 From: tproduit Date: Wed, 16 Dec 2020 16:35:53 +0100 Subject: [PATCH] Qgep swmm states (#55) * add state selection * state choice * check with gruner data * check with gruner data * check execute and extract functions * bug with storage export * change error message * solve p8p errors * solve p8p errors * solve p8p errors * solve p8p errors --- qgepplugin/processing_provider/QgepSwmm.py | 63 ++++++++++++------- .../processing_provider/swmm_create_input.py | 20 ++++-- .../processing_provider/swmm_execute.py | 13 ++-- .../swmm_extract_results.py | 2 +- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/qgepplugin/processing_provider/QgepSwmm.py b/qgepplugin/processing_provider/QgepSwmm.py index 8b1ded21..224f97f3 100644 --- a/qgepplugin/processing_provider/QgepSwmm.py +++ b/qgepplugin/processing_provider/QgepSwmm.py @@ -25,17 +25,18 @@ class QgepSwmm: - def __init__(self, title, service, inpfile, inptemplate, outfile, logfile, binfile, db_model_path): + def __init__(self, title, service, state, inpfile, inptemplate, outfile, binfile, db_model_path): """ Initiate QgepSwmm Parameters: title (string): Title of the simulation service (string): name of the service to be used to connect to the QGEP database + state (string): state for which the network is extracted (current or planned) inpfile (path): path of the INP file (input file for swmm) inptemplate (path): path of the INP file which store simulations parameters outfile (path): path of the OUT file which contains swmm results - logfile (path): path of the log file which contains swmm log + binfile (path): path of the swmm executable db_model_path (path): path of the folder which contains the db model """ self.title = title @@ -43,17 +44,19 @@ def __init__(self, title, service, inpfile, inptemplate, outfile, logfile, binfi self.input_file = inpfile self.options_template_file = inptemplate self.output_file = outfile - self.log_file = logfile self.bin_file = binfile self.db_model_path = db_model_path self.feedbacks = [] + self.state = state - def get_swmm_table(self, table_name): + def get_swmm_table(self, table_name, state, ws): """ Extract data from the swmm views in the database Parameters: table_name (string): Name of the view or table + state (string): current or planned + ws (boolean): if the origin table is a wastewater structure Returns: dic: table content @@ -64,8 +67,16 @@ def get_swmm_table(self, table_name): # Connects to service and get data and attributes from tableName con = psycopg2.connect(service=self.service) cur = con.cursor() + if (state == 'planned' and ws is True) or (state is None): + sql = 'select * from qgep_swmm.vw_{table_name}'.format(table_name=table_name) + else: + sql = """ + select * from qgep_swmm.vw_{table_name} + where state = '{state}' + """.format(table_name=table_name, state=state) + try: - cur.execute('select * from qgep_swmm.vw_{table_name}'.format(table_name=table_name)) + cur.execute(sql) except psycopg2.ProgrammingError: self.feedbacks.append('Table vw_{table_name} doesnt exists'.format(table_name=table_name)) return None, None @@ -74,12 +85,16 @@ def get_swmm_table(self, table_name): return data, attributes - def swmm_table(self, table_name): + def swmm_table(self, table_name, state=None, ws=False): """ - Write swmm objects extracted from QGEP in swmm input file + Write swmm objects extracted from QGEP in swmm input file. Selects according + to the state planned or current. If the object is a qgep wastewater structure + when the state is "planned" both "planned" and "operational" wastewater structures are selected Parameters: table_name (string): Name of the swmm section + state (string): current or planned + ws (boolean): if the origin table is a wastewater structure Returns: String: table content @@ -88,11 +103,11 @@ def swmm_table(self, table_name): # Create commented line which contains the field names fields = "" - data, attributes = self.get_swmm_table(table_name) + data, attributes = self.get_swmm_table(table_name, state, ws) if data is not None: for i, field in enumerate(attributes): # Does not write values stored in columns descriptions, tags and geom - if field not in ('description', 'tag', 'geom'): + if field not in ('description', 'tag', 'geom', 'state'): fields += field + "\t" # Create input paragraph @@ -108,7 +123,7 @@ def swmm_table(self, table_name): for i, v in enumerate(feature): # Does not write values stored in columns descriptions, tags and geom - if attributes[i] not in ('description', 'tag', 'geom'): + if attributes[i] not in ('description', 'tag', 'geom', 'state'): if v is not None: tbl += str(v) + '\t' else: @@ -158,6 +173,7 @@ def write_input(self): # From qgis swmm filename = self.input_file + state = self.state with codecs.open(filename, 'w', encoding='utf-8') as f: @@ -181,11 +197,11 @@ def write_input(self): # Hydrology # ---------- - f.write(self.swmm_table('RAINGAGES')) - f.write(self.swmm_table('SUBCATCHMENTS')) - f.write(self.swmm_table('SUBAREAS')) + f.write(self.swmm_table('RAINGAGES', state)) + f.write(self.swmm_table('SUBCATCHMENTS', state)) + f.write(self.swmm_table('SUBAREAS', state)) f.write(self.swmm_table('AQUIFERS')) - f.write(self.swmm_table('INFILTRATION')) + f.write(self.swmm_table('INFILTRATION', state)) f.write(self.swmm_table('POLYGONS')) f.write(self.copy_parameters_from_template('GROUNDWATER')) @@ -196,26 +212,27 @@ def write_input(self): # Hydraulics: nodes # ------------------ - f.write(self.swmm_table('JUNCTIONS')) + f.write(self.swmm_table('JUNCTIONS', state, ws=True)) # Create default junction to avoid errors f.write('default_qgep_node\t0\t0\n\n') - f.write(self.swmm_table('OUTFALLS')) - f.write(self.swmm_table('STORAGE')) + f.write(self.swmm_table('OUTFALLS', state, ws=True)) + f.write(self.swmm_table('STORAGES', state, ws=True)) f.write(self.swmm_table('COORDINATES')) - f.write(self.swmm_table('DWF')) + f.write(self.swmm_table('DWF', state)) f.write(self.copy_parameters_from_template('INFLOWS')) f.write(self.copy_parameters_from_template('DIVIDERS')) # Hydraulics: links # ------------------ - f.write(self.swmm_table('CONDUITS')) - f.write(self.swmm_table('PUMPS')) + f.write(self.swmm_table('CONDUITS', state, ws=True)) + f.write(self.swmm_table('LOSSES', state, ws=True)) + f.write(self.swmm_table('PUMPS', state, ws=True)) f.write(self.copy_parameters_from_template('ORIFICES')) f.write(self.copy_parameters_from_template('WEIRS')) f.write(self.copy_parameters_from_template('OUTLETS')) - f.write(self.swmm_table('XSECTIONS')) - f.write(self.swmm_table('LOSSES')) + f.write(self.swmm_table('XSECTIONS', state, ws=True)) + f.write(self.swmm_table('LOSSES', state, ws=True)) f.write(self.swmm_table('VERTICES')) f.write(self.copy_parameters_from_template('TRANSECTS')) @@ -356,7 +373,7 @@ def execute_swmm(self): """ - command = [self.bin_file, self.input_file, self.log_file, self.output_file] + command = [self.bin_file, self.input_file, self.output_file] print('command', command) proc = subprocess.run( command, diff --git a/qgepplugin/processing_provider/swmm_create_input.py b/qgepplugin/processing_provider/swmm_create_input.py index a1ef12fd..e7dc7ea3 100644 --- a/qgepplugin/processing_provider/swmm_create_input.py +++ b/qgepplugin/processing_provider/swmm_create_input.py @@ -28,6 +28,7 @@ QgsProcessingParameterString, QgsProcessingParameterFile, QgsProcessingParameterFileDestination, + QgsProcessingParameterEnum ) from .qgep_algorithm import QgepAlgorithm @@ -49,6 +50,7 @@ class SwmmCreateInputAlgorithm(QgepAlgorithm): DATABASE = 'DATABASE' TEMPLATE_INP_FILE = 'TEMPLATE_INP_FILE' INP_FILE = 'INP_FILE' + STATE = 'STATE' def name(self): return 'swmm_create_input' @@ -60,16 +62,20 @@ def initAlgorithm(self, config=None): """Here we define the inputs and output of the algorithm, along with some other properties. """ - + self.stateOptions = ["current", "planned"] # The parameters description = self.tr('Database') self.addParameter(QgsProcessingParameterString( self.DATABASE, description=description, defaultValue="pg_qgep_demo_data")) + description = self.tr('State (current or planned)') + self.addParameter(QgsProcessingParameterEnum( + self.STATE, description=description, options=self.stateOptions, defaultValue=self.stateOptions[0])) + description = self.tr('Template INP File') self.addParameter(QgsProcessingParameterFile(self.TEMPLATE_INP_FILE, description=description, extension="inp")) - description = self.tr('Result INP File') + description = self.tr('Destination INP File') self.addParameter(QgsProcessingParameterFileDestination( self.INP_FILE, description=description, fileFilter="inp (*.inp)")) @@ -80,12 +86,16 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: # init params database = self.parameterAsString(parameters, self.DATABASE, context) + state = self.parameterAsString(parameters, self.STATE, context) template_inp_file = self.parameterAsFile(parameters, self.TEMPLATE_INP_FILE, context) inp_file = self.parameterAsFileOutput(parameters, self.INP_FILE, context) - + state = self.stateOptions[int(state)] + if state not in ['current', 'planned']: + feedback.reportError('State must be "planned" or "current", state was set to "current"') + state = 'current' # Connect to QGEP database and perform translation - qs = QgepSwmm(datetime.datetime.today().isoformat(), database, - inp_file, template_inp_file, None, None, None, None) + qs = QgepSwmm(datetime.datetime.today().isoformat(), database, state, + inp_file, template_inp_file, None, None, None) qs.write_input() if qs.feedbacks is not None: diff --git a/qgepplugin/processing_provider/swmm_execute.py b/qgepplugin/processing_provider/swmm_execute.py index 8794c985..725685b7 100644 --- a/qgepplugin/processing_provider/swmm_execute.py +++ b/qgepplugin/processing_provider/swmm_execute.py @@ -51,7 +51,7 @@ class SwmmExecuteAlgorithm(QgepAlgorithm): INP_FILE = 'INP_FILE' OUT_FILE = 'OUT_FILE' - LOG_FILE = 'LOG_FILE' + # LOG_FILE = 'LOG_FILE' def name(self): return 'swmm_execute' @@ -72,15 +72,14 @@ def initAlgorithm(self, config=None): self.addParameter(QgsProcessingParameterFileDestination( self.OUT_FILE, description=description, fileFilter="out (*.out)")) - description = self.tr('LOG File') - self.addParameter(QgsProcessingParameterFileDestination( - self.LOG_FILE, description=description, fileFilter="log (*.log)")) + # description = self.tr('LOG File') + # self.addParameter(QgsProcessingParameterFileDestination( + # self.LOG_FILE, description=description, fileFilter="log (*.log)")) def processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: QgsProcessingFeedback): """Here is where the processing itself takes place.""" # init params - log_file = self.parameterAsFile(parameters, self.LOG_FILE, context) output_file = self.parameterAsFile(parameters, self.OUT_FILE, context) inp_file = self.parameterAsFileOutput(parameters, self.INP_FILE, context) swmm_cli = os.path.abspath(ProcessingConfig.getSetting('SWMM_PATH')) @@ -93,7 +92,7 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: Please configure it before running Swmm algorithms.') ) - qs = QgepSwmm(None, None, inp_file, None, output_file, log_file, swmm_cli, None) + qs = QgepSwmm(None, None, None, inp_file, None, output_file, swmm_cli, None) prompt = qs.execute_swmm() if qs.feedbacks is not None: for i in range(len(qs.feedbacks)): @@ -103,7 +102,7 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: if re.search('There are errors', prompt): feedback.reportError(prompt) - feedback.reportError('There were errors, look into logs for details: {log_file}'.format(log_file=log_file)) + feedback.reportError('There were errors, run the file in SWMM GUI for more details') feedback.setProgress(100) diff --git a/qgepplugin/processing_provider/swmm_extract_results.py b/qgepplugin/processing_provider/swmm_extract_results.py index fb79f451..b4c6ea1d 100644 --- a/qgepplugin/processing_provider/swmm_extract_results.py +++ b/qgepplugin/processing_provider/swmm_extract_results.py @@ -96,7 +96,7 @@ def processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: raise QgsProcessingException(self.invalidSinkError(parameters, self.NODE_SUMMARY)) # Get node summary from output file - qs = QgepSwmm(None, None, None, None, out_file, None, None, None) + qs = QgepSwmm(None, None, None, None, None, out_file, None, None) if qs.feedbacks is not None: for i in range(len(qs.feedbacks)): feedback.reportError(qs.feedbacks[i])