class frmMainEPANET(frmMain): """Main form for EPANET user interface, based on frmMain which is shared with SWMM.""" # Variables used to populate the tree control # Each item is a list: label plus either editing form for this section or a child list. # Special cases may just have a label and no editing form or children. # *_items are a lists of items in a section tree_options_Hydraulics = ["Hydraulics", frmHydraulicsOptions] tree_options_Quality = ["Quality", frmQualityOptions] tree_options_Reactions = ["Reactions", frmReactionsOptions] tree_options_Times = ["Times", frmTimesOptions] tree_options_Energy = ["Energy", frmEnergyOptions] tree_options_Report = ["Report", frmReportOptions] tree_options_MapBackdrop = ["Map/Backdrop", frmMapBackdropOptions] tree_options_items = [ tree_options_Hydraulics, tree_options_Quality, tree_options_Reactions, tree_options_Times, tree_options_Energy, tree_options_Report, tree_options_MapBackdrop ] tree_controls_Simple = [ "Simple", frmControls, ["EPANET Simple Controls", "CONTROLS"] ] tree_controls_RuleBased = [ "Rule-Based", frmControls, ["EPANET Rule-Based Controls", "RULES"] ] tree_controls_items = [tree_controls_Simple, tree_controls_RuleBased] tree_TitleNotes = ["Title/Notes", frmTitle] tree_Options = ["Options", tree_options_items] tree_Junctions = ["Junctions", frmJunction] tree_Reservoirs = ["Reservoirs", frmReservior] tree_Tanks = ["Tanks", frmTank] tree_Pipes = ["Pipes", frmPipe] tree_Pumps = ["Pumps", frmPump] tree_Valves = ["Valves", frmValve] tree_Labels = ["Labels", None] tree_Patterns = ["Patterns", frmPatternEditor] tree_Curves = ["Curves", frmCurveEditor] tree_Controls = ["Controls", tree_controls_items] tree_top_items = [ tree_TitleNotes, tree_Options, tree_Junctions, tree_Reservoirs, tree_Tanks, tree_Pipes, tree_Pumps, tree_Valves, tree_Labels, tree_Patterns, tree_Curves, tree_Controls ] def __init__(self, q_application): self.model = "EPANET" self.program_settings = QtCore.QSettings(QtCore.QSettings.IniFormat, QtCore.QSettings.UserScope, "EPA", self.model) print("Read program settings from " + self.program_settings.fileName()) self.model_path = '' # Set this only if needed later when running model self.output = None # Set this when model output is available self.status_suffix = "_status.txt" self.status_file_name = '' # Set this when model status is available self.output_filename = '' # Set this when model output is available self.project_type = Project # Use the model-specific Project as defined in core.epanet.project self.project_reader_type = ProjectReader self.project_writer_type = ProjectWriter self.project = Project() self.assembly_path = os.path.dirname(os.path.abspath(__file__)) frmMain.__init__(self, q_application) self.on_load(tree_top_item_list=self.tree_top_items) self.tree_types = { self.tree_Patterns[0]: Pattern, self.tree_Curves[0]: Curve, self.tree_Junctions[0]: Junction, self.tree_Reservoirs[0]: Reservoir, self.tree_Tanks[0]: Tank, self.tree_Pipes[0]: Pipe, self.tree_Pumps[0]: Pump, self.tree_Valves[0]: Valve, self.tree_Labels[0]: Label } self.section_types = { Pattern: "patterns", Curve: "curves", Junction: "junctions", Reservoir: "reservoirs", Tank: "tanks", Pipe: "pipes", Pump: "pumps", Valve: "valves", Label: "labels" } if self.map_widget: # initialize empty model map layers, ready to have model elements added self.model_layers = ModelLayersEPANET(self.map_widget) HelpHandler.init_class(os.path.join(self.assembly_path, "epanet.qhc")) self.help_topic = "" # TODO: specify topic to open when Help key is pressed on main form self.helper = HelpHandler(self) self.actionStdProjSummary.triggered.connect( lambda: self.show_edit_window(self.get_editor("Title/Notes"))) self.actionStatus_ReportMenu = QtGui.QAction(self) self.actionStatus_ReportMenu.setObjectName( from_utf8("actionStatus_ReportMenu")) self.actionStatus_ReportMenu.setText(transl8("frmMain", "Status", None)) self.actionStatus_ReportMenu.setToolTip( transl8("frmMain", "Display Simulation Status", None)) self.menuReport.addAction(self.actionStatus_ReportMenu) QtCore.QObject.connect(self.actionStatus_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_status) self.actionProjStatus.triggered.connect(self.report_status) self.actionEnergy_ReportMenu = QtGui.QAction(self) self.actionEnergy_ReportMenu.setObjectName( from_utf8("actionEnergy_ReportMenu")) self.actionEnergy_ReportMenu.setText(transl8("frmMain", "Energy", None)) self.actionEnergy_ReportMenu.setToolTip( transl8("frmMain", "Display Simulation Energy", None)) self.menuReport.addAction(self.actionEnergy_ReportMenu) QtCore.QObject.connect(self.actionEnergy_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_energy) self.actionCalibration_ReportMenu = QtGui.QAction(self) self.actionCalibration_ReportMenu.setObjectName( from_utf8("actionCalibration_ReportMenu")) self.actionCalibration_ReportMenu.setText( transl8("frmMain", "Calibration", None)) self.actionCalibration_ReportMenu.setToolTip( transl8("frmMain", "Display Simulation Calibration", None)) self.menuReport.addAction(self.actionCalibration_ReportMenu) QtCore.QObject.connect(self.actionCalibration_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_calibration) self.actionReaction_ReportMenu = QtGui.QAction(self) self.actionReaction_ReportMenu.setObjectName( from_utf8("actionReaction_ReportMenu")) self.actionReaction_ReportMenu.setText( transl8("frmMain", "Reaction", None)) self.actionReaction_ReportMenu.setToolTip( transl8("frmMain", "Display Simulation Reaction", None)) self.menuReport.addAction(self.actionReaction_ReportMenu) QtCore.QObject.connect(self.actionReaction_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_reaction) self.actionFull_ReportMenu = QtGui.QAction(self) self.actionFull_ReportMenu.setObjectName( from_utf8("actionFull_ReportMenu")) self.actionFull_ReportMenu.setText(transl8("frmMain", "Full...", None)) self.actionFull_ReportMenu.setToolTip( transl8("frmMain", "Save full report as text file", None)) self.menuReport.addAction(self.actionFull_ReportMenu) QtCore.QObject.connect(self.actionFull_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_full) self.actionGraph_ReportMenu = QtGui.QAction(self) self.actionGraph_ReportMenu.setObjectName( from_utf8("actionGraph_ReportMenu")) self.actionGraph_ReportMenu.setText( transl8("frmMain", "Graph...", None)) self.actionGraph_ReportMenu.setToolTip( transl8("frmMain", "Display graph selection options", None)) self.menuReport.addAction(self.actionGraph_ReportMenu) QtCore.QObject.connect(self.actionGraph_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_graph) self.actionProjPlotTimeseries.triggered.connect(self.report_graph) self.actionProjPlotScatter.triggered.connect(self.report_graph) self.actionProjPlotProfile.triggered.connect(self.report_graph) self.actionTable_ReportMenu = QtGui.QAction(self) self.actionTable_ReportMenu.setObjectName( from_utf8("actionTable_ReportMenu")) self.actionTable_ReportMenu.setText( transl8("frmMain", "Table...", None)) self.actionTable_ReportMenu.setToolTip( transl8("frmMain", "Display table selection options", None)) self.menuReport.addAction(self.actionTable_ReportMenu) QtCore.QObject.connect(self.actionTable_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_table) self.actionProjTableTimeseries.triggered.connect(self.report_table) self.Help_Topics_Menu = QtGui.QAction(self) self.Help_Topics_Menu.setObjectName(from_utf8("Help_Topics_Menu")) self.Help_Topics_Menu.setText(transl8("frmMain", "Help Topics", None)) self.Help_Topics_Menu.setToolTip( transl8("frmMain", "Display Help Topics", None)) self.menuHelp.addAction(self.Help_Topics_Menu) QtCore.QObject.connect(self.Help_Topics_Menu, QtCore.SIGNAL('triggered()'), self.help_topics) self.Help_About_Menu = QtGui.QAction(self) self.Help_About_Menu.setObjectName(from_utf8("Help_About_Menu")) self.Help_About_Menu.setText(transl8("frmMain", "About", None)) self.Help_About_Menu.setToolTip( transl8("frmMain", "About EPANET", None)) self.menuHelp.addAction(self.Help_About_Menu) QtCore.QObject.connect(self.Help_About_Menu, QtCore.SIGNAL('triggered()'), self.help_about) self.cbFlowUnits.clear() self.cbFlowUnits.addItems([ 'Flow Units: CFS', 'Flow Units: GPM', 'Flow Units: MGD', 'Flow Units: IMGD', 'Flow Units: AFD', 'Flow Units: LPS', 'Flow Units: LPM', 'Flow Units: MLD', 'Flow Units: CMH', 'Flow Units: CMD' ]) self.cbFlowUnits.currentIndexChanged.connect( self.cbFlowUnits_currentIndexChanged) self.cbOffset.setVisible(False) if self.map_widget: self.map_widget.applyLegend() self.map_widget.LegendDock.setVisible(False) self.cboMapSubcatchments.setVisible(False) self.lblMapSubcatchments.setVisible(False) self.set_thematic_controls() self.cboMapNodes.currentIndexChanged.connect( self.update_thematic_map) self.cboMapLinks.currentIndexChanged.connect( self.update_thematic_map) self.signalTimeChanged.connect(self.update_thematic_map_time) def set_thematic_controls(self): self.allow_thematic_update = False self.cboMapNodes.clear() self.cboMapNodes.addItems( ['None', 'Elevation', 'Base Demand', 'Initial Quality']) self.cboMapLinks.clear() self.cboMapLinks.addItems([ 'None', 'Length', 'Diameter', 'Roughness', 'Bulk Coeff.', 'Wall Coeff.' ]) if self.output: # Add object type labels to map combos if there are any of each type in output object_type = ENO.ENR_node_type if object_type: attribute_names = [ attribute.name for attribute in object_type.Attributes ] for item in attribute_names: self.cboMapNodes.addItem(item) object_type = ENO.ENR_link_type if object_type: attribute_names = [ attribute.name for attribute in object_type.Attributes ] for item in attribute_names: self.cboMapLinks.addItem(item) self.horizontalTimeSlider.setMaximum(self.output.num_periods - 1) self.allow_thematic_update = True self.update_thematic_map() def update_thematic_map(self): if not self.allow_thematic_update or not self.map_widget: return enable_time_widget = False if self.model_layers.nodes_layers: selected_attribute = self.cboMapNodes.currentText() attribute = None setting_index = self.cboMapNodes.currentIndex() if setting_index < 4: meta_item = Junction.metadata.meta_item_of_label( selected_attribute) attribute = meta_item.attribute color_by = {} self.thematic_node_min = None self.thematic_node_max = None if attribute: # Found an attribute of the node class to color by for item in self.project.all_nodes(): value = float(getattr(item, attribute, 0)) color_by[item.name] = value if self.thematic_node_min is None or value < self.thematic_node_min: self.thematic_node_min = value if self.thematic_node_max is None or value > self.thematic_node_max: self.thematic_node_max = value elif self.output: # Look for attribute to color by in the output attribute = ENO.ENR_node_type.get_attribute_by_name( selected_attribute) if attribute: enable_time_widget = True # find min and max values over entire run for time_increment in range(0, self.output.num_periods - 1): values = ENO.ENR_node_type.get_attribute_for_all_at_time( self.output, attribute, time_increment) for value in values: if self.thematic_node_min is None or value < self.thematic_node_min: self.thematic_node_min = value if self.thematic_node_max is None or value > self.thematic_node_max: self.thematic_node_max = value values = ENO.ENR_node_type.get_attribute_for_all_at_time( self.output, attribute, self.time_index) index = 0 for node in self.output.nodes.values(): color_by[node.name] = values[index] index += 1 for layer in self.model_layers.nodes_layers: if layer.isValid(): if color_by: self.map_widget.applyGraduatedSymbologyStandardMode( layer, color_by, self.thematic_node_min, self.thematic_node_max) else: self.map_widget.set_default_point_renderer(layer) layer.triggerRepaint() if self.model_layers.links_layers: selected_attribute = self.cboMapLinks.currentText() attribute = None setting_index = self.cboMapLinks.currentIndex() if setting_index < 6: meta_item = Pipe.metadata.meta_item_of_label( selected_attribute) attribute = meta_item.attribute color_by = {} self.thematic_link_min = None self.thematic_link_max = None if attribute: # Found an attribute of the pipe class to color by for link in self.project.all_links(): try: if attribute == 'max_depth': pass # for value in self.project.xsections.value: # if value.link == conduit.name: # color_by[conduit.name] = float(value.geometry1) else: color_by[link.name] = float( getattr(link, attribute, 0)) if self.thematic_link_min is None or color_by[ link.name] < self.thematic_link_min: self.thematic_link_min = color_by[link.name] if self.thematic_link_max is None or color_by[ link.name] > self.thematic_link_max: self.thematic_link_max = color_by[link.name] except Exception as exLinkAtt: print("update_thematic_map: link attribute: " + link.name + ': ' + str(exLinkAtt)) elif self.output: # Look for attribute to color by in the output attribute = ENO.ENR_link_type.get_attribute_by_name( selected_attribute) if attribute: enable_time_widget = True # find min and max values over entire run for time_increment in range(0, self.output.num_periods - 1): values = ENO.ENR_link_type.get_attribute_for_all_at_time( self.output, attribute, time_increment) for value in values: if self.thematic_link_min is None or value < self.thematic_link_min: self.thematic_link_min = value if self.thematic_link_max is None or value > self.thematic_link_max: self.thematic_link_max = value values = ENO.ENR_link_type.get_attribute_for_all_at_time( self.output, attribute, self.time_index) index = 0 for link in self.output.links.values(): color_by[link.name] = values[index] index += 1 for layer in self.model_layers.links_layers: if layer.isValid(): if color_by: self.map_widget.applyGraduatedSymbologyStandardMode( layer, color_by, self.thematic_link_min, self.thematic_link_max) else: self.map_widget.set_default_line_renderer(layer) layer.triggerRepaint() self.time_widget.setVisible(enable_time_widget) if enable_time_widget: self.update_thematic_map_time() def update_thematic_map_time(self): """ Update thematic map for the current self.time_index. Depends on update_thematic_map having been called since last change to thematic map options. """ try: if not self.allow_thematic_update or not self.map_widget: return if self.model_layers.nodes_layers: selected_attribute = self.cboMapNodes.currentText() setting_index = self.cboMapNodes.currentIndex() color_by = {} if setting_index >= 4 and self.output: # Look for attribute to color by in the output attribute = ENO.ENR_node_type.get_attribute_by_name( selected_attribute) if attribute: values = ENO.ENR_node_type.get_attribute_for_all_at_time( self.output, attribute, self.time_index) index = 0 for node in self.output.nodes.values(): color_by[node.name] = values[index] index += 1 for layer in self.model_layers.nodes_layers: if layer.isValid(): if color_by: self.map_widget.applyGraduatedSymbologyStandardMode( layer, color_by, self.thematic_node_min, self.thematic_node_max) else: self.map_widget.set_default_point_renderer(layer) layer.triggerRepaint() if self.model_layers.links_layers: selected_attribute = self.cboMapLinks.currentText() setting_index = self.cboMapLinks.currentIndex() color_by = {} if setting_index >= 6 and self.output: # Look for attribute to color by in the output attribute = ENO.ENR_link_type.get_attribute_by_name( selected_attribute) if attribute: values = ENO.ENR_link_type.get_attribute_for_all_at_time( self.output, attribute, self.time_index) index = 0 for link in self.output.links.values(): color_by[link.name] = values[index] index += 1 for layer in self.model_layers.links_layers: if layer.isValid(): if color_by: self.map_widget.applyGraduatedSymbologyStandardMode( layer, color_by, self.thematic_link_min, self.thematic_link_max) else: self.map_widget.set_default_line_renderer(layer) layer.triggerRepaint() except Exception as exBig: print("Exception in update_thematic_map_time: " + str(exBig)) def cboMap_currentIndexChanged(self): pass def cbFlowUnits_currentIndexChanged(self): import core.epanet.options.hydraulics self.project.options.hydraulics.flow_units = core.epanet.options.hydraulics.FlowUnits[ self.cbFlowUnits.currentText()[12:]] self.project.metric = self.project.options.hydraulics.flow_units in core.epanet.options.hydraulics.flow_units_metric def report_status(self): print "report_status" if not os.path.isfile(self.status_file_name): prefix, extension = os.path.splitext(self.project.file_name) if os.path.isfile(prefix + self.status_suffix): self.status_file_name = prefix + self.status_suffix if os.path.isfile(self.status_file_name): webbrowser.open_new_tab(self.status_file_name) else: QMessageBox.information( None, self.model, "Model status not found.\n" "Run the model to generate model status.", QMessageBox.Ok) def report_energy(self): if self.output: self._frmEnergyReport = frmEnergyReport(self) self._frmEnergyReport.set_data(self.project, self.output) self._frmEnergyReport.show() else: QMessageBox.information( None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_calibration(self): if self.output: self._frmCalibrationReportOptions = frmCalibrationReportOptions( self, self.project, self.output) self._frmCalibrationReportOptions.show() else: QMessageBox.information( None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_reaction(self): self.reaction_report() pass def report_full(self): if self.output: directory = os.path.dirname(self.project.file_name) report_file_name = QtGui.QFileDialog.getSaveFileName( self, "Save Full Report As...", directory, "Text files (*.txt)") if report_file_name: try: reporter = reports.Reports(self.project, self.output) reporter.write_report(report_file_name) webbrowser.open_new_tab(report_file_name) except Exception as e1: msg = str(e1) + '\n' + str(traceback.print_exc()) print(msg) QMessageBox.information( None, self.model, "Error writing report to \n" + report_file_name + '\n' + msg, QMessageBox.Ok) else: QMessageBox.information( None, self.model, "There is no model output currently open.\n" "Model output is automatically opened after model is run.", QMessageBox.Ok) def report_graph(self): if self.output: self._frmGraph = frmGraph(self) self._frmGraph.set_from(self.project, self.output) self._frmGraph.show() else: QMessageBox.information( None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_table(self): if self.output: self._frmTable = frmTable(self) self._frmTable.set_from(self.project, self.output) self._frmTable.show() else: QMessageBox.information( None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def reaction_report(self): # Reaction Report' if self.output: # Find conversion factor to kilograms/day ucf = 1.0e6 / 24 quality_options = self.project.options.quality if 'ug' in str(quality_options.mass_units): ucf = 1.0e9 / 24 # Get average reaction rates from output file bulk, wall, tank, source = self.output.get_reaction_summary() bulk /= ucf wall /= ucf tank /= ucf source /= ucf if bulk > 0 or wall > 0 or tank > 0 or source > 0: footer_text = "Inflow Rate = " + format(source, '0.1f') else: footer_text = 'No reactions occurred' import matplotlib.pyplot as plt labels = "%10.1f Tanks" % tank, "%10.1f Bulk" % bulk, "%10.1f Wall" % wall sum_reaction = bulk + wall + tank size_bulk = bulk / sum_reaction size_wall = wall / sum_reaction size_tank = tank / sum_reaction sizes = [size_tank, size_bulk, size_wall] colors = ['green', 'blue', 'red'] explode = (0, 0, 0) plt.figure("Reaction Report") plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.2f%%', shadow=True, startangle=180) plt.axis('equal') plt.suptitle("Average Reaction Rates (kg/day)", fontsize=16) plt.text(0.9, -0.9, footer_text) plt.show() else: QMessageBox.information( None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def calibration_data(self): self._frmCalibrationData = frmCalibrationData(self) self._frmCalibrationData.show() pass def get_editor(self, edit_name): frm = None # First handle special cases where forms need more than simply being created # the following items will respond to a click on a node form, not the tree diagram if edit_name == 'Labels': edit_these = [] if self.project and self.project.labels: if not isinstance(self.project.labels.value, basestring): if isinstance(self.project.labels.value, list): edit_these.extend(self.project.labels.value) if len(edit_these) == 0: new_item = Label() new_item.name = "NewLabel" edit_these.append(new_item) self.project.labels.value = edit_these else: self.new_item = False frm = frmGenericPropertyEditor(self, edit_these, new_item, "EPANET Map Label Editor") frm.helper = HelpHandler(frm) frm.help_topic = "epanet/src/src/maplabeleditordialog.htm" elif edit_name == 'Patterns' or edit_name == 'Curves': # in these cases the click on the tree diagram populates the lower left list, not directly to an editor return None elif edit_name == self.tree_Junctions[0] and len( self.project.junctions.value) == 0: return None elif edit_name == self.tree_Reservoirs[0] and len( self.project.reservoirs.value) == 0: return None elif edit_name == self.tree_Tanks[0] and len( self.project.tanks.value) == 0: return None elif edit_name == self.tree_Pipes[0] and len( self.project.pipes.value) == 0: return None elif edit_name == self.tree_Pumps[0] and len( self.project.pumps.value) == 0: return None elif edit_name == self.tree_Valves[0] and len( self.project.valves.value) == 0: return None elif edit_name == self.tree_Labels[0] and len( self.project.labels.value) == 0: return None else: # General-purpose case finds most editors from tree information frm = self.make_editor_from_tree(edit_name, self.tree_top_items) return frm def get_editor_with_selected_items(self, edit_name, selected_items): return self.make_editor_from_tree(edit_name, self.tree_top_items, selected_items) def get_object_list(self, category): section = self.project.find_section(category) if category == 'Quality' or category == 'Controls' or category == 'Reactions': return None if section and isinstance(section.value, list): return [item.name for item in section.value] else: return None def add_object(self, tree_text): item_type = self.tree_types[tree_text] new_item = item_type() new_item.name = self.new_item_name(item_type) self.show_edit_window( self.make_editor_from_tree(self.tree_section, self.tree_top_items, [], new_item)) def delete_named_object(self, tree_text, item_name): item_type = self.tree_types[tree_text] section_field_name = self.section_types[item_type] if hasattr(self.project, section_field_name): section = getattr(self.project, section_field_name) else: raise Exception("Section not found in project: " + section_field_name) item = section.value[item_name] self.delete_item(item) def run_simulation(self): # Find input file to run # TODO: decide whether to automatically save to temp location as previous version did. use_existing = self.project and self.project.file_name if use_existing: self.save_project(self.project.file_name) elif self.project.all_nodes(): # unsaved changes to a new project have been made, prompt to save if self.save_project_as(): use_existing = True else: return None else: self.open_project() inp_file_name = '' if self.project: inp_file_name = self.project.file_name if os.path.exists(inp_file_name): current_directory = os.getcwd() if not os.path.exists(self.model_path): if 'darwin' in sys.platform: lib_name = 'libepanet.dylib.dylib' elif 'win' in sys.platform: lib_name = 'epanet2_amd64.dll' else: # Linux lib_name = 'libepanet2_amd64.so' self.model_path = self.find_external(lib_name) if os.path.exists(self.model_path): try: prefix, extension = os.path.splitext(inp_file_name) self.status_file_name = prefix + self.status_suffix self.output_filename = prefix + '.out' working_dir = os.path.abspath( os.path.dirname(inp_file_name)) if os.path.isdir(working_dir): print( "Changing into directory containing input file: " + working_dir) os.chdir(working_dir) else: try: import tempfile working_dir = tempfile.gettempdir() print("Changing into temporary directory: " + working_dir) os.chdir(working_dir) except Exception as err_temp: print( "Could not change into temporary directory: " + str(err_temp)) if self.output: self.output.close() self.output = None model_api = ENepanet(inp_file_name, self.status_file_name, self.output_filename, self.model_path) frmRun = frmRunEPANET(model_api, self.project, self) self._forms.append(frmRun) frmRun.Execute() # self.report_status() try: self.output = ENOutputWrapper.OutputObject( self.output_filename) self.set_thematic_controls() return except Exception as e1: print(str(e1) + '\n' + str(traceback.print_exc())) QMessageBox.information( None, self.model, "Error opening model output:\n {0}\n{1}\n{2}". format(self.output_filename, str(e1), str(traceback.print_exc())), QMessageBox.Ok) except Exception as e1: print(str(e1) + '\n' + str(traceback.print_exc())) QMessageBox.information( None, self.model, "Error running model with library:\n {0}\n{1}\n{2}". format(self.model_path, str(e1), str(traceback.print_exc())), QMessageBox.Ok) finally: try: os.chdir(current_directory) if model_api and model_api.isOpen(): model_api.ENclose() except: pass return # # Could not run with library, try running with executable # # Run executable with StatusMonitor0 # args = [] # self.modelenv1 = 'EXE_EPANET' # program = os.environ[self.modelenv1] # # exe_name = "epanet2d.exe" # exe_path = os.path.join(self.assembly_path, exe_name) # if not os.path.exists(exe_path): # pp = os.path.dirname(os.path.dirname(self.assembly_path)) # exe_path = os.path.join(pp, "Externals", exe_name) # if not os.path.exists(exe_path): # exe_path = QFileDialog.getOpenFileName(self, 'Locate EPANET Executable', '/', # 'exe files (*.exe)') # if os.path.exists(exe_path): # os.environ[self.modelenv1] = exe_path # else: # os.environ[self.modelenv1] = '' # # if not os.path.exists(program): # QMessageBox.information(None, "EPANET", "EPANET Executable not found", QMessageBox.Ok) # return -1 # # args.append(file_name) # args.append(prefix + '.txt') # args.append(prefix + '.out') # status = model_utility.StatusMonitor0(program, args, self, model='EPANET') # status.show() # os.chdir(current_directory) else: QMessageBox.information(None, self.model, self.model + " input file not found", QMessageBox.Ok) def help_topics(self): self.helper.show_help() def help_about(self): self._frmAbout = frmAbout(self) self._frmAbout.show() def open_project_quiet(self, file_name): """ Set wait cursor during open to show operation is in progress. Open project from file_name using frmMain.open_project_quiet. Create model layers on map and set UI controls from opened project. """ self.setWaitCursor() if file_name: self.setWindowTitle("Reading " + file_name) if self.map_widget: self.map_widget.setVisible(False) self.repaint() frmMain.open_project_quiet(self, file_name) ui.convenience.set_combo( self.cbFlowUnits, 'Flow Units: ' + self.project.options.hydraulics.flow_units.name) if self.time_widget: self.labelStartTime.setText('0:00') self.labelEndTime.setText(self.project.times.duration) if self.map_widget: try: self.model_layers.create_layers_from_project(self.project) self.map_widget.zoomfull() self.setQgsMapTool( ) # Reset any active tool that still has state from old project except Exception as ex: print(str(ex) + '\n' + str(traceback.print_exc())) self.map_widget.setVisible(True) self.restoreCursor()
class frmMapDimensions(QDialog): def __init__(self, main_form=None, *args): QDialog.__init__(self) self.helper = HelpHandler(self) if main_form.model == "SWMM": self.help_topic = "swmm/src/src/mapdimensionsdialog.htm" elif main_form.model == "EPANET": self.help_topic = "epanet/src/src/Map_Dime.htm" self.ui = Ui_frmMapDimensionsDesigner() self.ui.setupUi(self) self.session = main_form self.icon = main_form.windowIcon() self.map_widget = self.session.map_widget self.options = None if args is not None and len(args) > 0: self.options = args[0] self.ui.rdoUnitDegrees.toggled.connect(self.changeLinearMapUnit) self.ui.rdoUnitNone.toggled.connect(self.changeLinearMapUnit) self.ui.rdoUnitFeet.toggled.connect(self.changeLinearMapUnit) self.ui.rdoUnitMeters.toggled.connect(self.changeLinearMapUnit) self.ui.txtLLx.textChanged.connect( lambda: self.checkCoords(self.ui.txtLLx.text())) self.ui.txtLLy.textChanged.connect( lambda: self.checkCoords(self.ui.txtLLy.text())) self.ui.txtURx.textChanged.connect( lambda: self.checkCoords(self.ui.txtURx.text())) self.ui.txtURy.textChanged.connect( lambda: self.checkCoords(self.ui.txtURy.text())) self.ui.btnAutoSize.clicked.connect(self.autoSetMapDimensions) self.ui.buttonBox.accepted.connect(self.setExtent) self.ui.btnHelp.clicked.connect(self.show_help) self.setupOptions() def autoSetMapDimensions(self): # Determines map dimensions based on range of vertices' coordinates MAXDEGDIGITS = 4 # Max.decimal digits for lat - long degrees pass sigDigit = 2 if self.ui.rdoUnitDegrees.isChecked(): sigDigit = MAXDEGDIGITS self.display_layers_extent() def setExtent(self): if self.session is None: return if self.map_widget is None: return val1, is_val_good1 = self.floatTryParse(self.ui.txtLLx.text()) val2, is_val_good2 = self.floatTryParse(self.ui.txtLLy.text()) val3, is_val_good3 = self.floatTryParse(self.ui.txtURx.text()) val4, is_val_good4 = self.floatTryParse(self.ui.txtURy.text()) if is_val_good1 and is_val_good2 and is_val_good3 and is_val_good4: if val1 == val3 or val2 == val4: #MSG_ILLEGAL_MAP_LIMITS #LLXEdit.SetFocus return else: self.map_widget.coord_origin.x = val1 self.map_widget.coord_origin.y = val2 self.map_widget.coord_fext.x = val3 self.map_widget.coord_fext.y = val4 if self.session.project is not None: if self.session.project.map is not None: self.session.project.map.dimensions = (val1, val2, val3, val4) self.session.map_widget.set_extent_by_corners( self.session.project.map.dimensions) if self.session.project is not None: if self.session.project.backdrop is not None: self.session.project.backdrop.dimensions = ( self.ui.txtLLx.text(), self.ui.txtLLy.text(), self.ui.txtURx.text(), self.ui.txtURy.text()) if self.ui.rdoUnitFeet.isChecked(): if not isinstance( self.session.project.backdrop.units, str): self.session.project.backdrop.units = self.session.project.backdrop.units.FEET else: self.session.project.backdrop.units = "FEET" elif self.ui.rdoUnitMeters.isChecked(): if not isinstance( self.session.project.backdrop.units, str): self.session.project.backdrop.units = self.session.project.backdrop.units.METERS else: self.session.project.backdrop.units = "METERS" elif self.ui.rdoUnitDegrees.isChecked(): if not isinstance( self.session.project.backdrop.units, str): self.session.project.backdrop.units = self.session.project.backdrop.units.DEGREES else: self.session.project.backdrop.units = "DEGREES" else: if not isinstance( self.session.project.backdrop.units, str): self.session.project.backdrop.units = self.session.project.backdrop.units.NONE else: self.session.project.backdrop.units = "" pass def setupOptions(self): if self.session is None: return if self.map_widget is None: return model_dim = self.session.project.backdrop.dimensions if model_dim and model_dim[0] is not None and model_dim[ 1] is not None and model_dim[2] is not None and model_dim[ 3] is not None: #self.ui.txtLLx.setText('{:.3f}'.format(self._main_form.map_widget.coord_origin.x)) #self.ui.txtLLy.setText('{:.3f}'.format(self._main_form.map_widget.coord_origin.y)) #self.ui.txtURx.setText('{:.3f}'.format(self._main_form.map_widget.coord_fext.x)) #self.ui.txtURy.setText('{:.3f}'.format(self._main_form.map_widget.coord_fext.x)) self.ui.txtLLx.setText(str(model_dim[0])) self.ui.txtLLy.setText(str(model_dim[1])) self.ui.txtURx.setText(str(model_dim[2])) self.ui.txtURy.setText(str(model_dim[3])) else: self.display_layers_extent() if not isinstance(self.session.project.backdrop.units, str): units = self.session.project.backdrop.units.name else: units = self.session.project.backdrop.units.upper() if units == "FEET": # feet self.ui.rdoUnitFeet.setChecked(True) elif units == "METERS": # meters self.ui.rdoUnitMeters.setChecked(True) elif units == "DEGREES": # degrees self.ui.rdoUnitDegrees.setChecked(True) else: self.ui.rdoUnitNone.setChecked(True) self.setWindowIcon(self.icon) def display_layers_extent(self): if self.session.model_layers: llx = 0 lly = 0 urx = 10000 ury = 10000 layers = [] for mlyr in self.session.model_layers.all_layers: lyr_name = mlyr.name() if lyr_name and \ (lyr_name.lower().startswith("label") or lyr_name.lower().startswith("subcentroid") or lyr_name.lower().startswith("sublink")): continue layers.append(mlyr) r = self.session.map_widget.get_extent(layers) llx = r.xMinimum() lly = r.yMinimum() urx = r.xMaximum() ury = r.yMaximum() self.ui.txtLLx.setText(str(llx)) self.ui.txtLLy.setText(str(lly)) self.ui.txtURx.setText(str(urx)) self.ui.txtURy.setText(str(ury)) def floatTryParse(self, value): try: return float(value), True except ValueError: return value, False def changeLinearMapUnit(self): if self.session is None: return if self.map_widget is None: return if self.ui.rdoUnitDegrees.isChecked(): self.map_widget.map_linear_unit = self.map_widget.map_unit_names[ 6] # Degrees elif self.ui.rdoUnitMeters.isChecked(): self.map_widget.map_linear_unit = self.map_widget.map_unit_names[ 0] # Meters elif self.ui.rdoUnitNone.isChecked(): self.map_widget.map_linear_unit = self.map_widget.map_unit_names[ 7] # Unknown elif self.ui.rdoUnitFeet.isChecked(): self.map_widget.map_linear_unit = self.map_widget.map_unit_names[ 2] # Feet if self.session.project is not None: if self.session.project.map is not None: self.session.project.map.setMapUnits( self.session.map_widget.map_linear_unit) return def checkCoords(self, avalue): if len(avalue) == 0: return if len(avalue) == 1 and avalue[0] == '-': return val, value_is_good = self.floatTryParse(avalue) if not value_is_good: msg = QMessageBox() msg.setWindowTitle('Map Dimension') msg.setText('Coordinate value is not valid numeric value.') msg.setStandardButtons(QMessageBox.Ok) msg.exec_() del msg pass def coordsInGoodFormat(self): val1, is_val_good1 = self.floatTryParse(self.ui.txtLLx.text()) val2, is_val_good2 = self.floatTryParse(self.ui.txtLLy.text()) val3, is_val_good3 = self.floatTryParse(self.ui.txtURx.text()) val4, is_val_good4 = self.floatTryParse(self.ui.txtURy.text()) if is_val_good1 and is_val_good2 and is_val_good3 and is_val_good4: if val1 == val3 or val2 == val4: #MSG_ILLEGAL_MAP_LIMITS #LLXEdit.SetFocus return False else: return True else: return False def show_help(self): self.helper.show_help()
class frmMainSWMM(frmMain): """Main form for SWMM user interface, based on frmMain which is shared with EPANET.""" # Variables used to populate the tree control # Each item is a list: label plus either editing form for this section or a child list of tree variables. # If an editing form takes additional arguments, they follow the editing form as a list. # Special cases may just have a label and no editing form or children. # *_items are a lists of items in a section tree_options_General = ["General", frmGeneralOptions] tree_options_Dates = ["Dates", frmDates] tree_options_TimeSteps = ["Time Steps", frmTimeSteps] tree_options_DynamicWave = ["Dynamic Wave", frmDynamicWave] tree_options_InterfaceFiles = ["Interface Files", frmInterfaceFiles] tree_options_Reporting = ["Reporting", frmReportOptions] tree_options_MapBackdrop = ["Map/Backdrop", frmMapBackdropOptions] tree_options_items = [ tree_options_General, tree_options_Dates, tree_options_TimeSteps, tree_options_DynamicWave, tree_options_InterfaceFiles, tree_options_Reporting, tree_options_MapBackdrop] tree_climatology_Temperature = ["Temperature", frmClimatology, ["Temperature"]] tree_climatology_Evaporation = ["Evaporation", frmClimatology, ["Evaporation"]] tree_climatology_WindSpeed = ["Wind Speed", frmClimatology, ["Wind Speed"]] tree_climatology_SnowMelt = ["Snow Melt", frmClimatology, ["Snow Melt"]] tree_climatology_ArealDepletion = ["Areal Depletion", frmClimatology, ["Areal Depletion"]] tree_climatology_Adjustment = ["Adjustment", frmClimatology, ["Adjustment"]] tree_climatology_items = [ tree_climatology_Temperature, tree_climatology_Evaporation, tree_climatology_WindSpeed, tree_climatology_SnowMelt, tree_climatology_ArealDepletion, tree_climatology_Adjustment] tree_hydrology_RainGages = ["Rain Gages", None] tree_hydrology_Subcatchments = ["Subcatchments", frmSubcatchments] tree_hydrology_Aquifers = ["Aquifers", frmAquifers] tree_hydrology_SnowPacks = ["Snow Packs", frmSnowPack] tree_hydrology_UnitHydrographs = ["Unit Hydrographs", frmUnitHydrograph] tree_hydrology_LIDControls = ["LID Controls", frmLID] tree_hydrology_items = [ tree_hydrology_RainGages, tree_hydrology_Subcatchments, tree_hydrology_Aquifers, tree_hydrology_SnowPacks, tree_hydrology_UnitHydrographs, tree_hydrology_LIDControls] tree_nodes_Junctions = ["Junctions", frmJunction] tree_nodes_Outfalls = ["Outfalls", None, "1"] tree_nodes_Dividers = ["Dividers", None, "1"] tree_nodes_StorageUnits = ["Storage Units", None, "1"] tree_nodes_items = [ tree_nodes_Junctions, tree_nodes_Outfalls, tree_nodes_Dividers, tree_nodes_StorageUnits] tree_links_Conduits = ["Conduits", frmCrossSection] tree_links_Pumps = ["Pumps", None] tree_links_Orifices = ["Orifices", None] tree_links_Weirs = ["Weirs", None] tree_links_Outlets = ["Outlets", None] tree_links_items = [ tree_links_Conduits, tree_links_Pumps, tree_links_Orifices, tree_links_Weirs, tree_links_Outlets] tree_hydraulics_Nodes = ["Nodes", tree_nodes_items] tree_hydraulics_Links = ["Links", tree_links_items] tree_hydraulics_Transects = ["Transects", frmTransect] tree_hydraulics_Controls = ["Controls", frmControls] tree_hydraulics_items = [ tree_hydraulics_Nodes, tree_hydraulics_Links, tree_hydraulics_Transects, tree_hydraulics_Controls] tree_quality_Pollutants = ["Pollutants", None] tree_quality_LandUses = ["Land Uses", frmLandUses] tree_quality_items = [ tree_quality_Pollutants, tree_quality_LandUses] tree_curves_ControlCurves = ["Control Curves", frmCurveEditor, ["SWMM Control Curves", "CONTROL"]] tree_curves_DiversionCurves = ["Diversion Curves", frmCurveEditor, ["SWMM Diversion Curves", "DIVERSION"]] tree_curves_PumpCurves = ["Pump Curves", frmCurveEditor, ["SWMM Pump Curves", "PUMP"]] tree_curves_RatingCurves = ["Rating Curves", frmCurveEditor, ["SWMM Rating Curves", "RATING"]] tree_curves_ShapeCurves = ["Shape Curves", frmCurveEditor, ["SWMM Shape Curves", "SHAPE"]] tree_curves_StorageCurves = ["Storage Curves", frmCurveEditor, ["SWMM Storage Curves", "STORAGE"]] tree_curves_TidalCurves = ["Tidal Curves", frmCurveEditor, ["SWMM Tidal Curves", "TIDAL"]] tree_curves_items = [ tree_curves_ControlCurves, tree_curves_DiversionCurves, tree_curves_PumpCurves, tree_curves_RatingCurves, tree_curves_ShapeCurves, tree_curves_StorageCurves, tree_curves_TidalCurves] tree_TitleNotes = ["Title/Notes", frmTitle] tree_Options = ["Options", tree_options_items] tree_Climatology = ["Climatology", tree_climatology_items] tree_Hydrology = ["Hydrology", tree_hydrology_items] tree_Hydraulics = ["Hydraulics", tree_hydraulics_items] tree_Quality = ["Quality", tree_quality_items] tree_Curves = ["Curves", tree_curves_items] tree_TimeSeries = ["Time Series", frmTimeseries] tree_TimePatterns = ["Time Patterns", frmPatternEditor] tree_MapLabels = ["Map Labels", None] tree_top_items = [ tree_TitleNotes, tree_Options, tree_Climatology, tree_Hydrology, tree_Hydraulics, tree_Quality, tree_Curves, tree_TimeSeries, tree_TimePatterns, tree_MapLabels] tree_items_using_id = (tree_hydrology_LIDControls, tree_hydrology_UnitHydrographs, tree_hydrology_SnowPacks, tree_hydraulics_Transects, tree_quality_LandUses, tree_TimeSeries, tree_TimePatterns, tree_curves_ControlCurves, tree_curves_DiversionCurves, tree_curves_PumpCurves, tree_curves_RatingCurves, tree_curves_ShapeCurves, tree_curves_StorageCurves, tree_curves_TidalCurves) def __init__(self, q_application): frmMain.__init__(self, q_application) self.model = "SWMM" self.model_path = '' # Set this only if needed later when running model self.output = None # Set this when model output is available self.status_suffix = "_status.txt" self.status_file_name = '' # Set this when model status is available self.output_filename = '' # Set this when model output is available self.project_type = Project # Use the model-specific Project as defined in core.swmm.project self.project = Project() self.assembly_path = os.path.dirname(os.path.abspath(__file__)) self.on_load(tree_top_item_list=self.tree_top_items) HelpHandler.init_class(os.path.join(self.assembly_path, "swmm.qhc")) self.helper = HelpHandler(self) self.help_topic = "swmm/src/src/swmmsmainwindow.htm" self.actionStatus_ReportMenu = QtGui.QAction(self) self.actionStatus_ReportMenu.setObjectName(from_utf8("actionStatus_ReportMenu")) self.actionStatus_ReportMenu.setText(transl8("frmMain", "Status", None)) self.actionStatus_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Status", None)) self.menuReport.addAction(self.actionStatus_ReportMenu) QtCore.QObject.connect(self.actionStatus_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_status) self.actionSummary_ReportMenu = QtGui.QAction(self) self.actionSummary_ReportMenu.setObjectName(from_utf8("actionSummary_ReportMenu")) self.actionSummary_ReportMenu.setText(transl8("frmMain", "Summary", None)) self.actionSummary_ReportMenu.setToolTip(transl8("frmMain", "Display Results Summary", None)) self.menuReport.addAction(self.actionSummary_ReportMenu) QtCore.QObject.connect(self.actionSummary_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_summary) menu = QtGui.QMenu() submenuGraph = QtGui.QMenu(self.menuReport) submenuGraph.setTitle("Graph") self.menuReport.addMenu(submenuGraph) self.actionGraph_ProfileMenu = QtGui.QAction(self) self.actionGraph_ProfileMenu.setObjectName(from_utf8("actionGraph_ProfileMenu")) self.actionGraph_ProfileMenu.setText(transl8("frmMain", "Profile", None)) self.actionGraph_ProfileMenu.setToolTip(transl8("frmMain", "Display Profile Plot", None)) submenuGraph.addAction(self.actionGraph_ProfileMenu) QtCore.QObject.connect(self.actionGraph_ProfileMenu, QtCore.SIGNAL('triggered()'), self.report_profile) self.actionGraph_TimeSeriesMenu = QtGui.QAction(self) self.actionGraph_TimeSeriesMenu.setObjectName(from_utf8("actionGraph_TimeSeriesMenu")) self.actionGraph_TimeSeriesMenu.setText(transl8("frmMain", "Time Series", None)) self.actionGraph_TimeSeriesMenu.setToolTip(transl8("frmMain", "Display Time Series Plot", None)) submenuGraph.addAction(self.actionGraph_TimeSeriesMenu) QtCore.QObject.connect(self.actionGraph_TimeSeriesMenu, QtCore.SIGNAL('triggered()'), self.report_timeseries) self.actionGraph_ScatterMenu = QtGui.QAction(self) self.actionGraph_ScatterMenu.setObjectName(from_utf8("actionGraph_ScatterMenu")) self.actionGraph_ScatterMenu.setText(transl8("frmMain", "Scatter", None)) self.actionGraph_ScatterMenu.setToolTip(transl8("frmMain", "Display Scatter Plot", None)) submenuGraph.addAction(self.actionGraph_ScatterMenu) QtCore.QObject.connect(self.actionGraph_ScatterMenu, QtCore.SIGNAL('triggered()'), self.report_scatter) self.actionTable_VariableMenu = QtGui.QAction(self) self.actionTable_VariableMenu.setObjectName(from_utf8("actionTable_VariableMenu")) self.actionTable_VariableMenu.setText(transl8("frmMain", "Table", None)) self.actionTable_VariableMenu.setToolTip(transl8("frmMain", "Display Table", None)) self.menuReport.addAction(self.actionTable_VariableMenu) QtCore.QObject.connect(self.actionTable_VariableMenu, QtCore.SIGNAL('triggered()'), self.report_variable) self.actionStatistics_ReportMenu = QtGui.QAction(self) self.actionStatistics_ReportMenu.setObjectName(from_utf8("actionStatistics_ReportMenu")) self.actionStatistics_ReportMenu.setText(transl8("frmMain", "Statistics", None)) self.actionStatistics_ReportMenu.setToolTip(transl8("frmMain", "Display Results Statistics", None)) self.menuReport.addAction(self.actionStatistics_ReportMenu) QtCore.QObject.connect(self.actionStatistics_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_statistics) self.Help_Topics_Menu = QtGui.QAction(self) self.Help_Topics_Menu.setObjectName(from_utf8("Help_Topics_Menu")) self.Help_Topics_Menu.setText(transl8("frmMain", "Help Topics", None)) self.Help_Topics_Menu.setToolTip(transl8("frmMain", "Display Help Topics", None)) self.menuHelp.addAction(self.Help_Topics_Menu) QtCore.QObject.connect(self.Help_Topics_Menu, QtCore.SIGNAL('triggered()'), self.help_topics) self.Help_About_Menu = QtGui.QAction(self) self.Help_About_Menu.setObjectName(from_utf8("Help_About_Menu")) self.Help_About_Menu.setText(transl8("frmMain", "About", None)) self.Help_About_Menu.setToolTip(transl8("frmMain", "About SWMM", None)) self.menuHelp.addAction(self.Help_About_Menu) QtCore.QObject.connect(self.Help_About_Menu, QtCore.SIGNAL('triggered()'), self.help_about) def get_output(self): if not self.output: if os.path.isfile(self.output_filename): self.output = SMOutputWrapper.OutputObject(self.output_filename) return self.output def report_status(self): print "report_status" if not os.path.isfile(self.status_file_name): prefix, extension = os.path.splitext(self.project.file_name) if os.path.isfile(prefix + self.status_suffix): self.status_file_name = prefix + self.status_suffix if os.path.isfile(self.status_file_name): webbrowser.open_new_tab(self.status_file_name) else: QMessageBox.information(None, self.model, "Model status not found.\n" "Run the model to generate model status.", QMessageBox.Ok) def report_profile(self): if self.get_output(): self._frmProfilePlot = frmProfilePlot(self) self._frmProfilePlot.set_from(self.project, self.get_output()) self._frmProfilePlot.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_timeseries(self): if self.get_output(): self._frmTimeSeriesPlot = frmTimeSeriesPlot(self) self._frmTimeSeriesPlot.set_from(self.project, self.get_output()) self._frmTimeSeriesPlot.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_scatter(self): if self.get_output(): self._frmScatterPlot = frmScatterPlot(self) self._frmScatterPlot.set_from(self.project, self.get_output()) self._frmScatterPlot.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_variable(self): if self.get_output(): self._frmTableSelection = frmTableSelection(self) self._frmTableSelection.set_from(self.project, self.get_output()) self._frmTableSelection.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_statistics(self): if self.get_output(): self._frmStatisticsReportSelection = frmStatisticsReportSelection(self) self._frmStatisticsReportSelection.set_from(self.project, self.get_output()) self._frmStatisticsReportSelection.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_summary(self): if not os.path.isfile(self.status_file_name): prefix, extension = os.path.splitext(self.project.file_name) if os.path.isfile(prefix + self.status_suffix): self.status_file_name = prefix + self.status_suffix if os.path.isfile(self.status_file_name): self._frmSummaryReport = frmSummaryReport(self) self._frmSummaryReport.set_from(self.project, self.status_file_name) self._frmSummaryReport.show() else: QMessageBox.information(None, self.model, "Model status not found.\n" "Run the model to generate model status.", QMessageBox.Ok) def calibration_data(self): self._frmCalibrationData = frmCalibrationData(self) self._frmCalibrationData.show() pass def get_editor(self, edit_name): frm = None # First handle special cases where forms need more than simply being created if edit_name == self.tree_quality_Pollutants[0]: edit_these = [] if self.project and self.project.pollutants: if not isinstance(self.project.pollutants.value, basestring): if isinstance(self.project.pollutants.value, list): edit_these.extend(self.project.pollutants.value) if len(edit_these) == 0: new_item = Pollutant() new_item.name = "NewPollutant" edit_these.append(new_item) self.project.pollutants.value = edit_these frm = frmGenericPropertyEditor(self, edit_these, "SWMM Pollutant Editor") frm.helper = HelpHandler(frm) frm.help_topic = "swmm/src/src/pollutanteditordialog.htm" elif edit_name in [item[0] for item in self.tree_items_using_id]: # in these cases the click on the tree diagram populates the lower left list, not directly to an editor return None # the following items will respond to a click on a conduit form, not the tree diagram # elif edit_name == tree_links_Conduits[0]: # frm = frmCrossSection(self) # the following items will respond to a click on a node form, not the tree diagram # elif edit_name == "Outfalls" or edit_name == "Dividers" or edit_name == "Storage Units": # frm = frmInflows(self) else: # General-purpose case finds most editors from tree information frm = self.make_editor_from_tree(edit_name, self.tree_top_items) return frm def get_editor_with_selected_item(self, edit_name, selected_item): frm = None # First handle special cases where forms need more than simply being created if edit_name == "Pollutants": edit_these = [] if self.project and self.project.pollutants: if not isinstance(self.project.pollutants.value, basestring): if isinstance(self.project.pollutants.value, list): for value in self.project.pollutants.value: if value.name == selected_item: edit_these.append(value) frm = frmGenericPropertyEditor(self, edit_these, "SWMM Pollutant Editor") elif edit_name == "Aquifers": # do all of these for now, will want to restrict to only selected one frm = self.make_editor_from_tree(edit_name, self.tree_top_items) # the following items will respond to a click on a conduit form, not the tree diagram elif edit_name == "Conduits": frm = frmCrossSection(self) # the following items will respond to a click on a node form, not the tree diagram # elif edit_name == "Outfalls" or edit_name == "Dividers" or edit_name == "Storage Units": # frm = frmInflows(self) else: # General-purpose case finds most editors from tree information frm = self.make_editor_from_tree(edit_name, self.tree_top_items) frm.set_from(self.project, selected_item) return frm def get_object_list(self, category): ids = [] if category == self.tree_hydrology_Subcatchments[0]: for i in range(0, len(self.project.subcatchments.value)): ids.append(self.project.subcatchments.value[i].name) # elif category.lower() == self.tree_hydrology_RainGages[0]: # for i in range(0, len(self.project.raingages.value)): # ids.append(self.project.raingages.value[i].name) elif category == self.tree_hydrology_Aquifers[0]: for i in range(0, len(self.project.aquifers.value)): ids.append(self.project.aquifers.value[i].name) elif category == self.tree_hydrology_SnowPacks[0]: for i in range(0, len(self.project.snowpacks.value)): ids.append(self.project.snowpacks.value[i].name) elif category == self.tree_hydrology_UnitHydrographs[0]: for i in range(0, len(self.project.hydrographs.value)): ids.append(self.project.hydrographs.value[i].group_name) elif category == self.tree_hydrology_LIDControls[0]: for i in range(0, len(self.project.lid_controls.value)): ids.append(self.project.lid_controls.value[i].control_name) elif category == self.tree_nodes_Junctions[0]: for i in range(0, len(self.project.junctions.value)): ids.append(self.project.junctions.value[i].name) # elif category == self.tree_nodes_Outfalls[0]: # for i in range(0, len(self.project.outfalls.value)): # ids.append(self.project.outfalls.value[i].name) # elif category == self.tree_nodes_Dividers[0]: # for i in range(0, len(self.project.dividers.value)): # ids.append(self.project.dividers.value[i].name) # elif category == self.tree_nodes_StorageUnits[0]: # for i in range(0, len(self.project.storage.value)): # ids.append(self.project.storage.value[i].name) elif category == self.tree_links_Conduits[0]: for i in range(0, len(self.project.conduits.value)): ids.append(self.project.conduits.value[i].name) elif category == self.tree_links_Pumps: for i in range(0, len(self.project.pumps.value)): ids.append(self.project.pumps.value[i].name) # elif category == self.tree_links_Orifices[0]: # for i in range(0, len(self.project.orifices.value)): # ids.append(self.project.orifices.value[i].name) # elif category == self.tree_links_Weirs[0]: # for i in range(0, len(self.project.weirs.value)): # ids.append(self.project.weirs.value[i].name) # elif category == self.tree_links_Outlets[0]: # for i in range(0, len(self.project.outlets.value)): # ids.append(self.project.outlets.value[i].name) elif category == self.tree_hydraulics_Transects[0]: for i in range(0, len(self.project.transects.value)): ids.append(self.project.transects.value[i].name) elif category == self.tree_quality_Pollutants[0]: for i in range(0, len(self.project.pollutants.value)): ids.append(self.project.pollutants.value[i].name) elif category == self.tree_quality_LandUses[0]: for i in range(0, len(self.project.landuses.value)): ids.append(self.project.landuses.value[i].land_use_name) elif category == self.tree_curves_ControlCurves[0]: for i in range(0, len(self.project.curves.value)): if self.project.curves.value[i].curve_type == CurveType.CONTROL: ids.append(self.project.curves.value[i].curve_id) elif category == self.tree_curves_DiversionCurves[0]: for i in range(0, len(self.project.curves.value)): if self.project.curves.value[i].curve_type == CurveType.DIVERSION: ids.append(self.project.curves.value[i].curve_id) elif category == self.tree_curves_PumpCurves[0]: for i in range(0, len(self.project.curves.value)): curve_type = self.project.curves.value[i].curve_type if curve_type == CurveType.PUMP1 or curve_type == CurveType.PUMP2 or \ curve_type == CurveType.PUMP3 or curve_type == CurveType.PUMP4: ids.append(self.project.curves.value[i].curve_id) elif category == self.tree_curves_RatingCurves[0]: for i in range(0, len(self.project.curves.value)): if self.project.curves.value[i].curve_type == CurveType.RATING: ids.append(self.project.curves.value[i].curve_id) elif category == self.tree_curves_ShapeCurves[0]: for i in range(0, len(self.project.curves.value)): if self.project.curves.value[i].curve_type == CurveType.SHAPE: ids.append(self.project.curves.value[i].curve_id) elif category == self.tree_curves_StorageCurves[0]: for i in range(0, len(self.project.curves.value)): if self.project.curves.value[i].curve_type == CurveType.STORAGE: ids.append(self.project.curves.value[i].curve_id) elif category == self.tree_curves_TidalCurves[0]: for i in range(0, len(self.project.curves.value)): if self.project.curves.value[i].curve_type == CurveType.TIDAL: ids.append(self.project.curves.value[i].curve_id) elif category == self.tree_TimeSeries[0]: for i in range(0, len(self.project.timeseries.value)): ids.append(self.project.timeseries.value[i].name) elif category == self.tree_TimePatterns[0]: for i in range(0, len(self.project.patterns.value)): ids.append(self.project.patterns.value[i].name) # elif category == self.tree_MapLabels[0]: # for i in range(0, len(self.project.labels.value)): # ids.append(self.project.labels.value[i].label_text) else: ids = None return ids def add_object_clicked(self, section_name): if section_name == self.tree_hydrology_Subcatchments[0]: new_item = Subcatchment() new_item.name = "New" if len(self.project.subcatchments.value) == 0: edit_these = [] edit_these.append(new_item) self.project.subcatchments.value = edit_these else: self.project.subcatchments.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) # elif section_name == self.tree_hydrology_RainGages[0]: elif section_name == self.tree_hydrology_Aquifers[0]: new_item = Aquifer() new_item.name = "New" if len(self.project.aquifers.value) == 0: edit_these = [] edit_these.append(new_item) self.project.aquifers.value = edit_these else: self.project.aquifers.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) elif section_name == self.tree_hydrology_SnowPacks[0]: new_item = SnowPack() new_item.name = "New" if len(self.project.snowpacks.value) == 0: edit_these = [] edit_these.append(new_item) self.project.snowpacks.value = edit_these else: self.project.snowpacks.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) elif section_name == self.tree_hydrology_UnitHydrographs[0]: new_item = UnitHydrograph() new_item.group_name = "New" if len(self.project.hydrographs.value) == 0: edit_these = [] edit_these.append(new_item) self.project.hydrographs.value = edit_these else: self.project.hydrographs.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.group_name)) elif section_name == self.tree_hydrology_LIDControls[0]: new_item = LIDControl() new_item.control_name = "New" if len(self.project.lid_controls.value) == 0: edit_these = [] edit_these.append(new_item) self.project.lid_controls.value = edit_these else: self.project.lid_controls.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.control_name)) elif section_name == self.tree_nodes_Junctions[0]: new_item = Junction() new_item.name = "New" if len(self.project.junctions.value) == 0: edit_these = [] edit_these.append(new_item) self.project.junctions.value = edit_these else: self.project.junctions.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) # elif section_name == self.tree_nodes_Outfalls[0]: # elif section_name == self.tree_nodes_Dividers[0]: # elif section_name == self.tree_nodes_StorageUnits[0]: elif section_name == self.tree_links_Conduits[0]: new_item = Conduit() new_item.name = "New" if len(self.project.conduits.value) == 0: edit_these = [] edit_these.append(new_item) self.project.conduits.value = edit_these else: self.project.conduits.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) elif section_name == self.tree_links_Pumps: new_item = Pump() new_item.name = "New" if len(self.project.pumps.value) == 0: edit_these = [] edit_these.append(new_item) self.project.pumps.value = edit_these else: self.project.pumps.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) # elif section_name == self.tree_links_Orifices[0]: # elif section_name == self.tree_links_Weirs[0]: # elif section_name == self.tree_links_Outlets[0]: elif section_name == self.tree_hydraulics_Transects[0]: new_item = Transect() new_item.name = "New" if len(self.project.transects.value) == 0: edit_these = [] edit_these.append(new_item) self.project.transects.value = edit_these else: self.project.transects.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) elif section_name == self.tree_quality_Pollutants[0]: new_item = Pollutant() new_item.name = "NewPollutant" if len(self.project.pollutants.value) == 0: edit_these = [] edit_these.append(new_item) self.project.pollutants.value = edit_these else: self.project.pollutants.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) elif section_name == self.tree_quality_LandUses[0]: new_item = Landuse() new_item.land_use_name = "New" if len(self.project.landuses.value) == 0: edit_these = [] edit_these.append(new_item) self.project.landuses.value = edit_these else: self.project.landuses.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.land_use_name)) elif section_name == self.tree_curves_ControlCurves[0]: new_item = Curve() new_item.curve_id = "New" new_item.curve_type = CurveType.CONTROL if len(self.project.curves.value) == 0: edit_these = [] edit_these.append(new_item) self.project.curves.value = edit_these else: self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == self.tree_curves_DiversionCurves[0]: new_item = Curve() new_item.curve_id = "New" new_item.curve_type = CurveType.DIVERSION if len(self.project.curves.value) == 0: edit_these = [] edit_these.append(new_item) self.project.curves.value = edit_these else: self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == self.tree_curves_PumpCurves[0]: new_item = Curve() new_item.curve_id = "New" new_item.curve_type = CurveType.PUMP1 if len(self.project.curves.value) == 0: edit_these = [] edit_these.append(new_item) self.project.curves.value = edit_these else: self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == self.tree_curves_RatingCurves[0]: new_item = Curve() new_item.curve_id = "New" new_item.curve_type = CurveType.RATING if len(self.project.curves.value) == 0: edit_these = [] edit_these.append(new_item) self.project.curves.value = edit_these else: self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == self.tree_curves_ShapeCurves[0]: new_item = Curve() new_item.curve_id = "New" new_item.curve_type = CurveType.SHAPE if len(self.project.curves.value) == 0: edit_these = [] edit_these.append(new_item) self.project.curves.value = edit_these else: self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == self.tree_curves_StorageCurves[0]: new_item = Curve() new_item.curve_id = "New" new_item.curve_type = CurveType.STORAGE if len(self.project.curves.value) == 0: edit_these = [] edit_these.append(new_item) self.project.curves.value = edit_these else: self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == self.tree_curves_TidalCurves[0]: new_item = Curve() new_item.curve_id = "New" new_item.curve_type = CurveType.TIDAL if len(self.project.curves.value) == 0: edit_these = [] edit_these.append(new_item) self.project.curves.value = edit_these else: self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == self.tree_TimeSeries[0]: new_item = TimeSeries() new_item.name = "New" if len(self.project.timeseries.value) == 0: edit_these = [] edit_these.append(new_item) self.project.timeseries.value = edit_these else: self.project.timeseries.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) elif section_name == self.tree_TimePatterns[0]: new_item = Pattern() new_item.name = "New" if len(self.project.patterns.value) == 0: edit_these = [] edit_these.append(new_item) self.project.patterns.value = edit_these else: self.project.patterns.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name)) # elif section_name == self.tree_MapLabels[0]: def delete_object_clicked(self, section_name, item_name): if section_name == self.tree_hydrology_Subcatchments[0]: for value in self.project.subcatchments.value: if value.name == item_name: self.project.subcatchments.value.remove(value) # elif section_name == self.tree_hydrology_RainGages[0]: elif section_name == self.tree_hydrology_Aquifers[0]: for value in self.project.aquifers.value: if value.name == item_name: self.project.aquifers.value.remove(value) elif section_name == self.tree_hydrology_SnowPacks[0]: for value in self.project.snowpacks.value: if value.name == item_name: self.project.snowpacks.value.remove(value) elif section_name == self.tree_hydrology_UnitHydrographs[0]: for value in self.project.hydrographs.value: if value.group_name == item_name: self.project.hydrographs.value.remove(value) elif section_name == self.tree_hydrology_LIDControls[0]: for value in self.project.lid_controls.value: if value.control_name == item_name: self.project.lid_controls.value.remove(value) elif section_name == self.tree_nodes_Junctions[0]: for value in self.project.junctions.value: if value.name == item_name: self.project.junctions.value.remove(value) # elif section_name == self.tree_nodes_Outfalls[0]: # elif section_name == self.tree_nodes_Dividers[0]: # elif section_name == self.tree_nodes_StorageUnits[0]: elif section_name == self.tree_links_Conduits[0]: for value in self.project.conduits.value: if value.name == item_name: self.project.conduits.value.remove(value) elif section_name == self.tree_links_Pumps: for value in self.project.pumps.value: if value.name == item_name: self.project.pumps.value.remove(value) # elif section_name == self.tree_links_Orifices[0]: # elif section_name == self.tree_links_Weirs[0]: # elif section_name == self.tree_links_Outlets[0]: elif section_name == self.tree_hydraulics_Transects[0]: for value in self.project.transects.value: if value.name == item_name: self.project.transects.value.remove(value) elif section_name == self.tree_quality_Pollutants[0]: for value in self.project.pollutants.value: if value.name == item_name: self.project.pollutants.value.remove(value) elif section_name == self.tree_quality_LandUses[0]: for value in self.project.landuses.value: if value.land_use_name == item_name: self.project.landuses.value.remove(value) elif section_name == self.tree_curves_ControlCurves[0]: for value in self.project.curves.value: if value.curve_id == item_name and value.curve_type == CurveType.CONTROL: self.project.curves.value.remove(value) elif section_name == self.tree_curves_DiversionCurves[0]: for value in self.project.curves.value: if value.curve_id == item_name and value.curve_type == CurveType.DIVERSION: self.project.curves.value.remove(value) elif section_name == self.tree_curves_PumpCurves[0]: for value in self.project.curves.value: if value.curve_id == item_name and \ (value.curve_type == CurveType.PUMP1 or value.curve_type == CurveType.PUMP2 or value.curve_type == CurveType.PUMP3 or value.curve_type == CurveType.PUMP4): self.project.curves.value.remove(value) elif section_name == self.tree_curves_RatingCurves[0]: for value in self.project.curves.value: if value.curve_id == item_name and value.curve_type == CurveType.RATING: self.project.curves.value.remove(value) elif section_name == self.tree_curves_ShapeCurves[0]: for value in self.project.curves.value: if value.curve_id == item_name and value.curve_type == CurveType.SHAPE: self.project.curves.value.remove(value) elif section_name == self.tree_curves_StorageCurves[0]: for value in self.project.curves.value: if value.curve_id == item_name and value.curve_type == CurveType.STORAGE: self.project.curves.value.remove(value) elif section_name == self.tree_curves_TidalCurves[0]: for value in self.project.curves.value: if value.curve_id == item_name and value.curve_type == CurveType.TIDAL: self.project.curves.value.remove(value) elif section_name == self.tree_TimeSeries[0]: for value in self.project.timeseries.value: if value.name == item_name: self.project.timeseries.value.remove(value) elif section_name == self.tree_TimePatterns[0]: for value in self.project.patterns.value: if value.name == item_name: self.project.patterns.value.remove(value) # elif section_name == self.tree_MapLabels[0]: def run_simulation(self): self.output = None # First find input file to run file_name = '' use_existing = self.project and self.project.file_name and os.path.exists(self.project.file_name) if use_existing: file_name = self.project.file_name # TODO: save if needed, decide whether to save to temp location as previous version did. else: directory = QtCore.QSettings(self.model, "GUI").value("ProjectDir", "") file_name = QFileDialog.getOpenFileName(self, "Open Project...", directory, "Inp files (*.inp);;All files (*.*)") if os.path.exists(file_name): prefix, extension = os.path.splitext(file_name) self.status_file_name = prefix + self.status_suffix self.output_filename = prefix + '.out' # if not os.path.exists(self.model_path): # if 'darwin' in sys.platform: # lib_name = 'libswmm.dylib' # ext = '.dylib' # elif 'win' in sys.platform: # lib_name = 'swmm5_x86.dll' # ext = '.dll' # # if lib_name: # self.model_path = os.path.join(self.assembly_path, lib_name) # if not os.path.exists(self.model_path): # pp = os.path.dirname(os.path.dirname(self.assembly_path)) # self.model_path = os.path.join(pp, "Externals", lib_name) # if not os.path.exists(self.model_path): # self.model_path = QFileDialog.getOpenFileName(self, # 'Locate ' + self.model +' Library', # '/', '(*{0})'.format(ext)) # # if os.path.exists(self.model_path): # try: # from Externals.swmm5 import pyswmm # swmm_object = pyswmm(file_name, self.status_file_name, self.output_filename, self.model_path) # swmm_object.swmmExec() # print(swmm_object.swmm_getVersion()) # print(swmm_object.swmm_getMassBalErr()) # # # model_api = pyepanet.ENepanet(file_name, self.status_file_name, self.output_filename, self.model_path) # # frmRun = frmRunEPANET(model_api, self.project, self) # # self._forms.append(frmRun) # # if not use_existing: # # # Read this project so we can refer to it while running # # frmRun.progressBar.setVisible(False) # # frmRun.lblTime.setVisible(False) # # frmRun.fraTime.setVisible(False) # # frmRun.fraBottom.setVisible(False) # # frmRun.showNormal() # # frmRun.set_status_text("Reading " + file_name) # # # # self.project = Project() # # self.project.read_file(file_name) # # frmRun.project = self.project # # # # frmRun.Execute() # return # except Exception as e1: # print(str(e1) + '\n' + str(traceback.print_exc())) # QMessageBox.information(None, self.model, # "Error running model with library:\n {0}\n{1}\n{2}".format( # self.model_path, str(e1), str(traceback.print_exc())), # QMessageBox.Ok) # # finally: # # try: # # if model_api and model_api.isOpen(): # # model_api.ENclose() # # except: # # pass # # return # Could not run with library, try running with executable args = [] exe_name = "swmm5.exe" exe_path = os.path.join(self.assembly_path, exe_name) if not os.path.isfile(exe_path): pp = os.path.dirname(os.path.dirname(self.assembly_path)) exe_path = os.path.join(pp, "Externals", exe_name) if not os.path.isfile(exe_path): pp = os.path.dirname(os.path.dirname(self.assembly_path)) exe_path = os.path.join(pp, "Externals", "swmm", "model", exe_name) if not os.path.isfile(exe_path): exe_path = QFileDialog.getOpenFileName(self, 'Locate SWMM Executable', '/', 'exe files (*.exe)') if os.path.isfile(exe_path): args.append(file_name) args.append(self.status_file_name) args.append(self.output_filename) # running the Exe status = StatusMonitor0(exe_path, args, self, model='SWMM') status.show() else: QMessageBox.information(None, self.model, self.model + " input file not found", QMessageBox.Ok) def help_topics(self): self.helper.show_help() def help_about(self): self._frmAbout = frmAbout(self) self._frmAbout.show() pass
class frmPlotViewer(QMainWindow, Ui_frmPlot): """ Generic plot viewer window that can copy, save, and print a plot - Time Series Viewer """ # MAGIC = "TSGRAPHSPEC:" def __init__(self, dataset, plot_type, plot_title, window_icon, x_title, y_title): """ Constructor Args: dataset: time series data as pandas data frame """ QMainWindow.__init__(self) self.helper = HelpHandler(self) self.setupUi(self) self.setWindowIcon(window_icon) self.actionPrint.setVisible(False) self.actionSave.setVisible(False) self.actionCopy.setVisible(False) self.menuFile.setEnabled(False) self.menuFile.setVisible(False) self.menuFile.deleteLater() self.dataset = dataset self.plot_title = plot_title self.x_title = x_title self.y_title = y_title if plot_type == 'time': self.plot_type = 'timeseries' self.help_topic = "swmm/src/src/timeserieseditordialog.htm" elif plot_type == 'xy': self.plot_type = 'xy' self.help_topic = "swmm/src/src/transecteditordialog.htm" elif plot_type == 'step': self.plot_type = 'step' self.help_topic = '' # TODO # self.plot = CurvePlot(self.fraPlot, width=6, height=2, dpi=100) # layout = QVBoxLayout(self.fraPlot) # layout.setContentsMargins(0, 0, 0, 0) # layout.addWidget(self.plot) # self.fraPlot.setLayout(layout) self.helper = HelpHandler(self) self.Xunits = {} self.Yunits = {} self.Xlabel = "" self.Ylabel = "" self.Xunit = "" self.Yunit = "" self.TXT_OPEN_CURVE_TITLE = 'Open a Curve' self.TXT_SAVE_CURVE_TITLE = 'Save Curve As' self.TXT_CURVE_FILTER = 'Curve files (*.CRV)|*.CRV|All files|*.*' self.xvals = [] self.yvals = [] self.btnClose.clicked.connect(self.frm_close) self.btnHelp.clicked.connect(self.get_help) self.actionOpen.triggered.connect(self.open_datafile) self.actionCopy.triggered.connect(self.copy_plot) self.actionSave.triggered.connect(self.save_plot) self.actionPrint.triggered.connect(self.print_plot) # self.installEventFilter(self) self.do_plot() def open_datafile(self): pass def copy_plot(self): pass def save_plot(self): pass def print_plot(self): pass def do_plot(self): """ Construct a plot of the dataset ToDo: based on user-specified plot type Returns: """ if self.dataset.shape[0] > 0 and self.dataset.shape[1] > 0: if self.plot_type == 'timeseries': # self.plot.setTitle(self.plot_title) # self.plot.set_time_series_data(self.dataset) self.set_time_series_data(self.dataset) elif self.plot_type == 'xy': # self.plot.setTitle(self.plot_title) # self.plot.set_xy_data(self.dataset, self.x_title, self.y_title) self.set_xy_data(self.dataset, self.x_title, self.y_title) elif self.plot_type == 'step': # self.plot.setTitle(self.plot_title) # self.plot.set_xy_data(self.dataset, self.x_title, self.y_title, step=True) self.set_xy_data(self.dataset, self.x_title, self.y_title, step=True) pass def frm_close(self): """ Close the plot form and discard dataset Returns: """ self.close() def get_help(self): self.helper.show_help() def set_xy_data(self, df, x_title, y_title, step=False): if df.shape[0] > 0 and df.shape[1] > 0: x = [] y = [] for row in range(len(df)): x.append(float(df.index[row])) y.append(float(df.iloc[row][0])) # the way frmScatterPlot does it: import matplotlib.pyplot as plt fig = plt.figure() fig.canvas.set_window_title(self.plot_title) plt.title(self.plot_title) plt.scatter(x, y, s=50, c="lightblue", edgecolors="blue", alpha=0.5) plt.plot(x, y, color='red') plt.xlabel(x_title) plt.ylabel(y_title) plt.grid(True) plt.show(block=True) def set_time_series_data(self, df): if df.shape[0] > 0 and df.shape[1] > 0: x = [] y = [] for row in range(len(df)): if df.hour_only: x.append(df.index[row]) else: x.append(mdates.date2num(df.index[row])) y.append(df.iloc[row][0]) # the way frmTimeSeriesPlot does it: import matplotlib.pyplot as plt fig = plt.figure() fig.canvas.set_window_title(self.plot_title) plt.title(self.plot_title) # left_y_plot = fig.add_subplot() left_y_plot = fig.gca().axes # colors = get_cmap('Dark2').colors # color_cycler = cycler.cycler('color', colors) # plt.rc('axes', prop_cycle=color_cycler) lines_plotted = [] line_legends = [] if df.hour_only: plt.xlabel("Elapsed time (hours)") else: plt.xlabel("Elapsed time (date)") fig.autofmt_xdate() plt.grid(True) new_line = left_y_plot.plot(x, y, label="xxx")[0] if not df.hour_only: left_y_plot.xaxis.set_major_formatter( mdates.DateFormatter('%Y-%m-%d %H:%M')) lines_plotted.append(new_line) plt.legend(lines_plotted, line_legends, loc="best") plt.show(block=False)
class frmMainEPANET(frmMain): """Main form for EPANET user interface, based on frmMain which is shared with SWMM.""" # Variables used to populate the tree control # Each item is a list: label plus either editing form for this section or a child list. # Special cases may just have a label and no editing form or children. # *_items are a lists of items in a section tree_options_Hydraulics = ["Hydraulics", frmHydraulicsOptions] tree_options_Quality = ["Quality", frmQualityOptions] tree_options_Reactions = ["Reactions", frmReactionsOptions] tree_options_Times = ["Times", frmTimesOptions] tree_options_Energy = ["Energy", frmEnergyOptions] tree_options_Report = ["Report", frmReportOptions] tree_options_MapBackdrop = ["Map/Backdrop", frmMapBackdropOptions] tree_options_items = [tree_options_Hydraulics, tree_options_Quality, tree_options_Reactions, tree_options_Times, tree_options_Energy, tree_options_Report, tree_options_MapBackdrop] tree_controls_Simple = ["Simple", frmControls, ["EPANET Simple Controls", "CONTROLS"]] tree_controls_RuleBased = ["Rule-Based", frmControls, ["EPANET Rule-Based Controls", "RULES"]] tree_controls_items = [tree_controls_Simple, tree_controls_RuleBased] tree_TitleNotes = ["Title/Notes", frmTitle] tree_Options = ["Options", tree_options_items] tree_Junctions = ["Junctions", None] tree_Reservoirs = ["Reservoirs", None] tree_Tanks = ["Tanks", None] tree_Pipes = ["Pipes", None] tree_Pumps = ["Pumps", None] tree_Valves = ["Valves", None] tree_Labels = ["Labels", None] tree_Patterns = ["Patterns", frmPatternEditor] tree_Curves = ["Curves", frmCurveEditor] tree_Controls = ["Controls", tree_controls_items] tree_top_items = [tree_TitleNotes, tree_Options, tree_Junctions, tree_Reservoirs, tree_Tanks, tree_Pipes, tree_Pumps, tree_Valves, tree_Labels, tree_Patterns, tree_Curves, tree_Controls] def __init__(self, q_application): frmMain.__init__(self, q_application) self.model = "EPANET" self.model_path = '' # Set this only if needed later when running model self.output = None # Set this when model output is available self.status_suffix = "_status.txt" self.status_file_name = '' # Set this when model status is available self.output_filename = '' # Set this when model output is available self.project_type = Project # Use the model-specific Project as defined in core.epanet.project self.project = Project() self.assembly_path = os.path.dirname(os.path.abspath(__file__)) self.on_load(tree_top_item_list=self.tree_top_items) HelpHandler.init_class(os.path.join(self.assembly_path, "epanet.qhc")) self.help_topic = "" # TODO: specify topic to open when Help key is pressed on main form self.helper = HelpHandler(self) self.actionStatus_ReportMenu = QtGui.QAction(self) self.actionStatus_ReportMenu.setObjectName(from_utf8("actionStatus_ReportMenu")) self.actionStatus_ReportMenu.setText(transl8("frmMain", "Status", None)) self.actionStatus_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Status", None)) self.menuReport.addAction(self.actionStatus_ReportMenu) QtCore.QObject.connect(self.actionStatus_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_status) self.actionEnergy_ReportMenu = QtGui.QAction(self) self.actionEnergy_ReportMenu.setObjectName(from_utf8("actionEnergy_ReportMenu")) self.actionEnergy_ReportMenu.setText(transl8("frmMain", "Energy", None)) self.actionEnergy_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Energy", None)) self.menuReport.addAction(self.actionEnergy_ReportMenu) QtCore.QObject.connect(self.actionEnergy_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_energy) self.actionCalibration_ReportMenu = QtGui.QAction(self) self.actionCalibration_ReportMenu.setObjectName(from_utf8("actionCalibration_ReportMenu")) self.actionCalibration_ReportMenu.setText(transl8("frmMain", "Calibration", None)) self.actionCalibration_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Calibration", None)) self.menuReport.addAction(self.actionCalibration_ReportMenu) QtCore.QObject.connect(self.actionCalibration_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_calibration) self.actionReaction_ReportMenu = QtGui.QAction(self) self.actionReaction_ReportMenu.setObjectName(from_utf8("actionReaction_ReportMenu")) self.actionReaction_ReportMenu.setText(transl8("frmMain", "Reaction", None)) self.actionReaction_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Reaction", None)) self.menuReport.addAction(self.actionReaction_ReportMenu) QtCore.QObject.connect(self.actionReaction_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_reaction) self.actionFull_ReportMenu = QtGui.QAction(self) self.actionFull_ReportMenu.setObjectName(from_utf8("actionFull_ReportMenu")) self.actionFull_ReportMenu.setText(transl8("frmMain", "Full...", None)) self.actionFull_ReportMenu.setToolTip(transl8("frmMain", "Save full report as text file", None)) self.menuReport.addAction(self.actionFull_ReportMenu) QtCore.QObject.connect(self.actionFull_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_full) self.actionGraph_ReportMenu = QtGui.QAction(self) self.actionGraph_ReportMenu.setObjectName(from_utf8("actionGraph_ReportMenu")) self.actionGraph_ReportMenu.setText(transl8("frmMain", "Graph...", None)) self.actionGraph_ReportMenu.setToolTip(transl8("frmMain", "Display graph selection options", None)) self.menuReport.addAction(self.actionGraph_ReportMenu) QtCore.QObject.connect(self.actionGraph_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_graph) self.actionTable_ReportMenu = QtGui.QAction(self) self.actionTable_ReportMenu.setObjectName(from_utf8("actionTable_ReportMenu")) self.actionTable_ReportMenu.setText(transl8("frmMain", "Table...", None)) self.actionTable_ReportMenu.setToolTip(transl8("frmMain", "Display table selection options", None)) self.menuReport.addAction(self.actionTable_ReportMenu) QtCore.QObject.connect(self.actionTable_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_table) self.Help_Topics_Menu = QtGui.QAction(self) self.Help_Topics_Menu.setObjectName(from_utf8("Help_Topics_Menu")) self.Help_Topics_Menu.setText(transl8("frmMain", "Help Topics", None)) self.Help_Topics_Menu.setToolTip(transl8("frmMain", "Display Help Topics", None)) self.menuHelp.addAction(self.Help_Topics_Menu) QtCore.QObject.connect(self.Help_Topics_Menu, QtCore.SIGNAL('triggered()'), self.help_topics) self.Help_About_Menu = QtGui.QAction(self) self.Help_About_Menu.setObjectName(from_utf8("Help_About_Menu")) self.Help_About_Menu.setText(transl8("frmMain", "About", None)) self.Help_About_Menu.setToolTip(transl8("frmMain", "About EPANET", None)) self.menuHelp.addAction(self.Help_About_Menu) QtCore.QObject.connect(self.Help_About_Menu, QtCore.SIGNAL('triggered()'), self.help_about) def report_status(self): print "report_status" if not os.path.isfile(self.status_file_name): prefix, extension = os.path.splitext(self.project.file_name) if os.path.isfile(prefix + self.status_suffix): self.status_file_name = prefix + self.status_suffix if os.path.isfile(self.status_file_name): webbrowser.open_new_tab(self.status_file_name) else: QMessageBox.information(None, self.model, "Model status not found.\n" "Run the model to generate model status.", QMessageBox.Ok) def report_energy(self): self._frmEnergyReport = frmEnergyReport(self) self._frmEnergyReport.set_data() self._frmEnergyReport.show() pass def report_calibration(self): if self.output: self._frmCalibrationReportOptions = frmCalibrationReportOptions(self, self.project) self._frmCalibrationReportOptions.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_reaction(self): self.reaction_report() pass def report_full(self): if self.output: directory = os.path.dirname(self.project.file_name) report_file_name = QtGui.QFileDialog.getSaveFileName(self, "Save Full Report As...", directory, "Text files (*.txt)") if report_file_name: try: reporter = reports.Reports(self.project, self.output) reporter.write_report(report_file_name) webbrowser.open_new_tab(report_file_name) except Exception as e1: msg = str(e1) + '\n' + str(traceback.print_exc()) print(msg) QMessageBox.information(None, self.model, "Error writing report to \n" + report_file_name + '\n' + msg, QMessageBox.Ok) else: QMessageBox.information(None, self.model, "There is no model output currently open.\n" "Model output is automatically opened after model is run.", QMessageBox.Ok) def report_graph(self): if self.output: self._frmGraph = frmGraph(self) self._frmGraph.set_from(self.project, self.output) self._frmGraph.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def report_table(self): if self.output: self._frmTable = frmTable(self) self._frmTable.set_from(self.project, self.output) self._frmTable.show() else: QMessageBox.information(None, self.model, "Model output not found.\n" "Run the model to generate output.", QMessageBox.Ok) def reaction_report(self): # TXT_NO_REACTION = 'No reactions occurred' # TXT_AVG_RATES = 'Average Reaction Rates (kg/day)' # ' Reaction Report' # Find conversion factor to kilograms/day ucf = 1.0e6/24 quality_options = self.project.options.quality if 'ug' in str(quality_options.mass_units): ucf = 1.0e9/24 # # // Get average reaction rates from output file # Uoutput.GetReactRates(r); # procedure GetReactRates(var R: array of Single); # //----------------------------------------------- # // Retrieves overall average reaction rates # // NOTE: The 3 avg. reaction rates + avg. source # // input rate are stored at end of the # // binary output file just before the last # // 3 records. # //----------------------------------------------- # begin # Seek(Fout, FileSize(Fout)-7*RECORDSIZE); # BlockRead(Fout, R, 4*Sizeof(Single)); # end; # for i := 0 to 3 do rate[i] := r[i] / ucf; # # // Check max. rate to see if any reactions occurred # maxrate := MaxValue(Slice(rate,3)); # if maxrate = 0 then # begin # Chart1.Foot.Text.Add(TXT_NO_REACTION); # end # # // Add each rate category to chart # else # begin # Chart1.Title.Text.Add(TXT_AVG_RATES); # Add(rate[0],TXT_BULK,clBlue); # Add(rate[1],TXT_WALL,clRed); # Add(rate[2],TXT_TANKS,clGreen); # Active := True; # Chart1.Foot.Text.Add(Format(FMT_INFLOW,[rate[3]])); # end; # end; import matplotlib.pyplot as plt # The slices will be ordered and plotted counter-clockwise. labels = '2.8 Tanks', '0.5 Bulk', '2.1 Wall' sizes = [52.49, 8.57, 38.93] colors = ['green', 'blue', 'red'] explode = (0, 0, 0) plt.figure("Reaction Report") plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.2f%%', shadow=True, startangle=180) # Set aspect ratio to be equal so that pie is drawn as a circle. plt.axis('equal') plt.suptitle("Average Reaction Rates (kg/day)", fontsize=16) plt.text(0.9,-0.9,"Inflow Rate = 6") plt.show() def calibration_data(self): self._frmCalibrationData = frmCalibrationData(self) self._frmCalibrationData.show() pass def get_editor(self, edit_name): frm = None # First handle special cases where forms need more than simply being created # the following items will respond to a click on a node form, not the tree diagram if edit_name == 'Reservoirs' or edit_name == 'Tanks': # assume we're editing the first node for now frm = frmSourcesQuality(self) frm.setWindowTitle('EPANET Source Editor for Node ' + '1') frm.set_from(self.project, '1') elif edit_name == 'Junctions': # assume we're editing the first junction for now frm = frmDemands(self) frm.setWindowTitle('EPANET Demands for Junction ' + '1') frm.set_from(self.project, '1') elif edit_name == 'Patterns': return None elif edit_name == 'Curves': return None else: # General-purpose case finds most editors from tree information frm = self.make_editor_from_tree(edit_name, self.tree_top_items) return frm def get_editor_with_selected_item(self, edit_name, selected_item): frm = None # the following items will respond to a click on a node form, not the tree diagram if edit_name == 'Reservoirs' or edit_name == 'Tanks': # assume we're editing the first node for now frm = frmSourcesQuality(self) frm.setWindowTitle('EPANET Source Editor for Node ' + '1') frm.set_from(self.project, '1') elif edit_name == 'Junctions': # assume we're editing the first junction for now frm = frmDemands(self) frm.setWindowTitle('EPANET Demands for Junction ' + '1') frm.set_from(self.project, '1') else: # General-purpose case finds most editors from tree information frm = self.make_editor_from_tree(edit_name, self.tree_top_items) frm.set_from(self.project, selected_item) return frm def get_object_list(self, category): ids = [] if category.lower() == 'junctions': for i in range(0, len(self.project.junctions.value)): ids.append(self.project.junctions.value[i].id) elif category.lower() == 'reservoirs': for i in range(0, len(self.project.reservoirs.value)): ids.append(self.project.reservoirs.value[i].id) elif category.lower() == 'tanks': for i in range(0, len(self.project.tanks.value)): ids.append(self.project.tanks.value[i].id) elif category.lower() == 'pipes': for i in range(0, len(self.project.pipes.value)): ids.append(self.project.pipes.value[i].id) elif category.lower() == 'pumps': for i in range(0, len(self.project.pumps.value)): ids.append(self.project.pumps.value[i].id) elif category.lower() == 'valves': for i in range(0, len(self.project.valves.value)): ids.append(self.project.valves.value[i].id) elif category.lower() == 'labels': for i in range(0, len(self.project.labels.value)): ids.append(self.project.labels.value[i].label) elif category.lower() == 'patterns': for i in range(0, len(self.project.patterns.value)): ids.append(self.project.patterns.value[i].pattern_id) elif category.lower() == 'curves': for i in range(0, len(self.project.curves.value)): ids.append(self.project.curves.value[i].curve_id) else: ids = None return ids def add_object_clicked(self, section_name): if section_name == "Patterns": new_item = Pattern() new_item.pattern_id = "NewPattern" self.project.patterns.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.pattern_id)) elif section_name == "Curves": new_item = Curve() new_item.curve_id = "NewCurve" self.project.curves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id)) elif section_name == "Junctions": new_item = Junction() new_item.id = "New" self.project.junctions.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id)) elif section_name == 'Reservoirs': new_item = Reservoir() new_item.id = "New" self.project.reservoirs.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id)) elif section_name == 'Tanks': new_item = Tank() new_item.id = "New" self.project.tanks.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id)) elif section_name == 'Pipes': new_item = Pipe() new_item.id = "New" self.project.pipes.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id)) elif section_name == 'Pumps': new_item = Pump() new_item.id = "New" self.project.pumps.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id)) elif section_name == 'Valves': new_item = Valve() new_item.id = "New" self.project.valves.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id)) elif section_name == 'Labels': new_item = Label() new_item.id = "New" self.project.labels.value.append(new_item) self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id)) def delete_object_clicked(self, section_name, item_name): if section_name == "Patterns": for value in self.project.patterns.value: if value.pattern_id == item_name: self.project.patterns.value.remove(value) elif section_name == "Curves": for value in self.project.curves.value: if value.curve_id == item_name: self.project.curves.value.remove(value) elif section_name == "Junctions": for value in self.project.junctions.value: if value.id == item_name: self.project.junctions.value.remove(value) elif section_name == 'Reservoirs': for value in self.project.reservoirs.value: if value.id == item_name: self.project.reservoirs.value.remove(value) elif section_name == 'Tanks': for value in self.project.tanks.value: if value.id == item_name: self.project.tanks.value.remove(value) elif section_name == 'Pipes': for value in self.project.pipes.value: if value.id == item_name: self.project.pipes.value.remove(value) elif section_name == 'Pumps': for value in self.project.pumps.value: if value.id == item_name: self.project.pumps.value.remove(value) elif section_name == 'Valves': for value in self.project.valves.value: if value.id == item_name: self.project.valves.value.remove(value) elif section_name == 'Labels': for value in self.project.labels.value: if value.id == item_name: self.project.labels.value.remove(value) def run_simulation(self): # Find input file to run file_name = '' use_existing = self.project and self.project.file_name and os.path.exists(self.project.file_name) if use_existing: file_name = self.project.file_name # TODO: save if needed, decide whether to save to temp location as previous version did. else: directory = QtCore.QSettings(self.model, "GUI").value("ProjectDir", "") file_name = QFileDialog.getOpenFileName(self, "Open Project...", directory, "Inp files (*.inp);;All files (*.*)") if os.path.exists(file_name): if not os.path.exists(self.model_path): if 'darwin' in sys.platform: lib_name = 'libepanet.dylib.dylib' elif 'win' in sys.platform: lib_name = 'epanet2_amd64.dll' else: # Linux lib_name = 'libepanet2_amd64.so' self.model_path = self.find_external(lib_name) if os.path.exists(self.model_path): try: prefix, extension = os.path.splitext(file_name) self.status_file_name = prefix + self.status_suffix self.output_filename = prefix + '.out' model_api = ENepanet(file_name, self.status_file_name, self.output_filename, self.model_path) frmRun = frmRunEPANET(model_api, self.project, self) self._forms.append(frmRun) if not use_existing: # Read this project so we can refer to it while running frmRun.progressBar.setVisible(False) frmRun.lblTime.setVisible(False) frmRun.fraTime.setVisible(False) frmRun.fraBottom.setVisible(False) frmRun.showNormal() frmRun.set_status_text("Reading " + file_name) self.project = Project() self.project.read_file(file_name) frmRun.project = self.project frmRun.Execute() self.report_status() self.output = ENOutputWrapper.OutputObject(self.output_filename) return except Exception as e1: print(str(e1) + '\n' + str(traceback.print_exc())) QMessageBox.information(None, self.model, "Error running model with library:\n {0}\n{1}\n{2}".format( self.model_path, str(e1), str(traceback.print_exc())), QMessageBox.Ok) finally: try: if model_api and model_api.isOpen(): model_api.ENclose() except: pass return # # Could not run with library, try running with executable # # Run executable with StatusMonitor0 # args = [] # self.modelenv1 = 'EXE_EPANET' # program = os.environ[self.modelenv1] # # exe_name = "epanet2d.exe" # exe_path = os.path.join(self.assembly_path, exe_name) # if not os.path.exists(exe_path): # pp = os.path.dirname(os.path.dirname(self.assembly_path)) # exe_path = os.path.join(pp, "Externals", exe_name) # if not os.path.exists(exe_path): # exe_path = QFileDialog.getOpenFileName(self, 'Locate EPANET Executable', '/', # 'exe files (*.exe)') # if os.path.exists(exe_path): # os.environ[self.modelenv1] = exe_path # else: # os.environ[self.modelenv1] = '' # # if not os.path.exists(program): # QMessageBox.information(None, "EPANET", "EPANET Executable not found", QMessageBox.Ok) # return -1 # # args.append(file_name) # args.append(prefix + '.txt') # args.append(prefix + '.out') # status = model_utility.StatusMonitor0(program, args, self, model='EPANET') # status.show() else: QMessageBox.information(None, self.model, self.model + " input file not found", QMessageBox.Ok) def find_external(self, lib_name): filename = os.path.join(self.assembly_path, lib_name) if not os.path.exists(filename): pp = os.path.dirname(os.path.dirname(self.assembly_path)) filename = os.path.join(pp, "Externals", lib_name) if not os.path.exists(filename): pp = os.path.dirname(os.path.dirname(self.assembly_path)) filename = os.path.join(pp, "Externals", "epanet", "model", lib_name) if not os.path.exists(filename): filename = QFileDialog.getOpenFileName(self, 'Locate ' + self.model + ' Library', '/', '(*{0})'.format(os.path.splitext(lib_name)[1])) return filename def help_topics(self): self.helper.show_help() def help_about(self): self._frmAbout = frmAbout(self) self._frmAbout.show() pass
class frmPlotViewer(QMainWindow, Ui_frmPlot): """ Generic plot viewer window that can copy, save, and print a plot - Time Series Viewer """ # MAGIC = "TSGRAPHSPEC:" def __init__(self, dataset, plot_type, plot_title, window_icon, x_title, y_title): """ Constructor Args: dataset: time series data as pandas data frame """ QMainWindow.__init__(self) self.helper = HelpHandler(self) self.setupUi(self) self.setWindowIcon(window_icon) self.actionPrint.setVisible(False) self.actionSave.setVisible(False) self.actionCopy.setVisible(False) self.menuFile.setEnabled(False) self.menuFile.setVisible(False) self.menuFile.deleteLater() self.dataset = dataset self.plot_title = plot_title self.x_title = x_title self.y_title = y_title if plot_type == 'time': self.plot_type = 'timeseries' self.help_topic = "swmm/src/src/timeserieseditordialog.htm" elif plot_type == 'xy': self.plot_type = 'xy' self.help_topic = "swmm/src/src/transecteditordialog.htm" self.plot = CurvePlot(self.fraPlot, width=6, height=2, dpi=100) layout = QVBoxLayout(self.fraPlot) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.plot) self.fraPlot.setLayout(layout) self.helper = HelpHandler(self) self.Xunits = {} self.Yunits = {} self.Xlabel = "" self.Ylabel = "" self.Xunit = "" self.Yunit = "" self.TXT_OPEN_CURVE_TITLE = 'Open a Curve' self.TXT_SAVE_CURVE_TITLE = 'Save Curve As' self.TXT_CURVE_FILTER = 'Curve files (*.CRV)|*.CRV|All files|*.*' self.xvals = [] self.yvals = [] self.btnClose.clicked.connect(self.frm_close) self.btnHelp.clicked.connect(self.get_help) self.actionOpen.triggered.connect(self.open_datafile) self.actionCopy.triggered.connect(self.copy_plot) self.actionSave.triggered.connect(self.save_plot) self.actionPrint.triggered.connect(self.print_plot) # self.installEventFilter(self) self.do_plot() def open_datafile(self): pass def copy_plot(self): pass def save_plot(self): pass def print_plot(self): pass def do_plot(self): """ Construct a plot of the dataset ToDo: based on user-specified plot type Returns: """ if self.dataset.shape[0] > 0 and self.dataset.shape[1] > 0: self.plot.setTitle(self.plot_title) if self.plot_type == 'timeseries': self.plot.set_time_series_data(self.dataset) elif self.plot_type == 'xy': self.plot.set_xy_data(self.dataset, self.x_title, self.y_title) pass def frm_close(self): """ Close the plot form and discard dataset Returns: """ self.close() def get_help(self): self.helper.show_help()
class frmDefaultsEditor(QMainWindow, Ui_frmGenericDefaultsEditor): """ Project defaults editor for setting and editing object id prefix (tab1) properties (tab2) hydraulic defaults (tab3) """ def __init__(self, session, project, defaults): QMainWindow.__init__(self, session) self.setupUi(self) self.helper = HelpHandler(self) self.help_topic = "swmm/src/src/projectdefaultsdialog.htm" self.defaults = defaults self.session = session self.project = project self.label_changed = False self.property_sub_changed = False self.parameter_changed = False self.loaded = False self.refresh_column = None if self.session is not None: self.setWindowTitle(self.session.model + " Project Defaults") self.cmdOK.clicked.connect(self.cmdOK_Clicked) self.cmdCancel.clicked.connect(self.cmdCancel_Clicked) #disable Help button on form since no other forms have one self.cmdHelp.setVisible(False) #self.cmdHelp.clicked.connect(self.cmdHelp_Clicked) # self.tabDefaults.currentChanged(int).connect(self.tab_changed) # self.tblGeneric.cellChanged(int, int).connect(self.tblGeneric_changed) self.tabDefaults.currentChanged.connect(self.tab_changed) self.tblGeneric.cellChanged.connect(self.tblGeneric_changed) self.chk4all.setVisible(False) self.corner_label_tab1 = QLabel("Object", self.tblGeneric) self.corner_label_tab1.setAlignment(QtCore.Qt.AlignCenter) self.corner_label_tab1.setAttribute( QtCore.Qt.WA_TransparentForMouseEvents) self.tblGeneric.verticalHeader().geometriesChanged.connect( self.resizeCorner) self.tblGeneric.horizontalHeader().geometriesChanged.connect( self.resizeCorner) self.gridLayout_tab2 = QGridLayout(self.tabDefaults.widget(1)) self.gridLayout_tab2.setObjectName(_fromUtf8("gridLayout_tab2")) self.tbl_2 = QTableWidget(self.tabDefaults.widget(1)) self.tbl_2.setObjectName(_fromUtf8("tbl_2")) self.tbl_2.setColumnCount(1) self.tbl_2.setRowCount(1) self.tbl_2.horizontalHeader().setStretchLastSection(True) self.gridLayout_tab2.addWidget(self.tbl_2, 0, 0, 0, 0) # self.tbl_2.cellChanged(int, int).connect(self.tbl_2_changed) self.tbl_2.cellChanged.connect(self.tbl_2_changed) self.corner_label_tab2 = QLabel("Property", self.tbl_2) self.corner_label_tab2.setAlignment(QtCore.Qt.AlignCenter) self.corner_label_tab2.setAttribute( QtCore.Qt.WA_TransparentForMouseEvents) self.tblGeneric.verticalHeader().geometriesChanged.connect( self.resizeCorner) self.tblGeneric.horizontalHeader().geometriesChanged.connect( self.resizeCorner) self.gridLayout_tab3 = QGridLayout(self.tabDefaults.widget(2)) self.gridLayout_tab3.setObjectName(_fromUtf8("gridLayout_tab3")) self.tbl_3 = QTableWidget(self.tabDefaults.widget(2)) self.tbl_3.setObjectName(_fromUtf8("tbl_3")) self.tbl_3.setColumnCount(1) self.tbl_3.setRowCount(1) self.tbl_3.horizontalHeader().setStretchLastSection(True) self.gridLayout_tab3.addWidget(self.tbl_3, 0, 0, 0, 0) self.tbl_3.cellChanged.connect(self.tbl_3_changed) self.corner_label_tab3 = QLabel("Option", self.tbl_3) self.corner_label_tab3.setAlignment(QtCore.Qt.AlignCenter) self.corner_label_tab3.setAttribute( QtCore.Qt.WA_TransparentForMouseEvents) self.tbl_3.verticalHeader().geometriesChanged.connect( self.resizeCorner) self.tbl_3.horizontalHeader().geometriesChanged.connect( self.resizeCorner) self.sm_hydraulics = QtCore.QSignalMapper(self) self.sm_hydraulics.mapped.connect(self.tbl_3_combo_indexChanged) self.populate_defaults() self.installEventFilter(self) self.loaded = True def resizeCorner(self): tab_ind = self.tabDefaults.currentIndex() if tab_ind == 0: self.corner_label_tab1.setGeometry( 0, 0, self.tblGeneric.verticalHeader().width(), self.tblGeneric.horizontalHeader().height()) elif tab_ind == 1: self.corner_label_tab2.setGeometry( 0, 0, self.tbl_2.verticalHeader().width(), self.tbl_2.horizontalHeader().height()) elif tab_ind == 2: self.corner_label_tab3.setGeometry( 0, 0, self.tbl_3.verticalHeader().width(), self.tbl_3.horizontalHeader().height()) def populate_defaults(self): """ set up the defaults from ini settings Returns: """ self.set_tabs(3) self.tabDefaults.setTabText(0, "ID Labels") self.tabDefaults.setTabText(1, "Subcatchments") self.tabDefaults.setTabText(2, "Nodes/Links") self.set_tab_prefix() self.set_sub_properties() self.set_tab_hydraulics() #self.tab_changed(0) def set_tabs(self, num_tab): """ ensure desired number of tabs are created Args: num_tab: the desired number of tabs Returns: """ while self.tabDefaults.count() < num_tab: c = self.tabDefaults.count() new_tab = QWidget(self.tabDefaults) self.tabDefaults.addTab(new_tab, "tab_" + str(c + 1)) while self.tabDefaults.count() > num_tab: c = self.tabDefaults.count() w = self.tabDefaults.widget(c - 1) self.tabDefaults.removeTab(c - 1) if w: del w def set_tab_prefix(self): """ setup the object id tab entries Returns: """ #self.model_object_keys = ["Rain Gage", "Subcatchment", "Junction", "Outfall", "Divider", # "Storage Unit", "Conduit", "Pump", "Regulator"] self.tblGeneric.setColumnCount(1) self.tblGeneric.setRowCount(len(self.defaults.model_object_keys)) self.tblGeneric.setHorizontalHeaderLabels(["ID Prefix"]) self.tblGeneric.setVerticalHeaderLabels( self.defaults.model_object_keys) for i in range(0, len(self.defaults.model_object_keys)): prefix = "" if self.defaults: #prefix = unicode(self.qsettings.value("Labels/" + self.model_object_keys[i], "")) prefix = self.defaults.model_object_prefix[ self.defaults.model_object_keys[i]] #self.tblGeneric.insertRow(self.tblGeneric.rowCount()) self.tblGeneric.setItem(i, 0, QTableWidgetItem(prefix)) self.tblGeneric.insertRow(self.tblGeneric.rowCount()) self.tblGeneric.setVerticalHeaderItem( self.tblGeneric.rowCount() - 1, QTableWidgetItem(self.defaults.id_increment_key)) if self.defaults: #self.increment = int(self.qsettings.value("Labels/Increment", 1)) self.increment = self.defaults.id_increment self.tblGeneric.setItem( self.tblGeneric.rowCount() - 1, 0, QTableWidgetItem(str(self.defaults.id_increment))) pass def set_sub_properties(self): """ setup object property defaults tab entries Returns: """ properties = [ "Area", "Width", "% Slope", "% Imperv", "N-Imperv", "N-Perv", "Dstore-Imperv", "Dstore-Perv", "%Zero-Imperv", "Infiltration Model" ] #self.properties_def_values = [5, 500, 0.5, 25, 0.01, 0.1, 0.05, 0.05, 25, "HORTON"] self.tbl_2.setColumnCount(1) self.tbl_2.setRowCount(len(self.defaults.properties_sub_keys)) self.tbl_2.setHorizontalHeaderLabels(["Default Value"]) self.tbl_2.setVerticalHeaderLabels(properties) for i in range(0, len(self.defaults.properties_sub_keys) - 1): #def_val = unicode(self.qsettings.value("Defaults/" + self.properties[i], def_val)) def_val = self.defaults.properties_sub_values[ self.defaults.properties_sub_keys[i]] self.tbl_2.setItem(i, 0, QTableWidgetItem(str(def_val))) self.set_infilmodel_cell(0) pass def set_tab_hydraulics(self): """ setup the hydraulic parameter defaults tab entries Returns: """ properties = [ "Node Invert", "Node Max. Depth", "Node Ponded Area", "Conduit Length", "Conduit Geometry", "Conduit Roughness", "Flow Units", "Link Offsets", "Routing Method", "Force Main Equation" ] #self.parameters_def_values = [0, 0, 0, 400, "CIRCULAR", 0.01, "CFS", "DEPTH", "KINWAVE", "H_W"] self.tbl_3.setColumnCount(1) self.tbl_3.setRowCount(len(self.defaults.parameters_keys)) self.tbl_3.setHorizontalHeaderLabels(["Default Value"]) self.tbl_3.setVerticalHeaderLabels(properties) for i in range(0, len(self.defaults.parameters_keys)): combobox = None key = self.defaults.parameters_keys[i] def_val = self.defaults.parameters_values[key] if "flow_units" in key.lower(): combobox = QComboBox() enum_val = FlowUnits[def_val] elif "link_offsets" in key.lower(): combobox = QComboBox() enum_val = LinkOffsets[def_val] elif "routing_model" in key.lower(): combobox = QComboBox() enum_val = FlowRouting[def_val.upper()] elif "force_main" in key.lower(): combobox = QComboBox() if def_val.upper() == "H-W": enum_val = ForceMainEquation['H_W'] if def_val.upper() == "D-W": enum_val = ForceMainEquation['D_W'] if combobox is not None: combobox.setObjectName(key + "|" + str(i) + "|0") set_combo_items(type(enum_val), combobox) set_combo(combobox, enum_val) combobox.currentIndexChanged.connect(self.sm_hydraulics.map) self.sm_hydraulics.setMapping(combobox, i) self.tbl_3.setCellWidget(i, 0, combobox) else: if "conduit_shape" in key.lower(): self.set_channel_cell(0) else: self.tbl_3.setItem(i, 0, QTableWidgetItem(str(def_val))) pass def eventFilter(self, ui_object, event): if event.type() == QtCore.QEvent.WindowUnblocked: if self.refresh_column and self.refresh_column > -1: self.set_infilmodel_cell(self.refresh_column) self.set_channel_cell(self.refresh_column) self.refresh_column = -1 return False def set_infilmodel_cell(self, column): # text plus button for demand categories editor tb = TextPlusButton(self) self.infil_model = E_InfilModel.HORTON.name if self.defaults: self.infil_model = self.defaults.properties_sub_values[ self.defaults.infil_model_key] # if self.qsettings.contains(self.default_key_infilmodel): # model_obj = self.qsettings.value(self.default_key_infilmodel) # # model_name = type(model_obj) # if model_obj is not None: # self.infil_model = unicode(model_obj.model_type().name) # else: # self.infil_model = unicode(self.qsettings.value("Defaults/" + self.properties[len(self.properties) - 1], # self.infil_model)) tb.textbox.setText(self.infil_model) tb.textbox.setEnabled(False) tb.column = column tb.button.clicked.connect(self.make_show_infilmodel(column)) self.tbl_2.setCellWidget(self.tbl_2.rowCount() - 1, 0, tb) def make_show_infilmodel(self, column): def local_show(): frm = frmInfiltration(self, [], None, "Default Infiltration Model", defaults=self.defaults) #frm.set_from(self.project, "") frm.setWindowModality(QtCore.Qt.ApplicationModal) frm.show() self.refresh_column = column self.property_sub_changed = True self.set_infilmodel_cell(0) return local_show def set_channel_cell(self, column): # text plus button for demand categories editor # xsection = CrossSection() tb = TextPlusButton(self) if self.defaults is not None and self.defaults.xsection is not None: self.channel_geom = self.defaults.xsection.shape.name tb.textbox.setText(self.channel_geom) tb.textbox.setEnabled(False) tb.column = column tb.button.clicked.connect(self.make_show_channel( column, self.defaults)) self.tbl_3.setCellWidget(4, 0, tb) def make_show_channel(self, column, defaults): def local_show(): frm = frmCrossSection(self.session, defaults=defaults) frm.setWindowTitle("Define Default Conduit Geometry") #frm.set_from(self.project, "") frm.setWindowModality(QtCore.Qt.ApplicationModal) frm.show() self.refresh_column = column self.parameter_changed = True self.set_channel_cell(0) return local_show def move_table(self, index): """ dynamically move table control to the currently active tab this is when only one table control is shared among multiple tabs Args: index: the active tab's index Returns: """ for i in range(0, self.tabDefaults.count()): controls = self.tabDefaults.widget(i).findChildren( QTableWidget, self.tblGeneric.objectName()) if len(controls) > 0 and i != index: layout_src = self.tabDefaults.widget(i).layout() if layout_src is not None: layout_src.removeWidget(self.tblGeneric) layout_dest = self.tabDefaults.widget(index).layout() if layout_dest is None: layout_dest = QGridLayout(self.tabDefaults.widget(index)) self.tabDefaults.widget(index).setLayout(layout_dest) layout_dest.addChildWidget(self.tblGeneric) break pass def tab_changed(self, index): #self.move_table(index) if index == 0: self.help_topic = "epanet/src/src/defaultidlabels.htm" # self.set_tab_prefix() elif index == 1: self.help_topic = "epanet/src/src/defaultsubcatchmentproperties.htm" # self.set_sub_properties() elif index == 2: self.help_topic = "epanet/src/src/defaultnodelinkproperties.htm" # self.set_tab_hydraulics() pass def tblGeneric_changed(self, row, col): if not self.loaded: return if self.tblGeneric.verticalHeaderItem(row) is None: return item = self.tblGeneric.item(row, col) if item is None: return key = self.tblGeneric.verticalHeaderItem(row).text() if key == self.defaults.id_increment_key: val, val_is_good = ParseData.intTryParse(item.text()) if val_is_good: self.defaults.id_increment = val else: self.defaults.model_object_prefix[key] = item.text() self.label_changed = True pass def tbl_2_changed(self, row, col): if not self.loaded: return if self.tbl_2.verticalHeaderItem(row) is None: return item = self.tbl_2.item(row, col) if item is None: return key = self.tbl_2.verticalHeaderItem(row).text() if "infiltration model" in key.lower(): self.defaults.properties_sub_values[key] = item.currentText() else: val, val_is_good = ParseData.floatTryParse(item.text()) if val_is_good: key = self.defaults.properties_sub_keys[row] self.defaults.properties_sub_values[key] = val self.property_sub_changed = True pass def tbl_3_changed(self, row, col): if not self.loaded: return if self.tbl_3.verticalHeaderItem(row) is None: return item = self.tbl_3.item(row, col) if item is None: return key = self.tbl_3.verticalHeaderItem(row).text() if "flow_units" in key.lower() or \ "link_offsets" in key.lower() or \ "routing" in key.lower() or \ "force_main" in key.lower(): # do nothing pass elif "conduit_shape" in key.lower(): #self.defaults.xsection.shape = CrossSection[item.text()] pass else: val, val_is_good = ParseData.floatTryParse(item.text()) if val_is_good: key = self.defaults.parameters_keys[row] self.defaults.parameters_values[key] = val self.parameter_changed = True pass def tbl_3_combo_indexChanged(self, index): if not self.loaded: return cb = self.tbl_3.cellWidget(index, 0) key = self.tbl_3.verticalHeaderItem(index).text() val = cb.currentText() self.defaults.parameters_values[key] = val self.parameter_changed = True pass def cmdOK_Clicked(self): """ save/sync user changes to the defaults Returns: """ if self.label_changed: self.defaults.sync_defaults_label() pass if self.property_sub_changed: self.defaults.sync_defaults_sub_property() pass if self.parameter_changed: self.defaults.sync_defaults_parameter() pass if self.chk4all.isChecked(): # take default labels and defaults from project ini file and apply to global SWMM.ini file self.session.program_settings.sync() pass self.close() pass def cmdCancel_Clicked(self): """ discard user changes to the defaults Returns: """ self.close() pass def cmdHelp_Clicked(self): """ display help """ self.helper.show_help() pass
class frmCurveEditor(QMainWindow, Ui_frmCurveEditor): def __init__(self, main_form, title, curve_type, edit_these, new_item): QMainWindow.__init__(self, main_form) self.helper = HelpHandler(self) self.help_topic = "swmm/src/src/curveeditordialog.htm" self.setupUi(self) if title: self.setWindowTitle(title) self.cboCurveType.clear() ui.convenience.set_combo_items(core.swmm.curves.CurveType, self.cboCurveType) self.cmdOK.clicked.connect(self.cmdOK_Clicked) self.cmdCancel.clicked.connect(self.cmdCancel_Clicked) self.btnSave.clicked.connect(self.save_curve_data) self.btnLoad.clicked.connect(self.load_curve_data) self.btnHelp.clicked.connect(self.show_help) self.btnView.clicked.connect(self.btnView_Clicked) # self.cboCurveType.clicked.connect(self.cboCurveType_currentIndexChanged) self.cboCurveType.currentIndexChanged.connect( self.cboCurveType_currentIndexChanged) # self.set_from(main_form.project) # do after init to set curve type self._main_form = main_form self.curve_type = curve_type self.project = main_form.project self.section = self.project.curves self.X = [] self.Y = [] self.new_item = new_item if new_item: self.set_from(new_item) elif edit_these: if isinstance(edit_these, list): # edit first transect if given a list self.set_from(edit_these[0]) else: self.set_from(edit_these) if (main_form.program_settings.value("Geometry/" + "frmCurveEditor_geometry") and main_form.program_settings.value("Geometry/" + "frmCurveEditor_state")): self.restoreGeometry( main_form.program_settings.value("Geometry/" + "frmCurveEditor_geometry", self.geometry(), type=QtCore.QByteArray)) self.restoreState( main_form.program_settings.value("Geometry/" + "frmCurveEditor_state", self.windowState(), type=QtCore.QByteArray)) def set_from(self, curve): flow_units = self._main_form.project.options.flow_units.name if not isinstance(curve, Curve): curve = self.section.value[curve] if isinstance(curve, Curve): self.editing_item = curve self.tblMult.setRowCount( max(len(curve.curve_xy) + 1, self.tblMult.rowCount())) if self.curve_type == "CONTROL": self.cboCurveType.setVisible(False) self.lblCurveType.setVisible(False) self.tblMult.setHorizontalHeaderLabels( ("Controller Value", "Control Setting")) elif self.curve_type == "DIVERSION": self.cboCurveType.setVisible(False) self.lblCurveType.setVisible(False) self.tblMult.setHorizontalHeaderLabels( ("Inflow (" + flow_units + ")", "Outflow (" + flow_units + ")")) elif self.curve_type == "PUMP": self.cboCurveType.setVisible(True) self.lblCurveType.setVisible(True) if curve.curve_type.name == "PUMP1": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Volume (m3)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Volume (ft3)", "Flow (" + flow_units + ")")) if curve.curve_type.name == "PUMP2": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Depth (m)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Depth (ft)", "Flow (" + flow_units + ")")) if curve.curve_type.name == "PUMP3": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Head (m)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Head (ft)", "Flow (" + flow_units + ")")) if curve.curve_type.name == "PUMP4": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Depth (m)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Depth (ft)", "Flow (" + flow_units + ")")) self.cboCurveType.clear() self.cboCurveType.addItems(("TYPE1", "TYPE2", "TYPE3", "TYPE4")) elif self.curve_type == "RATING": self.cboCurveType.setVisible(False) self.lblCurveType.setVisible(False) if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Head (m)", "Outflow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Head (ft)", "Outflow (" + flow_units + ")")) elif self.curve_type == "SHAPE": self.cboCurveType.setVisible(False) self.lblCurveType.setVisible(False) self.tblMult.setHorizontalHeaderLabels( ("Depth/Full Depth", "Width/Full Depth")) elif self.curve_type == "STORAGE": self.cboCurveType.setVisible(False) self.lblCurveType.setVisible(False) if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Depth (m)", "Area (m2)")) else: self.tblMult.setHorizontalHeaderLabels( ("Depth (ft)", "Area (ft2)")) elif self.curve_type == "TIDAL": self.cboCurveType.setVisible(False) self.lblCurveType.setVisible(False) if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Hour of Day", "Stage (m)")) else: self.tblMult.setHorizontalHeaderLabels( ("Hour of Day", "Stage (ft)")) elif self.curve_type == "WEIR": self.cboCurveType.setVisible(False) self.lblCurveType.setVisible(False) if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Head (m)", "Coefficient")) else: self.tblMult.setHorizontalHeaderLabels( ("Head (ft)", "Coefficient")) self.txtCurveName.setText(str(curve.name)) self.txtDescription.setText(str(curve.comment)) if self.curve_type == "PUMP": if curve.curve_type.name == "PUMP1": self.cboCurveType.setCurrentIndex(0) if curve.curve_type.name == "PUMP2": self.cboCurveType.setCurrentIndex(1) if curve.curve_type.name == "PUMP3": self.cboCurveType.setCurrentIndex(2) if curve.curve_type.name == "PUMP4": self.cboCurveType.setCurrentIndex(3) point_count = -1 for point in curve.curve_xy: point_count += 1 led = QLineEdit(str(point[0])) self.tblMult.setItem(point_count, 0, QTableWidgetItem(led.text())) led = QLineEdit(str(point[1])) self.tblMult.setItem(point_count, 1, QTableWidgetItem(led.text())) def cmdOK_Clicked(self): # TODO: Check for blank/duplicate curve name # TODO: Check if X-values are in ascending order orig_name = self.editing_item.name orig_comment = self.editing_item.comment orig_type = self.editing_item.curve_type orig_xy = self.editing_item.curve_xy self.editing_item.name = self.txtCurveName.text() self.editing_item.comment = self.txtDescription.text() if len(self.editing_item.comment) > 0: if self.editing_item.comment[0] != ';': self.editing_item.comment = ';' + self.editing_item.comment # curve.curve_type = core.swmm.curves.CurveType[self.cboCurveType.currentText()] if self.curve_type == "PUMP": if self.cboCurveType.currentIndex() == 0: self.editing_item.curve_type = core.swmm.curves.CurveType[ "PUMP1"] if self.cboCurveType.currentIndex() == 1: self.editing_item.curve_type = core.swmm.curves.CurveType[ "PUMP2"] if self.cboCurveType.currentIndex() == 2: self.editing_item.curve_type = core.swmm.curves.CurveType[ "PUMP3"] if self.cboCurveType.currentIndex() == 3: self.editing_item.curve_type = core.swmm.curves.CurveType[ "PUMP4"] self.editing_item.curve_xy = [] for row in range(self.tblMult.rowCount()): if self.tblMult.item(row, 0) and self.tblMult.item(row, 1): x = self.tblMult.item(row, 0).text() y = self.tblMult.item(row, 1).text() if len(x) > 0 and len(y) > 0: self.editing_item.curve_xy.append((x, y)) if self.new_item: # We are editing a newly created item and it needs to be added to the project self._main_form.add_item(self.new_item) self._main_form.mark_project_as_unsaved() else: pass # TODO: self._main_form.edited_? if orig_name != self.editing_item.name or \ orig_comment != self.editing_item.comment or \ orig_type != self.editing_item.curve_type or \ orig_xy != self.editing_item.curve_xy: self._main_form.mark_project_as_unsaved() self._main_form.program_settings.setValue( "Geometry/" + "frmCurveEditor_geometry", self.saveGeometry()) self._main_form.program_settings.setValue( "Geometry/" + "frmCurveEditor_state", self.saveState()) self.close() def cmdCancel_Clicked(self): self.close() def cboCurveType_currentIndexChanged(self, newIndex): curve_type = self.cboCurveType.currentText() flow_units = self._main_form.project.options.flow_units.name if curve_type == "TYPE1": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Volume (m3)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Volume (ft3)", "Flow (" + flow_units + ")")) elif curve_type == "TYPE2": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Depth (m)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Depth (ft)", "Flow (" + flow_units + ")")) elif curve_type == "TYPE3": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Head (m)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Head (ft)", "Flow (" + flow_units + ")")) elif curve_type == "TYPE4": if self._main_form.project.metric: self.tblMult.setHorizontalHeaderLabels( ("Depth (m)", "Flow (" + flow_units + ")")) else: self.tblMult.setHorizontalHeaderLabels( ("Depth (ft)", "Flow (" + flow_units + ")")) def load_curve_data(self): directory = self._main_form.program_settings.value("DataDir", "") file_name, ftype = QFileDialog.getOpenFileName(self, "Open Curve Data File", directory, "Curve Files (*.dat)") if os.path.exists(file_name): self._main_form.program_settings.setValue( "DataDir", os.path.dirname(file_name)) self._main_form.program_settings.sync() if file_name: with open(file_name, "r") as open_file: lines = open_file.readlines() if len(lines) > 1: a = lines[1].split() self.txtDescription.setText(a[len(a) - 1]) if len(lines) > 2: curve_xy = [] for i in range(2, len(lines)): try: x, y = lines[i].split() xval, xval_is_good = ParseData.floatTryParse(x) yval, yval_is_good = ParseData.floatTryParse(y) if xval_is_good and yval_is_good: curve_xy.append((x, y)) point_count = -1 for point in curve_xy: point_count += 1 led = QLineEdit(str(point[0])) self.tblMult.setItem(point_count, 0, QTableWidgetItem(led.text())) led = QLineEdit(str(point[1])) self.tblMult.setItem(point_count, 1, QTableWidgetItem(led.text())) pass except Exception as ex: pass def save_curve_data(self): directory = self._main_form.program_settings.value("DataDir", "") file_name, ftype = QFileDialog.getSaveFileName(self, "Save Curve Data File", directory, "Curve files (*.dat)") if os.path.exists(file_name): self._main_form.program_settings.setValue( "DataDir", os.path.dirname(file_name)) self._main_form.program_settings.sync() if file_name: path_only, file_only = os.path.split(file_name) try: self.curve_data_to_file(file_name) except Exception as ex: print(str(ex) + '\n' + str(traceback.print_exc())) QMessageBox.information( self, self._main_form.model, "Error saving {0}\nin {1}\n{2}\n{2}".format( file_only, path_only, str(ex), str(traceback.print_exc())), QMessageBox.Ok) def curve_data_to_file(self, file_name): if file_name: with open(file_name, 'w') as writer: #writer.writelines(self.as_text(project)) writer.write("EPASWMM Curve Data\n") writer.write(self.txtDescription.text() + "\n") for row in range(self.tblMult.rowCount()): if self.tblMult.item(row, 0) and self.tblMult.item(row, 1): x = self.tblMult.item(row, 0).text() y = self.tblMult.item(row, 1).text() if len(x) > 0 and len(y) > 0: writer.write("%s %s\n" % (str(x), str(y))) def show_help(self): self.helper.show_help() def GetData(self): # construct pandas time series from grid data del self.X[:] del self.Y[:] n = 0 for row in range(self.tblMult.rowCount()): if self.tblMult.item(row, 1): y_val, y_val_good = ParseData.floatTryParse( self.tblMult.item(row, 1).text()) x_val, x_val_good = ParseData.floatTryParse( self.tblMult.item(row, 0).text()) if y_val_good and x_val_good: # as long as the values are good self.Y.append(y_val) self.X.append(x_val) n += 1 else: return n return n def btnView_Clicked(self): """ Display the grid data with pandas dataframe plot function Returns: None """ n = self.GetData() if n > 0: ds = pd.Series(self.Y, index=self.X) df = pd.DataFrame({'DS-': ds}) # if Pump Type1 or Type2, plot as step function if self.curve_type == 'PUMP' and self.cboCurveType.currentIndex( ) in (0, 1): frm_plt = frmPlotViewer( df, 'step', self.curve_type + ' Curve ' + self.txtCurveName.text(), self.windowIcon(), self.tblMult.horizontalHeaderItem(0).text(), self.tblMult.horizontalHeaderItem(1).text()) else: frm_plt = frmPlotViewer( df, 'xy', self.curve_type + ' Curve ' + self.txtCurveName.text(), self.windowIcon(), self.tblMult.horizontalHeaderItem(0).text(), self.tblMult.horizontalHeaderItem(1).text()) # frm_plt.setWindowTitle('Curve Viewer') # frm_plt.setWindowModality(QtCore.Qt.ApplicationModal) # frm_plt.show() pass def keyPressEvent(self, event): if event.key() == Qt.Key_Return: if self.tblMult.currentRow() + 1 == self.tblMult.rowCount(): self.tblMult.insertRow(self.tblMult.rowCount())