Пример #1
0
class ReportOptions(Section):
    """Report Options"""

    SECTION_NAME = "[REPORT]"

    #     attribute, input_name
    metadata = Metadata(
        (("status", "Status"), ("summary", "Summary"), ("pagesize", "Page"),
         ("energy", "Energy"), ("file", "File")))

    metadata_lists = Metadata(
        (("nodes", "Nodes"), ("links", "Links"), ("elevation", "Elevation"),
         ("demand", "Demand"), ("head", "Head"), ("pressure", "Pressure"),
         ("quality", "Quality"), ("length", "Length"),
         ("diameter", "Diameter"), ("flow", "Flow"), ("velocity", "Velocity"),
         ("headloss", "Headloss"), ("position", "Position"),
         ("setting", "Setting"), ("reaction", "Reaction"), ("friction_factor",
                                                            "F-Factor")))
    """Mapping between attribute name and name used in input file"""
    def __init__(self):
        Section.__init__(self)

        ## sets the number of lines written per page of the output report
        self.pagesize = ''

        ## supplies the name of a file to which the output report will be written;
        ## don't write by default"""
        self.file = ''  # string

        ## determines whether a hydraulic status report should be generated
        self.status = StatusWrite.NO  # YES/NO/FULL

        ## determines whether a summary table of number of network components and key analysis options is generated
        self.summary = True  # YES/NO

        ## determines if a table reporting average energy usage and cost for each pump is provided;
        ## don't write by default"""
        self.energy = False  # YES/NO

        ## identifies which nodes will be reported on. List individual IDs or use NONE or ALL
        self.nodes = []

        ## identifies which links will be reported on. List individual IDs or use NONE or ALL
        self.links = []

        ## used to identify which quantities are reported on;
        ## don't write if blank
        self.parameters = []  # list of strings

    @property
    def page(self):
        """Alias for pagesize"""
        return self.pagesize

    @page.setter
    def page(self, new_value):
        """Alias for pagesize"""
        self.pagesize = new_value
Пример #2
0
class EnergyOptions(Section):
    """Defines global parameters used to compute pumping energy and cost"""

    SECTION_NAME = "[ENERGY]"

    #    attribute,            input_name, label, default, english, metric, hint
    metadata = Metadata((
        ("global_efficiency", "Global Efficiency"),
        ("global_price", "Global Price"),
        ("global_pattern", "Global Pattern"),
        ("demand_charge", "Demand Charge")))
    """Mapping between attribute name and name used in input file"""

    def __init__(self):
        Section.__init__(self)

        self.global_efficiency = "75"		# treat as string to preserve formatting
        """global default value of pumping efficiency for all pumps or efficiency curve name (percent)"""

        self.global_price = "0.0"		    # str
        """global default value of energy price for all pumps"""

        self.global_pattern = ''            # str
        """id of global default value of price pattern for all pumps"""

        self.demand_charge = "0.0"		    # str
        """added cost per maximum kW usage during the simulation period"""

        self.pumps = []
Пример #3
0
class Landuse(Section):
    """Identifies the various categories of land uses within the drainage area. Each subcatchment area
        can be assigned a different mix of land uses. Each land use can be subjected to a different
        street sweeping schedule."""

    #    attribute,              input_name, label,                     default, english, metric, hint
    metadata = Metadata(((
        "name", '', "Land Use Name", '', '', '',
        "User-assigned name of the land use."
    ), (
        "street_sweeping_interval", '', "Street Sweeping Interval", '', "days",
        "days",
        "Time between street sweeping within the land use (0 for no sweeping)."
    ), (
        "street_sweeping_availability", '', "Street Sweeping Availability", '',
        '', '',
        "Fraction of pollutant buildup that is available for removal by sweeping."
    ), ("last_swept", '', "Last Swept", '', "days", "days",
        "Time since land use was last swept at the start of the simulation.")))

    def __init__(self):
        Section.__init__(self)

        ## Name assigned to the land use
        self.name = "Unnamed"

        ## Days between street sweeping within the land use
        self.street_sweeping_interval = ''

        ## Fraction of the buildup of all pollutants that is available for removal by sweeping
        self.street_sweeping_availability = ''

        ## Number of days since last swept at the start of the simulation
        self.last_swept = ''
Пример #4
0
class Events(Section):
    """Events"""

    SECTION_NAME = "[EVENTS]"

    # DEFAULT_COMMENT = ";;Start Date         End Date"

    #    attribute,            input_name, label, default, english, metric, hint
    metadata = Metadata(
        (("start_date", "START DATE"), ("start_time", "START TIME"),
         ("end_date", "END DATE"), ("end_time", "END Time")))

    def __init__(self):
        Section.__init__(self)

        self.name = ""

        ## start date
        self.start_date = "01/01/1900"

        ## start time
        self.start_time = "00:00"

        ## end date
        self.end_date = "12/31/2000"

        ## end time
        self.end_time = "23:00"
Пример #5
0
class CurveNumberInfiltration(Section):
    """Curve Number Infiltration parameters"""

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata(
        (("subcatchment", '', "Subcatchment Name", "", '', '',
          "User-assigned name of subcatchment"), ("curve_number", '',
                                                  "Curve Number", "", '', '',
                                                  "SCS runoff curve number"),
         ("hydraulic_conductivity", '', "Conductivity", "", '', '',
          "This property has been deprecated and its value is ignored."),
         ("dry_days", '', "Drying Time", "", '', '',
          "Time for a fully saturated soil to completely dry (days)")))

    def __init__(self):
        Section.__init__(self)

        self.subcatchment = ''
        """Subcatchment name"""

        self.curve_number = None
        """SCS Curve Number"""

        self.hydraulic_conductivity = ''
        """Soil saturated hydraulic conductivity (no longer used for curve number infiltration)."""

        self.dry_days = ''
        """Time it takes for fully saturated soil to dry (days)."""
Пример #6
0
class Reservoir(Node):
    """Reservoir properties"""

    #    attribute, input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name", '', "Name", '', '', '', "User-assigned name of reservior"),
        ('x', '', "X-Coordinate", '', '', '',
         "X coordinate of reservior on study area map"),
        ('y', '', "Y-Coordinate", '', '', '',
         "Y coordinate of reservior on study area map"),
        ('', '', "Description", '', '', '', "Optional comment or description"),
        ('tag', '', "Tag", '', '', '', "Optional category or classification"),
        ('total_head', '', "Total Head", '0.0', '', '',
         "Hydraulic head (elevation + pressure head) of water in the reservoir"
         ),
        ('head_pattern_name', '', 'Head Pattern', '', '', '',
         "Head pattern ID, can be used to make the reservoir head vary with time"
         ),
        ('initial_quality', '', 'Initial Quality', '', '', '',
         "Water quality level at the reservior at the start of the simulation period"
         ),
        ('source_quality', '', 'Source Quality', '', '', '',
         "Quality of any water entering the network at this location, click to edit"
         )))

    def __init__(self):
        Node.__init__(self)

        self.total_head = "0.0"
        """Head is the hydraulic head (elevation + pressure head) of water in the reservoir"""

        self.head_pattern_name = ''
        """head pattern can be used to make the reservoir head vary with time"""
Пример #7
0
class Label(Section, Coordinate):
    """Assigns coordinates to map labels"""

    #    attribute,     input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name",                '', "Text",            '',       '', '',  "Text of the label"),
        ('x',                   '', "X-Coordinate",    '',       '', '',  "X coordinate of upper left corner of the label on the map"),
        ('y',                   '', "Y-Coordinate",    '',       '', '',  "Y coordinate of upper left corner of the label on the map"),
        ("anchor_name",         '', "Anchor Node",     "",       '', '',  "Name of a node or subcatchment to which the label is anchored when map is zoomed (optional)"),
        ("font",                '', "Font",            "",       '', '',  "The label's font"),
        ("size",                '', "Size",            "10.0",   '', '',  "The label's font size"),
        ("bold",                '', "Bold",            "False",  '', '',  "Set to True if the label is to be bold"),
        ("italics",             '', "Italics",         "False",  '', '',  "Set to True if the label is to be italicized"),
    ))

    def __init__(self):
        Section.__init__(self)
        Coordinate.__init__(self)

        """Text of label is saved in name attribute defined in Coordinate base class."""

        self.anchor_name = ""			# string
        """ID label of an anchor node (optional)"""

        self.font = ""
        """label font"""

        self.size = 10.0
        """label size"""

        self.bold = False
        """label bold"""

        self.italic = False
        """lable italics"""
Пример #8
0
class GreenAmptInfiltration(Section):
    """Green-Ampt Infiltration parameters"""

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("subcatchment", '', "Subcatchment Name", "", '', '',
         "User-assigned name of subcatchment"),
        ("suction", '', "Suction Head", "", '', '',
         "Soil capillary suction head (in or mm)"),
        ("hydraulic_conductivity", '', "Conductivity", "", '', '',
         "Soil saturated hydraulic conductivity (in/hr or mm/hr)"),
        ("initial_moisture_deficit", '', "Initial Deficit", "", '', '',
         "Difference between soil porosity and initial moisture content (a fraction)"
         )))

    def __init__(self):
        Section.__init__(self)

        self.subcatchment = ''
        """Subcatchment name"""

        self.suction = ''
        """Soil capillary suction (in or mm)."""

        self.hydraulic_conductivity = ''
        """Soil saturated hydraulic conductivity (in/hr or mm/hr)."""

        self.initial_moisture_deficit = ''
        """Initial soil moisture deficit (volume of voids / total volume)."""
Пример #9
0
class Junction(Node):
    """A Junction node"""

    #    attribute, input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name", '', "Name", '', '', '', "User-assigned name of junction"),
        ('x', '', "X-Coordinate", '', '', '',
         "X coordinate of junction on study area map"),
        ('y', '', "Y-Coordinate", '', '', '',
         "Y coordinate of junction on study area map"),
        ('description', '', "Description", '', '', '',
         "Optional comment or description"),
        ('tag', '', "Tag", '', '', '', "Optional category or classification"),
        ('', '', "Inflows", 'NO', '', '',
         "Click to specify any external inflows received at the junction"),
        ('.treatment(node_name)', '', "Treatment", 'NO', '', '',
         "Click to specify any pollutant removal supplied at the junction"),
        ("elevation", '', "Invert El.", '0', "(ft)", "(m)",
         "Elevation of junction's invert"),
        ("max_depth", '', "Max. Depth", '0', "(ft)", "(m)",
         "Maximum water depth (i.e. distance from invert to ground surface or 0 to use distance "
         "from invert to top of highest connecting link)"),
        ("initial_depth", '', "Initial Depth", '0', "(ft)", "(m)",
         "Initial water depth in junction"),
        ("surcharge_depth", '', "Surcharge Depth", '0', "(ft)", "(m)",
         "Depth in excess of maximum depth before flooding occurs"),
        ("ponded_area", '', "Ponded Area", '0', "(ft2)", "(m2)",
         "Area of ponded water when flooded")))

    def __init__(self):
        Node.__init__(self)

        # self.name = ''  # Unicode(default_value='', label="Name", help="User-assigned name of junction")
        # """name assigned to junction node"""

        ## Invert elevation of the Node (feet or meters)
        self.elevation = 0.0

        ## Maximum depth of junction (i.e., from ground surface to invert)
        ## feet or meters). If zero, then the distance from the invert to
        ## the top of the highest connecting link will be used.  (Ymax)
        self.max_depth = 0.0

        ## Depth of water at the junction at the start of the simulation
        ## (feet or meters) (Y0)
        self.initial_depth = 0.0

        ## Additional depth of water beyond the maximum depth that is
        ##  allowed before the junction floods (feet or meters).
        ## This parameter can be used to simulate bolted manhole covers
        ## or force main connections. (Ysur)
        self.surcharge_depth = 0.0

        ## Area occupied by ponded water atop the junction after flooding
        ## occurs (sq. feet or sq. meters). If the Allow Ponding simulation
        ## option is turned on, a non-zero value of this parameter will allow
        ## ponded water to be stored and subsequently returned to the
        ## conveyance system when capacity exists. (Apond)
        self.ponded_area = 0.0
class GreenAmptInfiltration(Section):
    """Green-Ampt Infiltration parameters"""

    field_format = "{:16}\t{:10}\t{:10}\t{:10}"

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("subcatchment", '', "Subcatchment Name", "", '', '',
         "User-assigned name of subcatchment"),
        ("suction", '', "Suction Head", "", '', '',
         "Soil capillary suction head (in or mm)"),
        ("hydraulic_conductivity", '', "Conductivity", "", '', '',
         "Soil saturated hydraulic conductivity (in/hr or mm/hr)"),
        ("initial_moisture_deficit", '', "Initial Deficit", "", '', '',
         "Difference between soil porosity and initial moisture content (a fraction)"
         )))

    def __init__(self, new_text=None):
        if new_text:
            self.set_text(
                new_text
            )  # set_text will call __init__ without new_text to do the initialization below
        else:
            Section.__init__(self)

            self.subcatchment = ''
            """Subcatchment name"""

            self.suction = ''
            """Soil capillary suction (in or mm)."""

            self.hydraulic_conductivity = ''
            """Soil saturated hydraulic conductivity (in/hr or mm/hr)."""

            self.initial_moisture_deficit = ''
            """Initial soil moisture deficit (volume of voids / total volume)."""

    def get_text(self):
        inp = ''
        if self.comment:
            inp = self.comment + '\n'
        inp += self.field_format.format(self.subcatchment, self.suction,
                                        self.hydraulic_conductivity,
                                        self.initial_moisture_deficit)
        return inp

    def set_text(self, new_text):
        self.__init__()
        new_text = self.set_comment_check_section(new_text)
        fields = new_text.split()
        if len(fields) > 0:
            self.subcatchment = fields[0]
        if len(fields) > 1:
            self.suction = fields[1]
        if len(fields) > 2:
            self.hydraulic_conductivity = fields[2]
        if len(fields) > 3:
            self.initial_moisture_deficit = fields[3]
Пример #11
0
class Landuse(Section):
    """Identifies the various categories of land uses within the drainage area. Each subcatchment area
        can be assigned a different mix of land uses. Each land use can be subjected to a different
        street sweeping schedule."""

    field_format = " {:15}\t{:10}\t{:10}\t{:10}\n"

    #    attribute,              input_name, label,                     default, english, metric, hint
    metadata = Metadata((
        ("land_use_name",                '', "Land Use Name",                '', '', '',
         "User-assigned name of the land use."),
        ("street_sweeping_interval",     '', "Street Sweeping Interval",     '', "days", "days",
         "Time between street sweeping within the land use (0 for no sweeping)."),
        ("street_sweeping_availability", '', "Street Sweeping Availability", '', '', '',
         "Fraction of pollutant buildup that is available for removal by sweeping."),
        ("last_swept",                   '', "Last Swept",                   '', "days", "days",
         "Time since land use was last swept at the start of the simulation.")
    ))

    def __init__(self, new_text=None):
        Section.__init__(self)
        self.land_use_name = ""
        """Name assigned to the land use"""

        self.street_sweeping_interval = ''
        """Days between street sweeping within the land use"""

        self.street_sweeping_availability = ''
        """Fraction of the buildup of all pollutants that is available for removal by sweeping"""

        self.last_swept = ''
        """Number of days since last swept at the start of the simulation"""

        if new_text:
            self.set_text(new_text)

    def get_text(self):
        inp = ''
        if self.comment:
            inp = self.comment + '\n'
        inp += Landuse.field_format.format(self.land_use_name,
                                           self.street_sweeping_interval,
                                           self.street_sweeping_availability,
                                           self.last_swept)
        return inp

    def set_text(self, new_text):
        self.__init__()
        fields = new_text.split()
        if len(fields) > 0:
            self.land_use_name = fields[0]
        if len(fields) > 1:
            self.street_sweeping_interval = fields[1]
        if len(fields) > 2:
            self.street_sweeping_availability =  fields[2]
        if len(fields) > 3:
            self.last_swept = fields[3]
class CurveNumberInfiltration(Section):
    """Curve Number Infiltration parameters"""

    field_format = "{:16}\t{:10}\t{:10}\t{:10}"

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata(
        (("subcatchment", '', "Subcatchment Name", "", '', '',
          "User-assigned name of subcatchment"), ("curve_number", '',
                                                  "Curve Number", "", '', '',
                                                  "SCS runoff curve number"),
         ("hydraulic_conductivity", '', "Conductivity", "", '', '',
          "This property has been deprecated and its value is ignored."),
         ("dry_days", '', "Drying Time", "", '', '',
          "Time for a fully saturated soil to completely dry (days)")))

    def __init__(self, new_text=None):
        if new_text:
            self.set_text(
                new_text
            )  # set_text will call __init__ without new_text to do the initialization below
        else:
            Section.__init__(self)

            self.subcatchment = ''
            """Subcatchment name"""

            self.curve_number = None
            """SCS Curve Number"""

            self.hydraulic_conductivity = ''
            """Soil saturated hydraulic conductivity (no longer used for curve number infiltration)."""

            self.dry_days = ''
            """Time it takes for fully saturated soil to dry (days)."""

    def get_text(self):
        inp = ''
        if self.comment:
            inp = self.comment + '\n'
        inp += self.field_format.format(self.subcatchment, self.curve_number,
                                        self.hydraulic_conductivity,
                                        self.dry_days)
        return inp

    def set_text(self, new_text):
        self.__init__()
        new_text = self.set_comment_check_section(new_text)
        fields = new_text.split()
        if len(fields) > 0:
            self.subcatchment = fields[0]
        if len(fields) > 1:
            self.curve_number = fields[1]
        if len(fields) > 2:
            self.hydraulic_conductivity = fields[2]
        if len(fields) > 3:
            self.dry_days = fields[3]
Пример #13
0
class Outfall(Junction):
    """A terminal node of the drainage system
        Defines a final downstream boundary under Dynamic Wave flow routing.
        For other types of flow routing they behave as a junction.
        Only a single link can be connected to an outfall node.
        The boundary conditions at an outfall can be described by any one
        of the following stage relationships:
            the critical or normal flow depth in the connecting conduit
            a fixed stage elevation
            a tidal stage described in a table of tide height versus hour
            a user-defined time series of stage versus time.
        The principal input parameters for outfalls include:
            invert elevation
            boundary condition type and stage description
            presence of a flap gate to prevent backflow through the outfall.
    """

    #    attribute, input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name",                '', "Name",            '',   '',   '',  "User-assigned name of outfall"),
        ('x',                   '', "X-Coordinate",    '',   '',   '',  "X coordinate of outfall on study area map"),
        ('y',                   '', "Y-Coordinate",    '',   '',   '',  "Y coordinate of outfall on study area map"),
       #('',                    '', "Description",     '',   '',   '',  "Optional comment or description"),
        ('tag',                 '', "Tag",             '',   '',   '',  "Optional category or classification"),
        ('',                    '', "Inflows",         'NO', '',   '',  "Click to specify any external inflows received at the outfall"),
        ('.treatment(name)',    '', "Treatment",       'NO', '',   '',  "Click to specify any pollutant removal supplied at the outfall"),
        ("elevation",           '', "Invert El.",      '0',  "ft", "m", "Elevation of outfall's invert"),
        ("tide_gate",           '', "Tide Gate",       '0',  '',   '',  "True if outfall contains a tide gate to prevent backflow"),
        ("route_to",            '', "Route To",        '0',  '',   '',  "Subcatchment outfall is routed onto (blank if not applicable)"),
        ("outfall_type",        '', "Type",            '0',  '',   '',  "Type of outfall boundary condition"),
        ("fixed_stage",         '', "Fixed Stage",     '0',  '',   '',  "Water elevation for a FIXED boundary condition"),
        ("tidal_curve",         '', "Curve Name",      '0',  '',   '',  "Name of tidal curve used for a TIDAL boundary condition"),
        ("time_series_name",    '', "Series Name",     '0',  '',   '',  "Name of time series for a TIMESERIES boundary condition")))

    def __init__(self):
        Junction.__init__(self)

        self.tide_gate = False
        """Tide Gate is present to prevent backflow"""

        self.outfall_type = OutfallType.FREE
        """Type of outfall boundary condition"""

        self.fixed_stage = 0.0
        """Water elevation for a FIXED type of outfall (feet or meters)."""

        self.tidal_curve = "None"
        """The TidalCurve relating water elevation to hour of the
            day for a TIDAL outfall."""

        self.time_series_name = "None"
        """Name of time series containing time history of outfall elevations
            for a TIMESERIES outfall"""

        self.route_to = ''
        """Optional name of a subcatchment that receives the outfall's discharge"""
Пример #14
0
class Tank(Node):
    """Tank properties"""

    #    attribute, input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name",            '', "Name",            '',    '',   '', "User-assigned name of tank"),
        ('x',               '', "X-Coordinate",    '',    '',   '', "X coordinate of tank on study area map"),
        ('y',               '', "Y-Coordinate",    '',    '',   '', "Y coordinate of tank on study area map"),
        ('',                '', "Description",     '',    '',   '', "Optional comment or description"),
        ('tag',             '', "Tag",             '',    '',   '', "Optional category or classification"),
        ('elevation',       '', "Elevation",       '0.0', '',   '', "Elevation of tank"),
        ('initial_level',   '', "Initial Level",   '0.0', '',   '', "Height of the water surface above the bottom elevation of the tank at the start of the simulation."),
        ('minimum_level',   '', "Minimum Level",   '0.0', '',   '', "Minimum height in feet (meters) of the water surface above the bottom elevation that will be maintained."),
        ('maximum_level',   '', "Maximum Level",   '0.0', '',   '', "Maximum height in feet (meters) of the water surface above the bottom elevation that will be maintained."),
        ('diameter',        '', "Diameter",        '0.0', '',   '', "The diameter of the tank"),
        ('minimum_volume',  '', "Minimum Volume",  '0.0', '',   '', "The volume of water in the tank when it is at its minimum level"),
        ('volume_curve',    '', "Volume Curve",    '',    '',   '', "The ID label of a curve used to describe the relation between tank volume and water level"),
        ('mixing_model',    '', "Mixing Model",    '',    '',   '', "The type of water quality mixing that occurs within the tank"),
        ('mixing_fraction', '', "Mixing Fraction", '0.0', '',   '', "The fraction of the tank's total volume that comprises the inlet-outlet compartment of the two-compartment (2COMP) mixing model"),
        ('reaction_coeff',  '', "Reaction Coeff.", '',    '',   '', "Tank-specific reaction coefficient"),
        ('initial_quality', '', 'Initial Quality', '0.0', '',   '', "Water quality level in the tank at the start of the simulation period"),
        ('source_quality',  '', 'Source Quality',  '',    '',   '', "Quality of any water entering the network at this location, click to edit")))

    def __init__(self):
        Node.__init__(self)

        ## Bottom elevation, ft (m)
        self.elevation = "0.0"

        ## Initial water level, ft (m)
        self.initial_level = "0.0"

        ## Minimum water level, ft (m)
        self.minimum_level = "0.0"

        ## Maximum water level, ft (m)
        self.maximum_level = "0.0"

        ## Nominal diameter, ft (m)
        self.diameter = "0.0"

        ## Minimum volume, cubic ft (cubic meters)
        self.minimum_volume = "0.0"

        ## If a volume curve is supplied the diameter value can be any non-zero number
        self.volume_curve = ''

        ## Mixing models include:
        ## Completely Mixed (MIXED);
        ## Two-Compartment Mixing (2COMP);
        ## Plug Flow (FIFO);
        ## Stacked Plug Flow (LIFO);
        self.mixing_model = MixingModel.MIXED

        ## fraction of the total tank volume devoted to the inlet/outlet compartment
        self.mixing_fraction = "0.0"
class GreenAmptInfiltration(Section):
    """Green-Ampt Infiltration parameters"""

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("subcatchment", '', "Subcatchment Name", "", '', '',
         "User-assigned name of subcatchment"),
        ("suction", '', "Suction Head", "", '', '',
         "Soil capillary suction head (in or mm)"),
        ("hydraulic_conductivity", '', "Conductivity", "", '', '',
         "Soil saturated hydraulic conductivity (in/hr or mm/hr)"),
        ("initial_moisture_deficit", '', "Initial Deficit", "", '', '',
         "Difference between soil porosity and initial moisture content (a fraction)"
         )))

    def __init__(self):
        Section.__init__(self)

        ## Subcatchment name
        self.subcatchment = "None"

        ## Soil capillary suction (in or mm).
        self.suction = '0.0'

        ## Soil saturated hydraulic conductivity (in/hr or mm/hr).
        self.hydraulic_conductivity = '0.0'

        ## Initial soil moisture deficit (volume of voids / total volume).
        self.initial_moisture_deficit = '0.0'

    def model_type(self):
        if str(self.suction) != str(GreenAmptInfiltration.default_suction()) or \
           str(self.hydraulic_conductivity) != str(GreenAmptInfiltration.default_conductivity()) or \
           str(self.initial_moisture_deficit) != str(GreenAmptInfiltration.default_init_deficit()):
            return E_InfilModel.MODIFIED_GREEN_AMPT
        else:
            return E_InfilModel.GREEN_AMPT

    def set_defaults(self):
        self.suction = str(GreenAmptInfiltration.default_suction())
        self.hydraulic_conductivity = str(
            GreenAmptInfiltration.default_conductivity())
        self.initial_moisture_deficit = str(
            GreenAmptInfiltration.default_init_deficit())

    @staticmethod
    def default_suction():
        return 3.5

    @staticmethod
    def default_conductivity():
        return 0.5

    @staticmethod
    def default_init_deficit():
        return 0.25
Пример #16
0
class RainGage(Section, Coordinate):
    """A rain gage, including reference to location and time-series data"""

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name",                    '', "Name",                  "",       '', '', "User-assigned name of rain gage"),
        ("x",                       '', "X-Coordinate",          "",       '', '', "X coordinate of rain gage on study area map"),
        ("y",                       '', "Y-Coordinate",          "",       '', '', "Y coordinate of rain gage on study area map"),
        ("description",             '', "Description",           "",       '', '', "Optional comment or description"),
        ("tag",                     '', "Tag",                   "",       '', '', "Optional category or classification"),
        ("rain_format",             '', "Rain Format",           "",       '', '', "Type of rainfall data recorded at rain gage"),
        ("rain_interval",           '', "Time Interval",         "1:00",   '', '', "Data recording time intervsl at rain gage"),
        ("snow_catch_factor",       '', "Snow Catch Factor",     "1",      '', '', "Correction factor applied to snowfall"),
        ("data_source",             '', "Data Source",           "",       '', '', "Source of rainfall data"),
        ("timeseries",              '', "Time Series Name",      "",       '', '', "Name of rainfall time series"),
        ("data_file_name",          '', "Data File Name",        "",       '', '', "Name of rainfall data file"),
        ("data_file_station_id",    '', "Data File Station ID",  "",       '', '', "Station ID contained in data file"),
        ("data_file_rain_units",    '', "Data file Rain Units",  "",       '', '', "Units of rainfall data")
    ))

    def __init__(self):
        Section.__init__(self)
        Coordinate.__init__(self)

        ## Optional description of the gage
        self.description = ''

        ## Optional label used to categorize the gage
        self.tag = ''

        ## Format in which the rain data are supplied:
        ## INTENSITY, VOLUME, CUMULATIVE (see also self.rain_units)
        self.rain_format = RainFormat.VOLUME

        ## Recording time interval between gage readings in either decimal
        ## hours or hours:minutes format.
        self.rain_interval = "1:00"

        ## Factor that corrects gage readings for snowfall
        self.snow_catch_factor = 1.0

        ## Source of rainfall data; This can be set to a
        ## TimeSeries or a TimeSeriesFile.
        self.data_source = RainDataSource.TIMESERIES

        ## name of time series with rainfall data if Data Source selection was TIMESERIES
        self.timeseries = "None"

        ## Name of external file containing rainfall data
        self.data_file_name = "None"

        ## Recording gage station number
        self.data_file_station_id = "StationID"

        ## Depth units (IN or MM) for rainfall values in the file
        self.data_file_rain_units = RainFileUnits.IN
Пример #17
0
class Report(Section):
    """Report Options"""

    SECTION_NAME = "[REPORT]"

    DEFAULT_COMMENT = ";;Reporting Options"

    #    attribute,            input_name, label, default, english, metric, hint
    metadata = Metadata((
        ("input", "INPUT"),
        ("continuity", "CONTINUITY"),
        ("flow_stats", "FLOWSTATS"),
        ("averages", "AVERAGES"),
        ("controls", "CONTROLS"),
        ("subcatchments", "SUBCATCHMENTS"),
        ("nodes", "NODES"),
        ("links", "LINKS"),
        ("lids", "LID")))
    """Mapping between attribute name and name used in input file"""

    LISTS = ("subcatchments", "nodes", "links", "lids")

    EMPTY_LIST = ["NONE"]
    ALL_LIST = ["ALL"]

    def __init__(self):
        Section.__init__(self)

        ## Whether report includes a summary of the input data
        self.input = False

        ## Whether to report continuity checks
        self.continuity = True

        ## Whether to report summary flow statistics
        self.flow_stats = True

        ## Average instead of instantaneous valeus
        self.averages = False

        ## Whether to list all control actions taken during a simulation
        self.controls = False

        ## List of subcatchments whose results are to be reported, or ALL or NONE
        self.subcatchments = Report.ALL_LIST

        ## List of nodes whose results are to be reported, or ALL or NONE
        self.nodes = Report.ALL_LIST

        ## List of links whose results are to be reported, or ALL or NONE
        self.links = Report.ALL_LIST

        ## List of lid specifications whose results are to be reported.
        ## Includes LID control name, subcatchment id and file name.
        self.lids = []
Пример #18
0
 def metadata(self, metadata):
     typeChecker(type(self).__name__, metadata, list, "metadata")
     self.__metadata = []
     for entry in metadata:
         try:
             loadChecker(type(self).__name__, entry, ['name', 'value'], "metadata")
             self.__metadata.append(Metadata(entry['name'], entry['value']))
         except MissingParameters as e:
             handler(type(self).__name__, 'Metadata {} is missing parameters: '
                                      '{}. Skipping.'
                 .format(entry, e))
Пример #19
0
 def metadata(self, metadata):
     typeChecker(type(self).__name__, metadata, list, "metadata")
     self.__metadata = []
     entry = ""
     try:
         for entry in metadata:
             self.__metadata.append(Metadata(entry['name'], entry['value']))
     except KeyError as e:
         handler(
             type(self).__name__, 'Metadata {} is missing parameters: '
             '{}. Unable to load.'.format(entry, e))
Пример #20
0
class TimeSteps(Section):
    """SWMM Time Step Options"""

    SECTION_NAME = "[OPTIONS]"

    #    attribute,                  input_name, label, default, english, metric, hint
    metadata = Metadata(
        (("skip_steady_state", "SKIP_STEADY_STATE"),
         ("report_step", "REPORT_STEP"), ("wet_step", "WET_STEP"),
         ("dry_step", "DRY_STEP"), ("routing_step", "ROUTING_STEP"),
         ("system_flow_tolerance", "SYS_FLOW_TOL", '', '5', '%', '%'),
         ("lateral_inflow_tolerance", "LAT_FLOW_TOL", '', '5', '%', '%')))
    """Mapping between attribute name and name used in input file"""

    TIME_FORMAT = "hh:mm:ss"

    def __init__(self):
        Section.__init__(self)

        self.skip_steady_state = False
        """bool: True to skip flow routing computations during steady state periods
            of a simulation. The last set of computed flows will be used.
        """

        self.report_step = "00:15:00"
        """str: Time interval for reporting of computed results."""

        self.wet_step = "00:05:00"
        """str: Time step length used to compute runoff from subcatchments during
        periods of rainfall or when ponded water remains on the surface.
        """

        self.dry_step = "01:00:00"
        """str: Time step length used for runoff computations
        (consisting essentially of pollutant buildup) 
        during periods when there is no rainfall and no ponded water.
        """

        self.routing_step = "00:05:00"
        """str: Time step used for routing flows and
        water quality constituents through the conveyance system
        """

        self.system_flow_tolerance = "5"
        """the maximum percent difference between total system inflow and
        total system outflow which can occur in order for the SKIP_STEADY_STATE
        option to take effect. The default is 5 percent.
        """

        self.lateral_inflow_tolerance = "5"
        """the maximum percent difference between the current and previous
Пример #21
0
class Dates(Section):
    """SWMM Date Options"""

    SECTION_NAME = "[OPTIONS]"

    #    attribute,           input_name, label, default, english, metric, hint
    metadata = Metadata((
        ("start_date",        "START_DATE"),
        ("start_time",        "START_TIME"),
        ("report_start_date", "REPORT_START_DATE"),
        ("report_start_time", "REPORT_START_TIME"),
        ("end_date",          "END_DATE"),
        ("end_time",          "END_TIME"),
        ("sweep_start",       "SWEEP_START"),
        ("sweep_end",         "SWEEP_END"),
        ("dry_days",          "DRY_DAYS")))
    """Mapping between attribute name and name used in input file"""

    DATE_FORMAT = "MM/dd/yyyy"
    DATE_SWEEP_FORMAT = "MM/dd"
    TIME_FORMAT = "hh:mm:ss"

    def __init__(self):
        Section.__init__(self)

        self.start_date = "1/1/2002"
        """Date when the simulation begins"""

        self.start_time = "0:00"
        """Time of day on the starting date when the simulation begins"""

        self.end_date = "1/1/2002"
        """Date when the simulation is to end"""

        self.end_time = "24:00"
        """Time of day on the ending date when the simulation will end"""

        self.report_start_date = "1/1/2002"
        """Date when reporting of results is to begin"""

        self.report_start_time = "0:00"
        """Time of day on the report starting date when reporting is to begin"""

        self.sweep_start = "1/1"
        """Day of the year (month/day) when street sweeping operations begin"""

        self.sweep_end = "12/31"
        """Day of the year (month/day) when street sweeping operations end"""

        self.dry_days = 0.0
        """Number of days with no rainfall prior to the start of the simulation"""
Пример #22
0
class TimesOptions(Section):
    """Defines various time step parameters used in the simulation"""

    SECTION_NAME = "[TIMES]"

    #    attribute,            input_name, label, default, english, metric, hint
    metadata = Metadata((
        ("duration", "Duration"),
        ("hydraulic_timestep", "Hydraulic Timestep"),
        ("quality_timestep", "Quality Timestep"),
        ("rule_timestep", "Rule Timestep"),
        ("pattern_timestep", "Pattern Timestep"),
        ("pattern_start", "Pattern Start"),
        ("report_timestep", "Report Timestep"),
        ("report_start", "Report Start"),
        ("start_clocktime", "Start ClockTime"),
        ("statistic", "Statistic")))
    """Mapping between attribute name and name used in input file"""

    def __init__(self):
        Section.__init__(self)

        self.duration = "0"			            # hours:minutes
        """duration of the simulation; the default of zero runs a single period snapshot analysis."""

        self.hydraulic_timestep = "1:00"	    # hours:minutes
        """determines how often a new hydraulic state of the network is computed"""

        self.quality_timestep = "0:05"		    # hours:minutes
        """time step used to track changes in water quality throughout the network"""

        self.rule_timestep = "0:05" 		    # hours:minutes
        """ime step used to check for changes in system status due to activation of rule-based controls"""

        self.pattern_timestep = "1:00" 		    # hours:minutes
        """interval between time periods in all time patterns"""

        self.pattern_start = "0:00"	            # hours:minutes
        """time offset at which all patterns will start"""

        self.report_timestep = "1:00"		    # hours:minutes
        """time interval between which output results are reported"""

        self.report_start = "0:00"	            # hours:minutes
        """length of time into the simulation at which output results begin to be reported"""

        self.start_clocktime = "12 am"		    # hours:minutes AM/PM
        """time of day (e.g., 3:00 PM) at which the simulation begins"""

        self.statistic = StatisticOptions.NONE  # NONE/AVERAGED/MINIMUM/MAXIMUM/RANGE
        """determines what kind of statistical post-processing to do on simulation results"""
Пример #23
0
class EnergyOptions(Section):
    """Defines global parameters used to compute pumping energy and cost"""

    SECTION_NAME = "[ENERGY]"

    #    attribute,            input_name, label, default, english, metric, hint
    metadata = Metadata((("global_efficiency", "Global Efficiency"),
                         ("global_price", "Global Price"), ("global_pattern",
                                                            "Global Pattern"),
                         ("demand_charge", "Demand Charge")))
    """Mapping between attribute name and name used in input file"""
    def __init__(self):
        Section.__init__(self)

        self.global_efficiency = "75"  # treat as string to preserve formatting
        """global default value of pumping efficiency for all pumps or efficiency curve ID (percent)"""

        self.global_price = "0.0"  # str
        """global default value of energy price for all pumps"""

        self.global_pattern = ''  # str
        """id of global default value of price pattern for all pumps"""

        self.demand_charge = "0.0"  # str
        """added cost per maximum kW usage during the simulation period"""

        self.pumps = []

    def get_text(self):
        if self.global_efficiency == "75" \
           and self.global_price == "0.0" \
           and self.global_pattern == '' \
           and self.demand_charge == "0.0" \
           and len(self.pumps) == 0:
            return ''  # This section has nothing different from defaults, return blank
        else:
            txt = []
            txt.append(Section.get_text(
                self))  # Get text for the global variables using metadata
            for pump_energy in self.pumps:  # Add text for each pump energy
                txt.append(pump_energy.get_text())
            return '\n'.join(txt)

    def set_text(self, new_text):
        Section.set_text(
            self,
            new_text)  # Initialize, and set the global values using metadata
        for line in new_text.splitlines():  # Set pump-specific values
            first_field = new_text.split(None, 1)[0]
            if first_field.upper() == "PUMP":
                self.pumps.append(PumpEnergy(line))
class Junction(Node):
    """Junction properties"""

    #    attribute, input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name", '', "Name", '', '', '', "User-assigned name of junction"),
        ('x', '', "X-Coordinate", '', '', '',
         "X coordinate of junction on study area map"),
        ('y', '', "Y-Coordinate", '', '', '',
         "Y coordinate of junction on study area map"),
        ('description', '', "Description", '', '', '',
         "Optional comment or description"),
        ('tag', '', "Tag", '', '', '',
         "Optional category or classification"), ('elevation', '', "Elevation",
                                                  '0.0', '(ft)', '(m)',
                                                  "Elevation of junction"),
        ('base_demand_flow', '', 'Base Demand', '0.0', '', '',
         "Base demand flow, characteristic of all demands at this node"),
        ('demand_pattern_name', '', 'Demand Pattern', '', '', '',
         "Demand pattern ID, optional"),
        ('demand_categories', '', 'Demand Categories', '', '', '',
         "Number of demand categories, click to edit"),
        ('emitter_coefficient', '', 'Emitter Coeff.', '', '', '',
         "Emitters are used to model flow through sprinkler heads or pipe leaks. Flow out of the emitter equals the product of the flow coefficient and the junction pressure raised to EMITTER EXPONENT, which defaults to 0.5 and can be set in OPTIONS section."
         ),
        ('initial_quality', '', 'Initial Quality', '', '(mg/L)', '(mg/L)',
         "Water quality level at the junction at the start of the simulation period"
         ),
        ('source_quality', '', 'Source Quality', '', '', '',
         "Quality of any water entering the network at this location, click to edit"
         )))

    def __init__(self):
        Node.__init__(self)

        ## elevation of junction
        self.elevation = '0.0'

        ## Base demand flow, characteristic of all demands at this node
        self.base_demand_flow = '0.0'

        ## Demand pattern ID, optional
        self.demand_pattern_name = ''

        ## Demand pattern object, optional
        self.demand_pattern_object = None

        ## Emitters are used to model flow through sprinkler heads or pipe leaks. Flow out of the emitter equals
        ## the product of the flow coefficient and the junction pressure raised to EMITTER EXPONENT, which
        ## defaults to 0.5 and can be set in OPTIONS section.
        self.emitter_coefficient = ''
Пример #25
0
class Pipe(EpanetLink):
    """A Pipe link in an EPANET model"""

    #    attribute,           input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name", '', "Pipe ID", "", '', '', "User-assigned name of the pipe"),
        ("inlet_node", '', "Start Node", "", '', '',
         "Node on the inlet end of the pipe"),
        ("outlet_node", '', "End Node", "", '', '',
         "Node on the outlet end of the pipe"),
        ("description", '', "Description", "", '', '',
         "Optional description of the pipe"),
        ("tag", '', "Tag", "", '', '',
         "Optional label used to categorize or classify the pipe"),
        ("length", '', "Length", "0.0", '', '', "Pipe length"),
        ("diameter", '', "Diameter", "0.0", '', '', "Pipe diameter"),
        ("roughness", '', "Roughness", "0.0", '', '',
         "Manning's roughness coefficient"),
        ("loss_coefficient", '', "Loss Coeff.", "0.0", '', '',
         "Minor loss coefficient"),
        ("initial_status", '', "Initial Status", "", '', '',
         "Initial status of a pipe"),
        ("bulk_reaction_coefficient", '', "Bulk Coeff.", "0.0", '', '',
         "Bulk reaction coefficient for this pipe"),
        ("wall_reaction_coefficient", '', "Wall Coeff.", "0.0", '', '',
         "Wall reaction coefficient for this pipe"),
    ))

    def __init__(self):
        EpanetLink.__init__(self)

        self.length = "0.0"
        """pipe length"""

        self.diameter = "0.0"
        """pipe diameter"""

        self.roughness = "0.0"
        """Manning's roughness coefficient"""

        self.loss_coefficient = "0.0"
        """Minor loss coefficient"""

        # See REACTIONS section for this parameter; could add convenience function to find it
        # self.bulk_reaction_coefficient = "0.0"
        """bulk reaction coefficient for this pipe"""

        # See REACTIONS section for this parameter; could add convenience function to find it
        # self.wall_reaction_coefficient = "0.0"
        """wall reaction coefficient for this pipe"""
Пример #26
0
class Divider(Junction):
    """Flow Dividers are drainage system nodes that divert inflows to
        a specific conduit in a prescribed manner. A flow divider can
        have no more than two conduit links on its discharge side.
        Flow dividers are only active under Kinematic Wave routing
        and are treated as simple junctions under Dynamic Wave routing.
    """

    #    attribute, input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name",                '', "Name",            '',   '',   '',  "User-assigned name of divider"),
        ('x',                   '', "X-Coordinate",    '',   '',   '',  "X coordinate of divider on study area map"),
        ('y',                   '', "Y-Coordinate",    '',   '',   '',  "Y coordinate of divider on study area map"),
        ('',                    '', "Description",     '',   '',   '',  "Optional comment or description"),
        ('tag',                 '', "Tag",             '',   '',   '',  "Optional category or classification"),
        ('',                    '', "Inflows",         'NO', '',   '',  "Click to specify any external inflows received at the divider"),
        ('.treatment(node_name)', '', "Treatment",   'NO', '',   '',  "Click to specify any pollutant removal supplied at the divider"),
        ("elevation",           '', "Invert El.",      '0',  "ft", "m", "Elevation of divider's invert"),
        ("max_depth",           '', "Max Depth",       '0',  'ft', 'm',
         "Maximum water depth (distance from invert to ground) or 0 to use distance from invert to top of highest connecting link"),
        ("initial_depth",       '', "Initial Depth",   '0',  '',   '',  "Initial water depth in junction"),
        ("surcharge_depth",     '', "Surcharge Depth", '0',  '',   '',  "Depth in excess of maximum depth before flooding occurs"),
        ("ponded_area",         '', "Ponded Area",     '0',  '',   '',  "Area of ponded water when flooded"),
        ("diverted_link",       '', "Diverted Link",   '',   '',   '',  "Name of link which receives the diverted flow"),
        ("flow_divider_type",   '', "Type",            '',   '',   '',  "Type of flow divider"),
        ("min_diversion_flow",  '', "Diversion Flow",  '0',  '',   '',  "Minimum flow at which diversion begins"),
        ("divider_curve",       '', "Tabular Curve Name", '', '',  '',  "Name of diversion curve used with a TABULAR divider"),
        ("weir_height",         '', "Weir Height",      '0',  '',  '',  "Depth at maximum flow for a WEIR divider"),
        ("weir_coefficient",    '', "Weir Coefficient", '0',  '',  '',  "Discharge coefficient for a WEIR divider")))

    def __init__(self):
        Junction.__init__(self)

        self.diverted_link = "None"
        """Name of link which receives the diverted flow."""

        self.flow_divider_type = FlowDividerType.CUTOFF
        """Type of flow divider from FlowDividerType(Enum)"""

        self.min_diversion_flow = 0.0
        """Flow at which diversion begins for a CUTOFF or WEIR divider (flow units)."""

        self.divider_curve = "None"
        """Diversion Curve used with a TABULAR divider"""

        self.weir_height = 0.0
        """Height of WEIR divider (ft or m)"""

        self.weir_coefficient = 0.0
        """Discharge coefficient for a WEIR divider"""
Пример #27
0
class Pump(EpanetLink):
    """A Pump link in an EPANET model"""

    #    attribute,  input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name", '', "Pump ID", "", '', '', "User-assigned name of the pump"),
        ("inlet_node", '', "Start Node", "", '', '',
         "Node on the inlet end of the pump"),
        ("outlet_node", '', "End Node", "", '', '',
         "Node on the outlet end of the pump"),
        ("description", '', "Description", "", '', '',
         "Optional description of the pump"),
        ("tag", '', "Tag", "", '', '',
         "Optional label used to categorize or classify the pump"),
        ("head_curve_name", '', "Pump Curve", "", '', '',
         "Curve that describes head versus flow for the pump"),
        ("power", '', "Power", "0.0", '', '',
         "Power value for constant energy pump, hp (kW)"),
        ("speed", '', "Speed", "0.0", '', '',
         "Relative speed setting (normal speed is 1.0, 0 means pump is off)"),
        ("pattern", '', "Pattern", "", '', '',
         "Time pattern that describes how speed setting varies with time"),
        ("initial_status", '', "Initial Status", "", '', '',
         "Initial status of a pump"),
        ("PumpEnergy.value", '', "Effic. Curve", "", '', '',
         "Efficiency curve name"),
        ("PumpEnergy.value", '', "Energy Price", "0.0", '', '',
         "Energy price for this pump"),
        ("PumpEnergy.value", '', "Price Pattern", "", '', '',
         "ID of price pattern for this pump"),
    ))

    def __init__(self):
        EpanetLink.__init__(self)

        self.type = PumpType.POWER
        """Either POWER or HEAD must be supplied for each pump. The other keywords are optional."""

        self.power = "0.0"
        """power value for constant energy pump, hp (kW)"""

        self.head_curve_name = ''
        """curve that describes head versus flow for the pump"""

        self.speed = "0.0"
        """relative speed setting (normal speed is 1.0, 0 means pump is off)"""

        self.pattern = ''
        """time pattern that describes how speed setting varies with time"""
Пример #28
0
class Label(Section, Coordinate):
    """A label on the map with location, text, and optional anchor node ID"""

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name", '', "Text", '', '', '', "Text of label"),
        ('x', '', "X-Coordinate", '', '', '',
         "X coordinate of label on study area map"),
        ('y', '', "Y-Coordinate", '', '', '',
         "Y coordinate of label on study area map"),
        ('anchor_name', '', "Anchor Node", '', '', '',
         "ID label of an anchor node (optional)"),
        ('meter_type', '', "Meter Type", '', '', '',
         "Type of object being metered by the label"),
        ('meter_name', '', "Meter ID", '', '', '',
         "ID of the object (Node or Link) being metered"),
        ("font", '', "Font", "", '', '', "The label's font"),
        ("size", '', "Size", "10.0", '', '', "The label's font size"),
        ("bold", '', "Bold", "False", '', '',
         "Set to True if the label is to be bold"),
        ("italic", '', "Italics", "False", '', '',
         "Set to True if the label is to be italicized"),
    ))

    def __init__(self):
        Section.__init__(self)
        Coordinate.__init__(self)
        """Text of label is saved in name attribute defined in Coordinate base class."""

        ## ID label of an anchor node (optional)
        self.anchor_name = ''  # string

        ## type of object being metered by the label
        self.meter_type = MeterType.NONE

        ## ID of the object (Node or Link) being metered
        self.meter_name = ''

        ## label font
        self.font = ""

        ## label size
        self.size = 10.0

        ## True to use bold
        self.bold = False

        ## True to use italics
        self.italic = False
class Orifice(SwmmLink):
    """An orifice link in a SWMM model"""

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata(
        (("name", '', "Name", "", '', '', "User-assigned name of orifice"),
         ("inlet_node", '', "Inlet Node", "", '', '',
          "Node on the inlet end of orifice"),
         ("outlet_node", '', "Outlet Node", "", '', '',
          "Node on the outlet end of orifice"),
         ("description", '', "Description", "", '', '',
          "Optional description of orifice"),
         ("tag", '', "Tag", "", '', '',
          "Optional label used to categorize or classify orifice"),
         ("type", '', "Type", "", '', '', "Type of orifice"),
         ("cross_section", '', "Shape", "", '', '',
          "Orifice shape"), ("height", '', "Height", "1.0", '(ft)', '(m)',
                             "Height of orifice opening when fully opened"),
         ("width", '', "Width", "1.0", '(ft)', '(m)',
          "Width of orifice opening when fully opened"),
         ("inlet_offset", '', "Inlet Offset", "0.0", '(ft)', '(m)',
          "Depth of bottom of orifice opening from inlet node invert"),
         ("discharge_coefficient", '', "Discharge Coeff.", "0.0", '', '',
          "Discharge coefficient"),
         ("flap_gate", '', "Flap Gate", "False", '', '',
          "True if orifice contains a flap gate to prevent backflow"),
         ("o_rate", '', "Time to Open/Close", "0.0", '', '',
          "Time in decimal hours to open/close a gated orifice")))

    def __init__(self):
        SwmmLink.__init__(self)

        ## OrificeType: Type of orifice
        self.type = OrificeType.SIDE

        ## Name of cross section in XSECTIONS Section
        self.cross_section = "None"

        ## float: Depth of bottom of orifice opening from inlet node invert
        self.inlet_offset = 0.0

        ## float: Discharge coefficient
        self.discharge_coefficient = 0.0

        ## bool: True if a flap gate exists that prevents backflow.
        self.flap_gate = False

        ## float: Time in decimal hours to open/close a gated orifice
        self.o_rate = 0.0
class Outlet(SwmmLink):
    """An outlet link in a SWMM model"""

    #    attribute,         input_name, label,         default, english, metric, hint
    metadata = Metadata((
        ("name", '', "Name", "", '', '', "User-assigned name of outlet"),
        ("inlet_node", '', "Inlet Node", "", '', '',
         "Node on the inlet end of outlet"),
        ("outlet_node", '', "Outlet Node", "", '', '',
         "Node on the outlet end of outlet"),
        ("description", '', "Description", "", '', '',
         "Optional description of the outlet"),
        ("tag", '', "Tag", "", '', '',
         "Optional label used to categorize or classify the outlet"),
        ("inlet_offset", '', "Inlet Offset", "0.0", '(ft)', '(m)',
         "Depth of outlet above inlet node invert"),
        ("flap_gate", '', "Flap Gate", "False", '', '',
         "True if outlet contains a flap gate to prevent backflow"),
        ("curve_type", '', "Rating Curve", "", '', '',
         "Method of defining flow as a function of either freeboard depth or head across the outlet"
         ), ("coefficient", '', "Functional Curve Coefficient", "0.0", '(ft)',
             '(m)',
             "A-value in expression Outflow = A*y^B for y(=depth or head)"),
        ("exponent", '', "Functional Curve Exponent", "0.0", '(ft)', '(m)',
         "B-value in expression Outflow = A*y^B for y(=depth or head)"),
        ("rating_curve", '', "Tabular Curve Name", "", '', '',
         "Name of rating curve that relates outflow to either depth or head")))

    def __init__(self):
        SwmmLink.__init__(self)

        ## float: Depth of outlet above inlet node invert
        self.inlet_offset = 0.0

        ## bool: True if outlet contains a flap gate to prevent backflow
        self.flap_gate = False

        ## float: Coefficient in outflow expression
        self.coefficient = 10.0

        ## float: Exponent in outflow expression
        self.exponent = 0.5

        ## OutletCurveType: Method of defining flow as a function of either freeboard depth or head across the outlet
        self.curve_type = OutletCurveType.FUNCTIONAL_DEPTH

        ## str: Name of rating curve that relates outflow to either depth or head
        self.rating_curve = "None"