def nodes(self, bbox=None, subset=None): """ collect all useful and available data related model nodes and organize in one dataframe. """ # check if this has been done already and return that data accordingly if self._nodes_df is not None and bbox == self.bbox: return self._nodes_df # parse out the main objects of this model inp = self.inp rpt = self.rpt # create dataframes of relevant sections from the INP juncs_df = create_dataframeINP(inp.path, "[JUNCTIONS]") outfalls_df = create_dataframeINP(inp.path, "[OUTFALLS]") storage_df = create_dataframeINP(inp.path, "[STORAGE]") # concatenate the DFs and keep only relevant cols all_nodes = pd.concat([juncs_df, outfalls_df, storage_df]) cols = ['InvertElev', 'MaxDepth', 'SurchargeDepth', 'PondedArea'] all_nodes = all_nodes[cols] if rpt: # add results data if a rpt file was found depth_summ = create_dataframeRPT(rpt.path, "Node Depth Summary") flood_summ = create_dataframeRPT(rpt.path, "Node Flooding Summary") # join the rpt data (index on depth df, suffixes for common cols) rpt_df = depth_summ.join(flood_summ, lsuffix='_depth', rsuffix='_flood') all_nodes = all_nodes.join(rpt_df) # join to the all_nodes df all_nodes = all_nodes.join(self.inp.coordinates[['X', 'Y']]) def nodexy(row): if math.isnan(row.X) or math.isnan(row.Y): return None else: return [(row.X, row.Y)] xys = all_nodes.apply(lambda r: nodexy(r), axis=1) all_nodes = all_nodes.assign(coords=xys) all_nodes = all_nodes.rename(index=str) self._nodes_df = all_nodes return all_nodes
def nodes(self, bbox=None, subset=None): """ collect all useful and available data related model nodes and organize in one dataframe. """ # check if this has been done already and return that data accordingly if self._nodes_df is not None and bbox == self.bbox: return self._nodes_df # parse out the main objects of this model inp = self.inp rpt = self.rpt # create dataframes of relevant sections from the INP juncs_df = create_dataframeINP(inp.path, "[JUNCTIONS]") outfalls_df = create_dataframeINP(inp.path, "[OUTFALLS]") storage_df = create_dataframeINP(inp.path, "[STORAGE]") # concatenate the DFs and keep only relevant cols all_nodes = pd.concat([juncs_df, outfalls_df, storage_df]) cols = ['InvertElev', 'MaxDepth', 'SurchargeDepth', 'PondedArea'] all_nodes = all_nodes[cols] if rpt: # add results data if a rpt file was found depth_summ = create_dataframeRPT(rpt.path, "Node Depth Summary") flood_summ = create_dataframeRPT(rpt.path, "Node Flooding Summary") # join the rpt data (index on depth df, suffixes for common cols) rpt_df = depth_summ.join( flood_summ, lsuffix='_depth', rsuffix='_flood') all_nodes = all_nodes.join(rpt_df) # join to the all_nodes df all_nodes = all_nodes.join(self.inp.coordinates[['X', 'Y']]) def nodexy(row): if math.isnan(row.X) or math.isnan(row.Y): return None else: return [(row.X, row.Y)] xys = all_nodes.apply(lambda r: nodexy(r), axis=1) all_nodes = all_nodes.assign(coords=xys) all_nodes = all_nodes.rename(index=str) self._nodes_df = all_nodes return all_nodes
def __call__(self): """ collect all useful and available data related to the conduits and organize in one dataframe. >>> model = swmmio.Model(MODEL_FULL_FEATURES__NET_PATH) >>> conduits_section = ModelSection(model, 'conduits') >>> conduits_section() """ # create dataframes of relevant sections from the INP for ix, sect in enumerate(self.config['inp_sections']): if ix == 0: df = create_dataframeINP(self.inp.path, sect, comment_cols=False) else: df_other = create_dataframeINP(self.inp.path, sect, comment_cols=False) df = df.join(df_other) if self.rpt: for rpt_sect in self.config['rpt_sections']: df = df.join(create_dataframeRPT(self.rpt.path, rpt_sect)) # add conduit coordinates xys = df.apply(lambda r: get_link_coords(r, self.inp.coordinates, self.inp.vertices), axis=1) df = df.assign(coords=xys.map(lambda x: x[0])) # make inlet/outlet node IDs string type df.InletNode = df.InletNode.astype(str) df.OutletNode = df.OutletNode.astype(str) return df
def __call__(self): """ collect all useful and available data related to the conduits and organize in one dataframe. >>> model = swmmio.Model(MODEL_FULL_FEATURES__NET_PATH) >>> conduits_section = ModelSection(model, 'conduits') >>> conduits_section() """ # create dataframes of relevant sections from the INP for ix, sect in enumerate(self.config['inp_sections']): if ix == 0: df = create_dataframeINP(self.inp.path, sect, comment_cols=False) else: df_other = create_dataframeINP(self.inp.path, sect, comment_cols=False) df = df.join(df_other) if df.empty: return df # if there is an RPT available, grab relevant sections if self.rpt: for rpt_sect in self.config['rpt_sections']: df = df.join(create_dataframeRPT(self.rpt.path, rpt_sect)) # add conduit coordinates xys = df.apply(lambda r: get_link_coords(r, self.inp.coordinates, self.inp.vertices), axis=1) df = df.assign(coords=xys.map(lambda x: x[0])) # make inlet/outlet node IDs string type df.InletNode = df.InletNode.astype(str) df.OutletNode = df.OutletNode.astype(str) return df
def conduits(self): """ collect all useful and available data related model conduits and organize in one dataframe. """ # check if this has been done already and return that data accordingly if self._conduits_df is not None: return self._conduits_df # parse out the main objects of this model inp = self.inp rpt = self.rpt # create dataframes of relevant sections from the INP conduits_df = create_dataframeINP(inp.path, "[CONDUITS]", comment_cols=False) xsections_df = create_dataframeINP(inp.path, "[XSECTIONS]", comment_cols=False) conduits_df = conduits_df.join(xsections_df) if rpt: # create a dictionary holding data from an rpt file, if provided link_flow_df = create_dataframeRPT(rpt.path, "Link Flow Summary") conduits_df = conduits_df.join(link_flow_df) # add conduit coordinates xys = conduits_df.apply(lambda r: get_link_coords( r, self.inp.coordinates, self.inp.vertices), axis=1) df = conduits_df.assign(coords=xys.map(lambda x: x[0])) # add conduit up/down inverts and calculate slope elevs = self.nodes()[['InvertElev']] df = pd.merge(df, elevs, left_on='InletNode', right_index=True, how='left') df = df.rename(index=str, columns={"InvertElev": "InletNodeInvert"}) df = pd.merge(df, elevs, left_on='OutletNode', right_index=True, how='left') df = df.rename(index=str, columns={"InvertElev": "OutletNodeInvert"}) df['UpstreamInvert'] = df.InletNodeInvert + df.InletOffset df['DownstreamInvert'] = df.OutletNodeInvert + df.OutletOffset df['SlopeFtPerFt'] = (df.UpstreamInvert - df.DownstreamInvert) / df.Length df.InletNode = df.InletNode.astype(str) df.OutletNode = df.OutletNode.astype(str) self._conduits_df = df return df
def conduits(self): """ collect all useful and available data related model conduits and organize in one dataframe. """ # check if this has been done already and return that data accordingly if self._conduits_df is not None: return self._conduits_df # parse out the main objects of this model inp = self.inp rpt = self.rpt # create dataframes of relevant sections from the INP conduits_df = create_dataframeINP(inp.path, "[CONDUITS]", comment_cols=False) xsections_df = create_dataframeINP(inp.path, "[XSECTIONS]", comment_cols=False) conduits_df = conduits_df.join(xsections_df) if rpt: # create a dictionary holding data from an rpt file, if provided link_flow_df = create_dataframeRPT(rpt.path, "Link Flow Summary") conduits_df = conduits_df.join(link_flow_df) # add conduit coordinates xys = conduits_df.apply(lambda r: get_link_coords(r, self.inp.coordinates, self.inp.vertices), axis=1) df = conduits_df.assign(coords=xys.map(lambda x: x[0])) # add conduit up/down inverts and calculate slope elevs = self.nodes()[['InvertElev']] df = pd.merge(df, elevs, left_on='InletNode', right_index=True, how='left') df = df.rename(index=str, columns={"InvertElev": "InletNodeInvert"}) df = pd.merge(df, elevs, left_on='OutletNode', right_index=True, how='left') df = df.rename(index=str, columns={"InvertElev": "OutletNodeInvert"}) df['UpstreamInvert'] = df.InletNodeInvert + df.InletOffset df['DownstreamInvert'] = df.OutletNodeInvert + df.OutletOffset df['SlopeFtPerFt'] = (df.UpstreamInvert - df.DownstreamInvert) / df.Length df.InletNode = df.InletNode.astype(str) df.OutletNode = df.OutletNode.astype(str) self._conduits_df = df return df
def subcatchments(self): """ collect all useful and available data related subcatchments and organize in one dataframe. """ subs = create_dataframeINP(self.inp.path, "[SUBCATCHMENTS]") subs = subs.drop([';', 'Comment', 'Origin'], axis=1) polygons_df = self.inp.polygons if self.rpt: flw = create_dataframeRPT( self.rpt.path, 'Subcatchment Runoff Summary') subs = subs.join(flw) # more accurate runoff calculations subs['RunoffAcFt'] = subs.TotalRunoffIn / 12.0 * subs.Area subs['RunoffMGAccurate'] = subs.RunoffAcFt / 3.06888785 self._subcatchments_df = subs return subs
def subcatchments(self): """ collect all useful and available data related subcatchments and organize in one dataframe. """ subs = create_dataframeINP(self.inp.path, "[SUBCATCHMENTS]") subs = subs.drop([';', 'Comment', 'Origin'], axis=1) polygons_df = self.inp.polygons if self.rpt: flw = create_dataframeRPT(self.rpt.path, 'Subcatchment Runoff Summary') subs = subs.join(flw) # more accurate runoff calculations subs['RunoffAcFt'] = subs.TotalRunoffIn / 12.0 * subs.Area subs['RunoffMGAccurate'] = subs.RunoffAcFt / 3.06888785 self._subcatchments_df = subs return subs
def timeseries_join(elements, *models): """ Given a list of element IDs and Model objects, a dataframe is returned with the elements' time series data for each model. Example: df = timeseries_join(elements = ['P1, P2'], model1, model2) returns df with index = DateTime and cols = [model1_P1_FlowCFS, model1_P2_FlowCFS, model2_P1_FlowCFS, model2_P2_FlowCFS] """ # dfs = [[dataframes.create_dataframeRPT(m.rpt, 'Link Results', el)[['FlowCFS']] # for el in elements] for m in models] param_name = 'FlowCFS' #as named by our dataframe method section_name = 'Link Results' #in the rpt dfs = [ create_dataframeRPT(m.rpt, section_name, elem)[[ param_name ]].rename(columns={ param_name: '{}_{}_{}'.format(m.inp.name, elem, param_name) }) for m in models for elem in elements ] df = pd.concat(dfs, axis=1) return df
def model_to_networkx(model, drop_cycles=True): from swmmio.utils.dataframes import create_dataframeINP, create_dataframeRPT ''' Networkx MultiDiGraph representation of the model ''' from geojson import Point, LineString try: import networkx as nx except ImportError: raise ImportError('networkx module needed. get this package here: ', 'https://pypi.python.org/pypi/networkx') def multidigraph_from_edges(edges, source, target): ''' create a MultiDiGraph from a dataframe of edges, using the row index as the key in the MultiDiGraph ''' us = edges[source] vs = edges[target] keys = edges.index data = edges.drop([source, target], axis=1) d_dicts = data.to_dict(orient='records') G = nx.MultiDiGraph() G.add_edges_from(zip(us, vs, keys, d_dicts)) return G # parse swmm model results with swmmio, concat all links into one dataframe nodes = model.nodes() if model.rpt is not None: inflow_cols = [ 'MaxLatInflow', 'MaxTotalInflow', 'LatInflowV', 'TotalInflowV', 'FlowBalErrorPerc' ] flows = create_dataframeRPT(model.rpt.path, "Node Inflow Summary")[inflow_cols] nodes = nodes.join(flows) conduits = model.conduits() links = pd.concat( [conduits, model.orifices(), model.weirs(), model.pumps()], sort=True) links['facilityid'] = links.index # create a nx.MultiDiGraph from the combined model links, add node data, set CRS G = multidigraph_from_edges(links, 'InletNode', target='OutletNode') G.add_nodes_from(zip(nodes.index, nodes.to_dict(orient='records'))) # create geojson geometry objects for each graph element for u, v, k, coords in G.edges(data='coords', keys=True): if coords: G[u][v][k]['geometry'] = LineString(coords) for n, coords in G.nodes(data='coords'): if coords: G.node[n]['geometry'] = Point(coords[0]) if drop_cycles: # remove cycles cycles = list(nx.simple_cycles(G)) if len(cycles) > 0: print('cycles detected and removed: {}'.format(cycles)) G.remove_edges_from(cycles) G.graph['crs'] = model.crs return G
def model_to_networkx(model, drop_cycles=True): from swmmio.utils.dataframes import create_dataframeINP, create_dataframeRPT ''' Networkx MultiDiGraph representation of the model ''' from geojson import Point, LineString try: import networkx as nx except ImportError: raise ImportError('networkx module needed. get this package here: ', 'https://pypi.python.org/pypi/networkx') def multidigraph_from_edges(edges, source, target): ''' create a MultiDiGraph from a dataframe of edges, using the row index as the key in the MultiDiGraph ''' us = edges[source] vs = edges[target] keys = edges.index data = edges.drop([source, target], axis=1) d_dicts = data.to_dict(orient='records') G = nx.MultiDiGraph() G.add_edges_from(zip(us, vs, keys, d_dicts)) return G # parse swmm model results with swmmio, concat all links into one dataframe nodes = model.nodes() if model.rpt is not None: inflow_cols = [ 'MaxLatInflow', 'MaxTotalInflow', 'LatInflowV', 'TotalInflowV', 'FlowBalErrorPerc'] flows = create_dataframeRPT( model.rpt.path, "Node Inflow Summary")[inflow_cols] nodes = nodes.join(flows) conduits = model.conduits() links = pd.concat([conduits, model.orifices(), model.weirs(), model.pumps()]) links['facilityid'] = links.index # create a nx.MultiDiGraph from the combined model links, add node data, set CRS G = multidigraph_from_edges(links, 'InletNode', target='OutletNode') G.add_nodes_from(zip(nodes.index, nodes.to_dict(orient='records'))) # create geojson geometry objects for each graph element for u, v, k, coords in G.edges(data='coords', keys=True): if coords: G[u][v][k]['geometry'] = LineString(coords) for n, coords in G.nodes(data='coords'): if coords: G.node[n]['geometry'] = Point(coords[0]) if drop_cycles: # remove cycles cycles = list(nx.simple_cycles(G)) if len(cycles) > 0: print('cycles detected and removed: {}'.format(cycles)) G.remove_edges_from(cycles) G.graph['crs'] = model.crs return G