def __init__(self, epanet_project, model_output):
        self.LogoTxt = (
            '**********************************************************************',
            '*                             E P A N E T                            *',
            '*                     Hydraulic and Water Quality                    *',
            '*                     Analysis for Pipe Networks                     *',
            '*                           Version 2.0                              *',
            '**********************************************************************'
        )
        self.F = None  # File being written to
        if isinstance(epanet_project, Project):
            self.project = epanet_project
        elif isinstance(epanet_project, str):
            self.project = Project()
            self.project.read_file(epanet_project)
        else:
            raise Exception(
                "Report Initialization: could not read EPANET project.")

        if isinstance(model_output, OutputObject):
            self.output = model_output
        elif isinstance(model_output, str):
            self.output = OutputObject(model_output)
        else:
            raise Exception(
                "Report Initialization: could not read output of model.\n"
                "Run the model to generate new output.")

        self.RptTitle = self.project.title.title
        self.PageNum = 0
        self.LineNum = 0
        self.Progstep = 0
        self.Nprogress = 0
Example #2
0
    def test_curves(self):
        """Test Curves section"""
        self.my_curve = curves.Curve()
        self.my_curve = curves.Curve()
        self.my_curve.curve_id = "XXX"
        self.my_curve.description = "test curve"
        self.my_curve.curve_type = curves.CurveType.HEADLOSS
        self.my_curve.curve_xy = ((1500, 250), (1400, 200))

        assert self.my_curve.curve_id == "XXX"
        assert self.my_curve.description == "test curve"
        assert self.my_curve.get_text().split() == [
            ';HEADLOSS:', 'test', 'curve', 'XXX', '1500', '250', 'XXX', '1400',
            '200'
        ], "incorrect pattern block"

        # Create new project with new text
        test_text = ("[CURVES]", ";ID\tX-Value\tY-Value",
                     ";--\t-------\t-------", ";PUMP: Pump Curve for Pump 9",
                     " 1\t1500\t250\t")
        from_text = Project()
        from_text.set_text('\n'.join(test_text))
        project_curves = from_text.curves
        assert Section.match_omit(project_curves.get_text(),
                                  '\n'.join(test_text), " -;\t\n")

        assert len(project_curves.value) == 1
        this_curve = project_curves.value[0]
        assert this_curve.curve_id == '1'
        assert this_curve.description == "Pump Curve for Pump 9"
        assert this_curve.curve_type == curves.CurveType.PUMP
        assert this_curve.curve_xy == [("1500", "250")]
    def runTest(self):
        """Test set_text and get_text"""
        from_text = Project()
        source_text = '\n'.join(self.TEST_TEXT)
        from_text.set_text(source_text)
        project_sources = from_text.sources

        assert Section.match_omit(project_sources.get_text(), source_text,
                                  " \t-;\n")

        assert project_sources.value[0].id == "JUNCTION-9090"
        assert project_sources.value[0].source_type == SourceType.CONCEN
        assert project_sources.value[0].baseline_strength == "8330"
        assert project_sources.value[0].pattern_id == "Pattern-A"

        assert project_sources.value[1].id == "JUNCTION-9091"
        assert project_sources.value[1].source_type == SourceType.MASS
        assert project_sources.value[1].baseline_strength == "8331"
        assert project_sources.value[1].pattern_id == "Pattern-B"

        assert project_sources.value[2].id == "JUNCTION-9092"
        assert project_sources.value[2].source_type == SourceType.FLOWPACED
        assert project_sources.value[2].baseline_strength == "8332"
        assert project_sources.value[2].pattern_id == "Pattern-C"

        assert project_sources.value[3].id == "JUNCTION-9093"
        assert project_sources.value[3].source_type == SourceType.SETPOINT
        assert project_sources.value[3].baseline_strength == "8333"
        assert project_sources.value[3].pattern_id == "Pattern-D"

        assert project_sources.value[4].id == "JUNCTION-9094"
        assert project_sources.value[4].source_type == SourceType.CONCEN
        assert project_sources.value[4].baseline_strength == "8334"
        assert project_sources.value[4].pattern_id == ""
    def runTest(self):
        """Test set_text and get_text"""
        from_text = Project()
        source_text = '\n'.join(self.TEST_TEXT)
        from_text.set_text(source_text)
        project_sources = from_text.sources

        assert Section.match_omit(project_sources.get_text(), source_text, " \t-;\n")

        assert project_sources.value[0].id == "JUNCTION-9090"
        assert project_sources.value[0].source_type == SourceType.CONCEN
        assert project_sources.value[0].baseline_strength == "8330"
        assert project_sources.value[0].pattern_id == "Pattern-A"

        assert project_sources.value[1].id == "JUNCTION-9091"
        assert project_sources.value[1].source_type == SourceType.MASS
        assert project_sources.value[1].baseline_strength == "8331"
        assert project_sources.value[1].pattern_id == "Pattern-B"

        assert project_sources.value[2].id == "JUNCTION-9092"
        assert project_sources.value[2].source_type == SourceType.FLOWPACED
        assert project_sources.value[2].baseline_strength == "8332"
        assert project_sources.value[2].pattern_id == "Pattern-C"

        assert project_sources.value[3].id == "JUNCTION-9093"
        assert project_sources.value[3].source_type == SourceType.SETPOINT
        assert project_sources.value[3].baseline_strength == "8333"
        assert project_sources.value[3].pattern_id == "Pattern-D"

        assert project_sources.value[4].id == "JUNCTION-9094"
        assert project_sources.value[4].source_type == SourceType.CONCEN
        assert project_sources.value[4].baseline_strength == "8334"
        assert project_sources.value[4].pattern_id == ""
    def test_curves(self):
        """Test Curves section"""
        self.my_curve = curves.Curve()
        self.my_curve = curves.Curve()
        self.my_curve.curve_id = "XXX"
        self.my_curve.description = "test curve"
        self.my_curve.curve_type = curves.CurveType.HEADLOSS
        self.my_curve.curve_xy = ((1500, 250), (1400, 200))

        assert self.my_curve.curve_id == "XXX"
        assert self.my_curve.description == "test curve"
        assert self.my_curve.get_text().split() == [';HEADLOSS:', 'test', 'curve',
                                                    'XXX', '1500', '250', 'XXX', '1400', '200'], "incorrect pattern block"

        # Create new project with new text
        test_text = ("[CURVES]",
                     ";ID\tX-Value\tY-Value",
                     ";--\t-------\t-------",
                     ";PUMP: Pump Curve for Pump 9",
                     " 1\t1500\t250\t")
        from_text = Project()
        from_text.set_text('\n'.join(test_text))
        project_curves = from_text.curves
        assert Section.match_omit(project_curves.get_text(), '\n'.join(test_text), " -;\t\n")

        assert len(project_curves.value) == 1
        this_curve = project_curves.value[0]
        assert this_curve.curve_id == '1'
        assert this_curve.description == "Pump Curve for Pump 9"
        assert this_curve.curve_type == curves.CurveType.PUMP
        assert this_curve.curve_xy == [("1500", "250")]
    def test_patterns(self):
        """Test one Pattern section"""
        self.my_pattern = patterns.Pattern()
        self.my_pattern.description = "test pattern"
        self.my_pattern.pattern_id = "XXX"
        self.my_pattern.multipliers = ("1.0", "1.1", "1.2", "1.3")

        assert self.my_pattern.pattern_id == "XXX"
        assert self.my_pattern.description == "test pattern"
        assert self.my_pattern.get_text().split() == [";test", "pattern", "XXX", "1.0", "1.1", "1.2", "1.3"], "get_text"

        # Create new Project with this section populated from TEST_TEXT
        test_text = ("[PATTERNS]",
                     ";ID\tMultipliers",
                     ";Demand Pattern",
                     " 1\t1.0\t1.2\t1.4\t1.6\t1.4\t1.2",
                     " 1\t1.0\t0.8\t0.6\t0.4\t0.6\t0.8",
                     " 2\t2.0\t2.2\t2.4\t2.6\t2.4\t2.2",
                     " 2\t2.0\t2.8\t2.6\t2.4\t2.6\t2.8")

        from_text = Project()
        from_text.set_text('\n'.join(test_text))
        pattern_list = from_text.patterns.value
        assert len(pattern_list) == 2
        assert int(pattern_list[0].pattern_id) == 1
        assert int(pattern_list[1].pattern_id) == 2

        assert float(pattern_list[0].multipliers[0]) == 1.0
        assert float(pattern_list[0].multipliers[1]) == 1.2
        assert float(pattern_list[0].multipliers[2]) == 1.4
        assert float(pattern_list[0].multipliers[3]) == 1.6
        assert float(pattern_list[0].multipliers[4]) == 1.4
        assert float(pattern_list[0].multipliers[5]) == 1.2

        assert float(pattern_list[0].multipliers[6]) == 1.0
        assert float(pattern_list[0].multipliers[7]) == 0.8
        assert float(pattern_list[0].multipliers[8]) == 0.6
        assert float(pattern_list[0].multipliers[9]) == 0.4
        assert float(pattern_list[0].multipliers[10]) == 0.6
        assert float(pattern_list[0].multipliers[11]) == 0.8

        assert float(pattern_list[1].multipliers[0]) == 2.0
        assert float(pattern_list[1].multipliers[1]) == 2.2
        assert float(pattern_list[1].multipliers[2]) == 2.4
        assert float(pattern_list[1].multipliers[3]) == 2.6
        assert float(pattern_list[1].multipliers[4]) == 2.4
        assert float(pattern_list[1].multipliers[5]) == 2.2

        assert float(pattern_list[1].multipliers[6]) == 2.0
        assert float(pattern_list[1].multipliers[7]) == 2.8
        assert float(pattern_list[1].multipliers[8]) == 2.6
        assert float(pattern_list[1].multipliers[9]) == 2.4
        assert float(pattern_list[1].multipliers[10]) == 2.6
        assert float(pattern_list[1].multipliers[11]) == 2.8
    def __init__(self, epanet_project, model_output):
        self.LogoTxt = (
            '**********************************************************************',
            '*                             E P A N E T                            *',
            '*                     Hydraulic and Water Quality                    *',
            '*                     Analysis for Pipe Networks                     *',
            '*                           Version 2.0                              *',
            '**********************************************************************')
        self.F = None  # File being written to
        if isinstance(epanet_project, Project):
            self.project = epanet_project
        elif isinstance(epanet_project, str):
            self.project = Project()
            self.project.read_file(epanet_project)
        else:
            raise Exception("Report Initialization: could not read EPANET project.")

        if isinstance(model_output, OutputObject):
            self.output = model_output
        elif isinstance(model_output, str):
            self.output = OutputObject(model_output)
        else:
            raise Exception("Report Initialization: could not read output of model.\n"
                            "Run the model to generate new output.")

        self.RptTitle = self.project.title.title
        self.PageNum = 0
        self.LineNum = 0
        self.Progstep = 0
        self.Nprogress = 0
    def runTest(self):
        """Test set_text and get_text of demand options"""
        from_text = Project()
        source_text = '\n'.join(self.TEST_TEXT)
        from_text.set_text(source_text)
        project_demands = from_text.demands

        assert Section.match_omit(project_demands.get_text(), source_text, " \t-;\n")

        assert project_demands.value[0].junction_id == "JUNCTION-0"
        assert project_demands.value[0].base_demand == "0.0"
        assert project_demands.value[0].demand_pattern == "PATTERN-1"
        assert project_demands.value[0].category == ''

        assert project_demands.value[1].junction_id == "JUNCTION-1"
        assert project_demands.value[1].base_demand == "0.1"
        assert project_demands.value[1].demand_pattern == "PATTERN-2"
        assert project_demands.value[1].category == ''

        assert project_demands.value[2].junction_id == "JUNCTION-12"
        assert project_demands.value[2].base_demand == "0.2"
        assert project_demands.value[2].demand_pattern == "PATTERN-12"
        assert project_demands.value[2].category == "Category-12"
    def runTest(self):
        """Test set_text and get_text of demand options"""
        from_text = Project()
        source_text = '\n'.join(self.TEST_TEXT)
        from_text.set_text(source_text)
        project_demands = from_text.demands

        assert Section.match_omit(project_demands.get_text(), source_text,
                                  " \t-;\n")

        assert project_demands.value[0].junction_id == "JUNCTION-0"
        assert project_demands.value[0].base_demand == "0.0"
        assert project_demands.value[0].demand_pattern == "PATTERN-1"
        assert project_demands.value[0].category == ''

        assert project_demands.value[1].junction_id == "JUNCTION-1"
        assert project_demands.value[1].base_demand == "0.1"
        assert project_demands.value[1].demand_pattern == "PATTERN-2"
        assert project_demands.value[1].category == ''

        assert project_demands.value[2].junction_id == "JUNCTION-12"
        assert project_demands.value[2].base_demand == "0.2"
        assert project_demands.value[2].demand_pattern == "PATTERN-12"
        assert project_demands.value[2].category == "Category-12"
class Reports:
    PAGESIZE = 55
    ULINE = '----------------------------------------------------------------------'
    FMT18 = '  Page 1                                          {:>22}'
    FMT_DATE = '%Y/%m/%d %I:%M%p'
    FMT82 = '  Page {:4d} {:60}'
    FMT71 = 'Energy Usage:'
    FMT72 = '                  Usage   Avg.     Kw-hr      Avg.      Peak      Cost'
    FMT73 = 'Pump             Factor Effic.     {:5}        Kw        Kw      /day'
    FMT74 = '{:45} Demand Charge: {:9.2f}'
    FMT75 = '{:45} Total Cost:    {:9.2f}'
    TXT_perM3 = '/m3'
    TXT_perMGAL = '/Mgal'
    TXT_CONTINUED = ' (continued)'
    TXT_INPUT_FILE = 'Input File: '
    TXT_LINK_INFO = 'Link - Node Table:'
    TXT_NODE_RESULTS = 'Node Results'
    TXT_LINK_RESULTS = 'Link Results'
    TXT_AT = ' at '
    TXT_ID = 'ID'
    TXT_NODE = 'Node'
    TXT_LINK = 'Link'
    TXT_START = 'Start'
    TXT_END = 'End'

    TimeStat = ['Single Period', 'Average', 'Minimum', 'Maximum', 'Range']

    def __init__(self, epanet_project, model_output):
        self.LogoTxt = (
            '**********************************************************************',
            '*                             E P A N E T                            *',
            '*                     Hydraulic and Water Quality                    *',
            '*                     Analysis for Pipe Networks                     *',
            '*                           Version 2.0                              *',
            '**********************************************************************')
        self.F = None  # File being written to
        if isinstance(epanet_project, Project):
            self.project = epanet_project
        elif isinstance(epanet_project, str):
            self.project = Project()
            self.project.read_file(epanet_project)
        else:
            raise Exception("Report Initialization: could not read EPANET project.")

        if isinstance(model_output, OutputObject):
            self.output = model_output
        elif isinstance(model_output, str):
            self.output = OutputObject(model_output)
        else:
            raise Exception("Report Initialization: could not read output of model.\n"
                            "Run the model to generate new output.")

        self.RptTitle = self.project.title.title
        self.PageNum = 0
        self.LineNum = 0
        self.Progstep = 0
        self.Nprogress = 0

    def write_line(self, line):
        if (self.LineNum >= self.PAGESIZE):
            self.PageNum += 1
            self.F.write('\n\f\n')  # newline form-feed newline
            self.F.write(self.FMT82.format(self.PageNum, self.RptTitle) + '\n')
            self.LineNum = 3
        self.F.write('  ' + line + '\n')
        self.LineNum += 1

    def write_logo(self):
        self.PageNum = 1
        self.LineNum = 1
        self.write_line(self.FMT18.format(datetime.now().strftime(self.FMT_DATE)))
        for line in self.LogoTxt:
            self.write_line(line)
        self.write_line('')
        self.write_line(self.TXT_INPUT_FILE + self.project.file_name)
        self.write_line('')
        self.write_line(self.RptTitle)
        self.write_line(self.project.title.notes)
        # self.write_line('')

    def write_energy_header(self, ContinueFlag):
        if self.LineNum + 11 > self.PAGESIZE:
            self.LineNum = self.PAGESIZE
        units = (self.TXT_perMGAL, self.TXT_perM3)[self.output.unit_system]
        line = self.FMT71
        if ContinueFlag:
            line += self.TXT_CONTINUED
        self.write_line(line)
        self.write_line(self.ULINE)
        line = self.FMT72
        self.write_line(line)
        line = self.FMT73.format(units)
        self.write_line(line)
        self.write_line(self.ULINE)

    def write_energy(self):
        self.write_energy_header(False)
        Csum = 0.0
        for pump in self.project.pumps.value:
            x = [0,0,0,0,0,0]
            Dcharge = 0
            # Uoutput.GetPumpEnergy(k,x,Dcharge)
            Csum += x[5]
            if (self.LineNum >= self.PAGESIZE):
                self.write_energy_header(True)
            line = '{:15}  {:6.2f} {:6.2f} {:9.2f} {:9.2f} {:9.2f} {:9.2f}'.format(
                    pump.id, x[0],   x[1],   x[2],   x[3],   x[4],   x[5])
            self.write_line(line)

        self.write_line(self.ULINE)
        line = self.FMT74.format('', Dcharge)
        self.write_line(line)
        line = self.FMT75.format('', Csum + Dcharge)
        self.write_line(line)
        self.write_line('')

    def write_node_header(self, period, ContinueFlag):
        if self.LineNum + 11 > self.PAGESIZE:
            self.LineNum = self.PAGESIZE
        line = self.TXT_NODE_RESULTS
        if self.output.numPeriods > 1:
            line += self.TXT_AT + self.output.get_time_string(period)
        line += ':'
        if ContinueFlag:
            line += self.TXT_CONTINUED
        self.write_line(line)
        self.write_line(self.ULINE)
        line = '{:15} {:>10}{:>10}{:>10}{:>10}'.format(self.TXT_NODE,
                                                       ENR_NodeAttributeNames[ENR_demand],
                                                       ENR_NodeAttributeNames[ENR_head],
                                                       ENR_NodeAttributeNames[ENR_pressure],
                                                       ENR_NodeAttributeNames[ENR_quality])
        self.write_line(line)
        line = '{:15} {:>10}{:>10}{:>10}{:>10}'.format(self.TXT_ID,
                                                       ENR_NodeAttributeUnits[ENR_demand][self.output.unit_system],
                                                       ENR_NodeAttributeUnits[ENR_head][self.output.unit_system],
                                                       ENR_NodeAttributeUnits[ENR_pressure][self.output.unit_system],
                                                       ENR_NodeAttributeUnits[ENR_quality][self.output.unit_system])
        self.write_line(line)
        self.write_line(self.ULINE)

    def write_link_header(self, period, ContinueFlag):
        if self.LineNum + 11 > self.PAGESIZE:
            self.LineNum = self.PAGESIZE
        S = self.TXT_LINK_RESULTS
        if self.output.numPeriods > 1:
            S += self.TXT_AT + self.output.get_time_string(period)
        S += ':'
        if ContinueFlag:
            S += self.TXT_CONTINUED
        self.write_line(S)
        self.write_line(self.ULINE)
        S = '{:15} {:10}{:10}{:10}{:10}'.format(self.TXT_LINK,
                                                ENR_LinkAttributeNames[ENR_flow],
                                                ENR_LinkAttributeNames[ENR_velocity],
                                                ENR_LinkAttributeNames[ENR_headloss],
                                                ENR_LinkAttributeNames[ENR_status])
        self.write_line(S)
        S = '{:15} {:10}{:10}{:10}'.format(self.TXT_ID,
                                           ENR_LinkAttributeUnits[ENR_flow][self.output.unit_system],
                                           ENR_LinkAttributeUnits[ENR_velocity][self.output.unit_system],
                                           ENR_LinkAttributeUnits[ENR_headloss][self.output.unit_system])
        self.write_line(S)
        self.write_line(self.ULINE)

    def write_link_info_header(self, ContinueFlag):
        S = self.TXT_LINK_INFO
        if ContinueFlag:
            S += self.TXT_CONTINUED
        self.write_line(S)
        self.write_line(self.ULINE)
        S = '{:15}{:15}{:15}{:10}{:10}'.format(self.TXT_LINK, self.TXT_START, self.TXT_END, "Length", "Diameter")
        self.write_line(S)

        len_units = ('ft','m')[self.output.unit_system]
        dia_units = ('in','mm')[self.output.unit_system]
        S = '{:15}{:15}{:15}{:>10}{:>10}'.format(self.TXT_ID, self.TXT_NODE, self.TXT_NODE, len_units, dia_units)
        self.write_line(S)
        self.write_line(self.ULINE)

    def write_link_info(self):
        self.write_link_info_header(False)
        for conduits in (self.project.pipes, self.project.pumps, self.project.valves):
            # TODO: update progress bar: MainForm.UpdateProgressBar(Nprogress, ProgStep)
            for conduit in conduits.value:
                # Note: Pascal report got these values from binary, we get them here from input
                # length = self.output.get_LinkValue(conduits.id, 0, 1) # Uoutput.GetLinkValStr(LINKLENGTH,0,I,J)
                if (self.LineNum >= self.PAGESIZE):
                    self.write_link_info_header(True)
                if hasattr(conduit, "length"):
                    length = conduit.length
                else:
                    length = "#N/A"
                if hasattr(conduit, "diameter"):
                    diameter = conduit.diameter
                else:
                    diameter = "#N/A"
                S = '{:15}{:15}{:15}{:>10}{:>10}'.format(conduit.id, conduit.inlet_node, conduit.outlet_node,
                                                         length, diameter)
                if conduits is self.project.pumps:
                    S += ' Pump'
                elif conduits is self.project.valves:
                    S += ' Valve'
                self.write_line(S)
        self.write_line('')

    def write_node_table(self, period):
        self.write_node_header(period, False)
        for nodes in (self.project.junctions, self.project.reservoirs, self.project.tanks):
            for node in nodes.value:
                #         MainForm.UpdateProgressBar(Nprogress, ProgStep)
                node_index = self.output.get_NodeIndex(node.id)
                if node_index < 0:
                    line = '{:15} {}'.format(node.id, 'not found in output.')
                else:
                    demand     = self.output.get_NodeValue(node_index, period, ENR_demand)
                    head       = self.output.get_NodeValue(node_index, period, ENR_head)
                    pressure   = self.output.get_NodeValue(node_index, period, ENR_pressure)
                    quality    = self.output.get_NodeValue(node_index, period, ENR_quality)
                    line = '{:15} {:7.2f} {:7.2f} {:7.2f} {:7.2f}'.format(node.id, demand, head, pressure, quality)
                if nodes is self.project.reservoirs:
                    line += ' Reservoir'
                elif nodes is self.project.tanks:
                    line += ' Tank'
                if (self.LineNum >= self.PAGESIZE):
                    self.write_node_header(period, True)
                self.write_line(line)
        self.write_line('')

    def write_link_table(self, period):
        self.write_link_header(period, False)
        for links in (self.project.pipes, self.project.pumps, self.project.valves):
            for link in links.value:
                # MainForm.UpdateProgressBar(Nprogress, ProgStep)
                link_index = self.output.get_LinkIndex(link.id)
                if link_index < 0:
                    line = '{:15} {}'.format(link.id, 'not found in output.')
                else:
                    flow     = self.output.get_LinkValue(link_index, period, ENR_flow)
                    velocity = self.output.get_LinkValue(link_index, period, ENR_velocity)
                    headloss = self.output.get_LinkValue(link_index, period, ENR_headloss)
                    linkstat = "Unknown"  # TODO: self.output.get_LinkValue(link_index, T, ENR_
                    line = '{:15} {:9.2f} {:9.2f} {:9.2f} {:>10}'.format(link.id, flow, velocity, headloss, linkstat)
                if links is self.project.pumps:
                    line += ' Pump'
                elif links is self.project.valves:
                    line += ' Valve'

                if (self.LineNum >= self.PAGESIZE):
                    self.write_link_header(period, True)
                self.write_line(line)
        self.write_line('')

    def write_results(self):
        for period in range(0, self.output.numPeriods):
            # Application.ProcessMessages
            self.write_node_table(period)
            # Application.ProcessMessages
            self.write_link_table(period)

    def write_report(self, report_file_name):
        #   MainForm.ShowProgressBar('Writing full report...')
        with open(report_file_name, 'w') as self.F:
            try:
                # Total = self.output.nodeCount + self.output.linkCount
                # Total *= self.output.numPeriods
                # Total += self.output.linkCount
                # with MainForm.ProgressBar do
                #   N = Max div Step
                # ProgStep = Round(Total/N)
                # Nprogress = 0
                self.write_logo()
                #     Application.ProcessMessages
                self.write_link_info()
                if self.output.pumpCount > 0:
                    self.write_energy()
                self.write_results()
                return True
            finally:
                print "Finished writing report " + report_file_name
                #   MainForm.HideProgressBar

    def all_link_ids(self):
        ids = []
        for links in (self.project.pipes, self.project.pumps, self.project.valves):
            for link in links.value:
                if self.output.get_LinkIndex(link.id) > -1:
                    ids.append(link.id)
                else:
                    print("Skipping link " + link.id + " because it was not found in output")
        return ids

    def all_link_types(self):
        types = []
        for link in self.project.pipes.value:
            if self.output.get_LinkIndex(link.id) > -1:
                types.append("Pipe")
        for link in self.project.pumps.value:
            if self.output.get_LinkIndex(link.id) > -1:
                types.append("Pump")
        for link in self.project.valves.value:
            if self.output.get_LinkIndex(link.id) > -1:
                types.append("Valve")
        return types

    def all_node_indexes(self):
        indexes = []
        for nodes in (self.project.junctions, self.project.reservoirs, self.project.tanks):
            for node in nodes.value:
                node_index = self.output.get_NodeIndex(node.id)
                if node_index > -1:
                    indexes.append(node_index)
        return indexes

    def all_node_ids(self):
        ids = []
        for nodes in (self.project.junctions, self.project.reservoirs, self.project.tanks):
            for node in nodes.value:
                node_index = self.output.get_NodeIndex(node.id)
                if node_index > -1:
                    ids.append(node.id)
                else:
                    print("Skipping node " + node.id + " because it was not found in output")
        return ids

    def all_node_types(self):
        types = []
        for node in self.project.junctions.value:
            if self.output.get_NodeIndex(node.id) > -1:
                types.append("Junction")
        for node in self.project.reservoirs.value:
            if self.output.get_NodeIndex(node.id) > -1:
                types.append("Reservoir")
        for node in self.project.tanks.value:
            if self.output.get_NodeIndex(node.id) > -1:
                types.append("Tank")
        return types

    def node_distances(self, node_ids):
        return range(0, len(node_ids))
        # TODO: compute distance from node coordinates
        distances = [0]
        x = None
        y = None
        for node_id in node_ids:
            for nodes in (self.project.junctions, self.project.reservoirs, self.project.tanks):
                for node in nodes.value:
                    if node.id == node_id:
                        if x and y:
                            distances.append(sqrt((x - node.x) ^ 2 + (y - node.y) ^ 2))
        return distances
class Reports:
    PAGESIZE = 55
    ULINE = '----------------------------------------------------------------------'
    FMT18 = '  Page 1                                          {:>22}'
    FMT_DATE = '%Y/%m/%d %I:%M%p'
    FMT82 = '  Page {:4d} {:60}'
    FMT71 = 'Energy Usage:'
    FMT72 = '                  Usage   Avg.     Kw-hr      Avg.      Peak      Cost'
    FMT73 = 'Pump             Factor Effic.     {:5}        Kw        Kw      /day'
    FMT74 = '{:45} Demand Charge: {:9.2f}'
    FMT75 = '{:45} Total Cost:    {:9.2f}'
    TXT_perM3 = '/m3'
    TXT_perMGAL = '/Mgal'
    TXT_CONTINUED = ' (continued)'
    TXT_INPUT_FILE = 'Input File: '
    TXT_LINK_INFO = 'Link - Node Table:'
    TXT_NODE_RESULTS = 'Node Results'
    TXT_LINK_RESULTS = 'Link Results'
    TXT_AT = ' at '
    TXT_ID = 'ID'
    TXT_NODE = 'Node'
    TXT_LINK = 'Link'
    TXT_START = 'Start'
    TXT_END = 'End'

    TimeStat = ['Single Period', 'Average', 'Minimum', 'Maximum', 'Range']

    def __init__(self, epanet_project, model_output):
        self.LogoTxt = (
            '**********************************************************************',
            '*                             E P A N E T                            *',
            '*                     Hydraulic and Water Quality                    *',
            '*                     Analysis for Pipe Networks                     *',
            '*                           Version 2.0                              *',
            '**********************************************************************'
        )
        self.F = None  # File being written to
        if isinstance(epanet_project, Project):
            self.project = epanet_project
        elif isinstance(epanet_project, str):
            self.project = Project()
            self.project.read_file(epanet_project)
        else:
            raise Exception(
                "Report Initialization: could not read EPANET project.")

        if isinstance(model_output, OutputObject):
            self.output = model_output
        elif isinstance(model_output, str):
            self.output = OutputObject(model_output)
        else:
            raise Exception(
                "Report Initialization: could not read output of model.\n"
                "Run the model to generate new output.")

        self.RptTitle = self.project.title.title
        self.PageNum = 0
        self.LineNum = 0
        self.Progstep = 0
        self.Nprogress = 0

    def write_line(self, line):
        if (self.LineNum >= self.PAGESIZE):
            self.PageNum += 1
            self.F.write('\n\f\n')  # newline form-feed newline
            self.F.write(self.FMT82.format(self.PageNum, self.RptTitle) + '\n')
            self.LineNum = 3
        self.F.write('  ' + line + '\n')
        self.LineNum += 1

    def write_logo(self):
        self.PageNum = 1
        self.LineNum = 1
        self.write_line(
            self.FMT18.format(datetime.now().strftime(self.FMT_DATE)))
        for line in self.LogoTxt:
            self.write_line(line)
        self.write_line('')
        self.write_line(self.TXT_INPUT_FILE + self.project.file_name)
        self.write_line('')
        self.write_line(self.RptTitle)
        self.write_line(self.project.title.notes)
        # self.write_line('')

    def write_energy_header(self, ContinueFlag):
        if self.LineNum + 11 > self.PAGESIZE:
            self.LineNum = self.PAGESIZE
        units = (self.TXT_perMGAL, self.TXT_perM3)[self.output.unit_system]
        line = self.FMT71
        if ContinueFlag:
            line += self.TXT_CONTINUED
        self.write_line(line)
        self.write_line(self.ULINE)
        line = self.FMT72
        self.write_line(line)
        line = self.FMT73.format(units)
        self.write_line(line)
        self.write_line(self.ULINE)

    def write_energy(self):
        self.write_energy_header(False)
        Csum = 0.0
        for pump in self.project.pumps.value:
            x = [0, 0, 0, 0, 0, 0]
            Dcharge = 0
            # Uoutput.GetPumpEnergy(k,x,Dcharge)
            Csum += x[5]
            if (self.LineNum >= self.PAGESIZE):
                self.write_energy_header(True)
            line = '{:15}  {:6.2f} {:6.2f} {:9.2f} {:9.2f} {:9.2f} {:9.2f}'.format(
                pump.id, x[0], x[1], x[2], x[3], x[4], x[5])
            self.write_line(line)

        self.write_line(self.ULINE)
        line = self.FMT74.format('', Dcharge)
        self.write_line(line)
        line = self.FMT75.format('', Csum + Dcharge)
        self.write_line(line)
        self.write_line('')

    def write_node_header(self, period, ContinueFlag):
        if self.LineNum + 11 > self.PAGESIZE:
            self.LineNum = self.PAGESIZE
        line = self.TXT_NODE_RESULTS
        if self.output.numPeriods > 1:
            line += self.TXT_AT + self.output.get_time_string(period)
        line += ':'
        if ContinueFlag:
            line += self.TXT_CONTINUED
        self.write_line(line)
        self.write_line(self.ULINE)
        line = '{:15} {:>10}{:>10}{:>10}{:>10}'.format(
            self.TXT_NODE, ENR_NodeAttributeNames[ENR_demand],
            ENR_NodeAttributeNames[ENR_head],
            ENR_NodeAttributeNames[ENR_pressure],
            ENR_NodeAttributeNames[ENR_quality])
        self.write_line(line)
        line = '{:15} {:>10}{:>10}{:>10}{:>10}'.format(
            self.TXT_ID,
            ENR_NodeAttributeUnits[ENR_demand][self.output.unit_system],
            ENR_NodeAttributeUnits[ENR_head][self.output.unit_system],
            ENR_NodeAttributeUnits[ENR_pressure][self.output.unit_system],
            ENR_NodeAttributeUnits[ENR_quality][self.output.unit_system])
        self.write_line(line)
        self.write_line(self.ULINE)

    def write_link_header(self, period, ContinueFlag):
        if self.LineNum + 11 > self.PAGESIZE:
            self.LineNum = self.PAGESIZE
        S = self.TXT_LINK_RESULTS
        if self.output.numPeriods > 1:
            S += self.TXT_AT + self.output.get_time_string(period)
        S += ':'
        if ContinueFlag:
            S += self.TXT_CONTINUED
        self.write_line(S)
        self.write_line(self.ULINE)
        S = '{:15} {:10}{:10}{:10}{:10}'.format(
            self.TXT_LINK, ENR_LinkAttributeNames[ENR_flow],
            ENR_LinkAttributeNames[ENR_velocity],
            ENR_LinkAttributeNames[ENR_headloss],
            ENR_LinkAttributeNames[ENR_status])
        self.write_line(S)
        S = '{:15} {:10}{:10}{:10}'.format(
            self.TXT_ID,
            ENR_LinkAttributeUnits[ENR_flow][self.output.unit_system],
            ENR_LinkAttributeUnits[ENR_velocity][self.output.unit_system],
            ENR_LinkAttributeUnits[ENR_headloss][self.output.unit_system])
        self.write_line(S)
        self.write_line(self.ULINE)

    def write_link_info_header(self, ContinueFlag):
        S = self.TXT_LINK_INFO
        if ContinueFlag:
            S += self.TXT_CONTINUED
        self.write_line(S)
        self.write_line(self.ULINE)
        S = '{:15}{:15}{:15}{:10}{:10}'.format(self.TXT_LINK, self.TXT_START,
                                               self.TXT_END, "Length",
                                               "Diameter")
        self.write_line(S)

        len_units = ('ft', 'm')[self.output.unit_system]
        dia_units = ('in', 'mm')[self.output.unit_system]
        S = '{:15}{:15}{:15}{:>10}{:>10}'.format(self.TXT_ID, self.TXT_NODE,
                                                 self.TXT_NODE, len_units,
                                                 dia_units)
        self.write_line(S)
        self.write_line(self.ULINE)

    def write_link_info(self):
        self.write_link_info_header(False)
        for conduits in (self.project.pipes, self.project.pumps,
                         self.project.valves):
            # TODO: update progress bar: MainForm.UpdateProgressBar(Nprogress, ProgStep)
            for conduit in conduits.value:
                # Note: Pascal report got these values from binary, we get them here from input
                # length = self.output.get_LinkValue(conduits.id, 0, 1) # Uoutput.GetLinkValStr(LINKLENGTH,0,I,J)
                if (self.LineNum >= self.PAGESIZE):
                    self.write_link_info_header(True)
                if hasattr(conduit, "length"):
                    length = conduit.length
                else:
                    length = "#N/A"
                if hasattr(conduit, "diameter"):
                    diameter = conduit.diameter
                else:
                    diameter = "#N/A"
                S = '{:15}{:15}{:15}{:>10}{:>10}'.format(
                    conduit.id, conduit.inlet_node, conduit.outlet_node,
                    length, diameter)
                if conduits is self.project.pumps:
                    S += ' Pump'
                elif conduits is self.project.valves:
                    S += ' Valve'
                self.write_line(S)
        self.write_line('')

    def write_node_table(self, period):
        self.write_node_header(period, False)
        for nodes in (self.project.junctions, self.project.reservoirs,
                      self.project.tanks):
            for node in nodes.value:
                #         MainForm.UpdateProgressBar(Nprogress, ProgStep)
                node_index = self.output.get_NodeIndex(node.id)
                if node_index < 0:
                    line = '{:15} {}'.format(node.id, 'not found in output.')
                else:
                    demand = self.output.get_NodeValue(node_index, period,
                                                       ENR_demand)
                    head = self.output.get_NodeValue(node_index, period,
                                                     ENR_head)
                    pressure = self.output.get_NodeValue(
                        node_index, period, ENR_pressure)
                    quality = self.output.get_NodeValue(
                        node_index, period, ENR_quality)
                    line = '{:15} {:7.2f} {:7.2f} {:7.2f} {:7.2f}'.format(
                        node.id, demand, head, pressure, quality)
                if nodes is self.project.reservoirs:
                    line += ' Reservoir'
                elif nodes is self.project.tanks:
                    line += ' Tank'
                if (self.LineNum >= self.PAGESIZE):
                    self.write_node_header(period, True)
                self.write_line(line)
        self.write_line('')

    def write_link_table(self, period):
        self.write_link_header(period, False)
        for links in (self.project.pipes, self.project.pumps,
                      self.project.valves):
            for link in links.value:
                # MainForm.UpdateProgressBar(Nprogress, ProgStep)
                link_index = self.output.get_LinkIndex(link.id)
                if link_index < 0:
                    line = '{:15} {}'.format(link.id, 'not found in output.')
                else:
                    flow = self.output.get_LinkValue(link_index, period,
                                                     ENR_flow)
                    velocity = self.output.get_LinkValue(
                        link_index, period, ENR_velocity)
                    headloss = self.output.get_LinkValue(
                        link_index, period, ENR_headloss)
                    linkstat = "Unknown"  # TODO: self.output.get_LinkValue(link_index, T, ENR_
                    line = '{:15} {:9.2f} {:9.2f} {:9.2f} {:>10}'.format(
                        link.id, flow, velocity, headloss, linkstat)
                if links is self.project.pumps:
                    line += ' Pump'
                elif links is self.project.valves:
                    line += ' Valve'

                if (self.LineNum >= self.PAGESIZE):
                    self.write_link_header(period, True)
                self.write_line(line)
        self.write_line('')

    def write_results(self):
        for period in range(0, self.output.numPeriods):
            # Application.ProcessMessages
            self.write_node_table(period)
            # Application.ProcessMessages
            self.write_link_table(period)

    def write_report(self, report_file_name):
        #   MainForm.ShowProgressBar('Writing full report...')
        with open(report_file_name, 'w') as self.F:
            try:
                # Total = self.output.nodeCount + self.output.linkCount
                # Total *= self.output.numPeriods
                # Total += self.output.linkCount
                # with MainForm.ProgressBar do
                #   N = Max div Step
                # ProgStep = Round(Total/N)
                # Nprogress = 0
                self.write_logo()
                #     Application.ProcessMessages
                self.write_link_info()
                if self.output.pumpCount > 0:
                    self.write_energy()
                self.write_results()
                return True
            finally:
                print "Finished writing report " + report_file_name
                #   MainForm.HideProgressBar

    def all_link_ids(self):
        ids = []
        for links in (self.project.pipes, self.project.pumps,
                      self.project.valves):
            for link in links.value:
                if self.output.get_LinkIndex(link.id) > -1:
                    ids.append(link.id)
                else:
                    print("Skipping link " + link.id +
                          " because it was not found in output")
        return ids

    def all_link_types(self):
        types = []
        for link in self.project.pipes.value:
            if self.output.get_LinkIndex(link.id) > -1:
                types.append("Pipe")
        for link in self.project.pumps.value:
            if self.output.get_LinkIndex(link.id) > -1:
                types.append("Pump")
        for link in self.project.valves.value:
            if self.output.get_LinkIndex(link.id) > -1:
                types.append("Valve")
        return types

    def all_node_indexes(self):
        indexes = []
        for nodes in (self.project.junctions, self.project.reservoirs,
                      self.project.tanks):
            for node in nodes.value:
                node_index = self.output.get_NodeIndex(node.id)
                if node_index > -1:
                    indexes.append(node_index)
        return indexes

    def all_node_ids(self):
        ids = []
        for nodes in (self.project.junctions, self.project.reservoirs,
                      self.project.tanks):
            for node in nodes.value:
                node_index = self.output.get_NodeIndex(node.id)
                if node_index > -1:
                    ids.append(node.id)
                else:
                    print("Skipping node " + node.id +
                          " because it was not found in output")
        return ids

    def all_node_types(self):
        types = []
        for node in self.project.junctions.value:
            if self.output.get_NodeIndex(node.id) > -1:
                types.append("Junction")
        for node in self.project.reservoirs.value:
            if self.output.get_NodeIndex(node.id) > -1:
                types.append("Reservoir")
        for node in self.project.tanks.value:
            if self.output.get_NodeIndex(node.id) > -1:
                types.append("Tank")
        return types

    def node_distances(self, node_ids):
        return range(0, len(node_ids))
        # TODO: compute distance from node coordinates
        distances = [0]
        x = None
        y = None
        for node_id in node_ids:
            for nodes in (self.project.junctions, self.project.reservoirs,
                          self.project.tanks):
                for node in nodes.value:
                    if node.id == node_id:
                        if x and y:
                            distances.append(
                                sqrt((x - node.x) ^ 2 + (y - node.y) ^ 2))
        return distances
Example #12
0
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
Example #13
0
    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)
Example #14
0
    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)