Build surface water network for MODFLOW's SFR Package

Overview

Surface water network

Codacy Badge CI

Creates surface water network, which can be used to create MODFLOW's SFR.

Python packages

Python 3.6+ is required.

Required

  • geopandas - process spatial data similar to pandas
  • pyproj>=2.2 - spatial projection support
  • rtree - spatial index support

Optional

  • flopy - read/write MODFLOW models
  • netCDF4 - used to read TopNet files

Testing

Run pytest -v or python3 -m pytest -v

For faster multi-core pytest -v -n 2 (with pytest-xdist)

Examples

import geopandas
import pandas as pd
import swn
import swn.file

Read from Shapefile:

shp_srs = 'tests/data/DN2_Coastal_strahler1z_stream_vf.shp'
lines = geopandas.read_file(shp_srs)
lines.set_index('nzsegment', inplace=True, verify_integrity=True)  # optional

Or, read from PostGIS:

from sqlalchemy import create_engine, engine

con_url = engine.url.URL(drivername='postgresql', database='scigen')
con = create_engine(con_url)
sql = 'SELECT * FROM wrc.rec2_riverlines_coastal'
lines = geopandas.read_postgis(sql, con)
lines.set_index('nzsegment', inplace=True, verify_integrity=True)  # optional

Initialise and create network:

n = swn.SurfaceWaterNetwork.from_lines(lines.geometry)
print(n)
# 
   

    #   304 segments: [3046409, 3046455, ..., 3050338, 3050418]

    #   154 headwater: [3046409, 3046542, ..., 3050338, 3050418]

    #   3 outlets: [3046700, 3046737, 3046736]

    #   no diversions />
   

Plot the network, write a Shapefile, write and read a SurfaceWaterNetwork file:

n.plot()

swn.file.gdf_to_shapefile(n.segments, 'segments.shp')

n.to_pickle('network.pkl')
n = swn.SurfaceWaterNetwork.from_pickle('network.pkl')

Remove segments that meet a condition (stream order), or that are upstream/downstream from certain locations:

n.remove(n.segments.stream_order == 1, segnums=n.query(upstream=3047927))

Read flow data from a TopNet netCDF file, convert from m3/s to m3/day:

nc_path = 'tests/data/streamq_20170115_20170128_topnet_03046727_strahler1.nc'
flow = swn.file.topnet2ts(nc_path, 'mod_flow', 86400)
# remove time and truncate to closest day
flow.index = flow.index.floor('d')

# 7-day mean
flow7d = flow.resample('7D').mean()

# full mean
flow_m = pd.DataFrame(flow.mean(0)).T

Process a MODFLOW/flopy model:

import flopy

m = flopy.modflow.Modflow.load('h.nam', model_ws='tests/data', check=False)
nm = swn.SwnModflow.from_swn_flopy(n, m)
nm.default_segment_data()
nm.set_segment_data_inflow(flow_m)
nm.plot()
nm.to_pickle('sfr_network.pkl')
nm = swn.SwnModflow.from_pickle('sfr_network.pkl', n, m)
nm.set_sfr_obj()
m.sfr.write_file('file.sfr')
nm.grid_cells.to_file('grid_cells.shp')
nm.reaches.to_file('reaches.shp')

Citation

Toews, M. W.; Hemmings, B. 2019. A surface water network method for generalising streams and rapid groundwater model development. In: New Zealand Hydrological Society Conference, Rotorua, 3-6 December, 2019. p. 166-169.

Comments
  • sort index before comparing

    sort index before comparing

    Lines and polygons dfs needed to be sorted before comparing index. (I suck at git so hopefully this works. Let me know if I need to do something different.)

    opened by wkitlasten 4
  • SwnMf6 obj has no attribute 'grid_cells'

    SwnMf6 obj has no attribute 'grid_cells'

    Generating my SwnMf6 object and pickling it like this:

    ngwf = swn.SwnMf6.from_swn_flopy(n, gwf,reach_include_fraction=0)
    ngwf.to_pickle('test_pickle.pkl')
    

    Then reading it back in like this:

    ngwf = swn.SwnMf6.from_pickle('test_pickle.pkl',gwf)

    But some of the object attributes are note being set. I can manually set ngwf._swn=n, but the grid_cells seems a bit more difficult. Results in this error:

    AttributeError: 'SwnMf6' object has no attribute 'grid_cells'

    AttributeError Traceback (most recent call last) in ----> 1 ngwf.plot()

    d:\modelling\surface-water-network\swn\modflow_base.py in plot(self, column, cmap, colorbar) 996 column=column, label="reaches", legend=colorbar, ax=ax, cmap=cmap) 997 --> 998 self.grid_cells.plot(ax=ax, color="whitesmoke", edgecolor="gainsboro") 999 1000 def getpt(g, idx):

    AttributeError: 'SwnMf6' object has no attribute 'grid_cells'

    opened by wkitlasten 2
  • mf6 support

    mf6 support

    Add support for building sfr datasets for MODFLOW6. Have started plumbing in the raw datasets on branch feat_mf6sfr. Perhaps don't need to worry too much about wrangling into Flopy framework, as long as we can build a write the external files as mf6 needs them.

    opened by briochh 2
  • Fixed to_rno_elev using pandas

    Fixed to_rno_elev using pandas

    This should ensure downstream rtp < upstream rtp, plus ensure reach falls within top and bottom of upper layer.

    Also changed keep_geom_type to False to get rid of heaps of deprication warnings. Not sure if that has other ramifications.

    opened by wkitlasten 1
  • swn can only be assigned once?

    swn can only be assigned once?

    I just pulled from main to make sure I was updated and started getting the following error after trying to load the pickle. Thoughts?

    ngwf = swn.SwnMf6.from_pickle(ppth,gwf)
    
    File "d:\modelling\surface-water-network\swn\modflow\_base.py", line 126, in from_pickle
        obj.swn = swn
    
      File "d:\modelling\surface-water-network\swn\modflow\_base.py", line 152, in swn
        raise AttributeError("swn property can only be set once")
    
    AttributeError: swn property can only be set once
    
    opened by wkitlasten 1
  • Need to be able to update model arrays

    Need to be able to update model arrays

    Trying to directly assign model arrays. For example after adjusting layer bottoms in _reachbyreach_elevs or _to_rno_elevs this results in Error: can't set attribute:

    self.model.dis.botm.array = botm

    But self.model.dis.botm = botm obliterates other information typically available through ngwf.model.dis.top.get_file_entry()

    Any suggestions on how to set just the array, but leave the other information intact?

    opened by wkitlasten 1
  • flopy SFR package interaction

    flopy SFR package interaction

    There is some behaviour to address related to modifying the flopy segment and reach data frames after undertaking the processing:

    When initiallising the flopy SFR object any missing column entries are added with default values - totally cool.

    However, when updating (e.g. m.sfr.segment_data = dict) missing data columns are never constructed - this then falls apart when writing the sfr (see for e.g. around line 1637 of mfsfr2.py). for flexibility at that writing step flopy expects a number of data columns to exist (even if they are infact never used).

    Worth noting that m.sfr.segment_data = dict approaches will (I think) happily deal with additional data columns in the passed dict (or record arrays) - but the initial constructor will not.

    opened by briochh 1
  • Feat: write_formatted_frame and read_formatted_frame methods

    Feat: write_formatted_frame and read_formatted_frame methods

    Closes #59 for packagedata and diversions files, but does not change connectiondata (for now, at least)

    Also, add read_formatted_frame as a convenience to read these formats back into a pandas DataFrame.

    enhancement 
    opened by mwtoews 0
  • Use items instead of iteritems

    Use items instead of iteritems

    iteritems() is deprecated since version 1.5.0, so use items() instead.

    Also pd.Series(data, dtype=dtype) does not properly cast a dict to dtype, so use pd.Series(data).astype(dtype) instead.

    opened by mwtoews 0
  • space before # in write_packagedata (maybe write_connectiondata)?

    space before # in write_packagedata (maybe write_connectiondata)?

    I am getting a space before # in the header of my packagedata file which causes issues in pandas unless I explicitly skip that line (i.e. pandas seems to read the line as a data followed by a comment, rather than a comment line). I can't quite figure out the formatting syntax to fix it in SWN and the fix on my end is a bit annoying (check for a header in each file, parse, etc).

    opened by wkitlasten 0
  • Mark deprecation for swn.spatial.get_sindex; require geopandas >=0.9

    Mark deprecation for swn.spatial.get_sindex; require geopandas >=0.9

    This approach might have been useful for older geopandas versions, but not anymore. The performance of gdf.sindex to get/generate a spatial index is good.

    Also, require geopandas >=0.9

    opened by mwtoews 0
  • to_rno_elev method now using pandas

    to_rno_elev method now using pandas

    This PR should take care of some bugs and speed things up. I also added a small work around for the rare case when a stream vertex falls on a grid line, resulting in the stream reach being a POINT. Probably a better way to handle it, but it got me past my issue.

    opened by wkitlasten 0
  • recurse_upstream issue

    recurse_upstream issue

    I am running into this issue with the DN3 network in Otago. Presumably it is an issue in the network. Is it a network connection/routing issue? Shapefile topology issue? Something else?

    File "D:\modelling\nzmf6\nzmf6\utils.py", line 315, in add_sfr n = swn.SurfaceWaterNetwork.from_lines(lines.geometry) File "d:\modelling\surface-water-network\swn\core.py", line 336, in from_lines recurse_upstream(segnum, segnum, 0, 0.0) File "d:\modelling\surface-water-network\swn\core.py", line 333, in recurse_upstream recurse_upstream(from_segnum, cat_group, num, dist) File "d:\modelling\surface-water-network\swn\core.py", line 333, in recurse_upstream recurse_upstream(from_segnum, cat_group, num, dist) File "d:\modelling\surface-water-network\swn\core.py", line 333, in recurse_upstream recurse_upstream(from_segnum, cat_group, num, dist) [Previous line repeated 976 more times] File "d:\modelling\surface-water-network\swn\core.py", line 329, in recurse_upstream dist += obj.segments.geometry[segnum].length File "C:\ProgramData\Anaconda3\envs\py37\lib\site-packages\geopandas\geoseries.py", line 558, in getitem return self._wrapped_pandas_method("getitem", key) File "C:\ProgramData\Anaconda3\envs\py37\lib\site-packages\geopandas\geoseries.py", line 551, in _wrapped_pandas_method val = getattr(super(GeoSeries, self), mtd)(*args, **kwargs) File "C:\ProgramData\Anaconda3\envs\py37\lib\site-packages\pandas\core\series.py", line 942, in getitem return self._get_value(key) File "C:\ProgramData\Anaconda3\envs\py37\lib\site-packages\pandas\core\series.py", line 1052, in _get_value return self.index._get_values_for_loc(self, loc, label) File "C:\ProgramData\Anaconda3\envs\py37\lib\site-packages\pandas\core\indexes\base.py", line 5184, in _get_values_for_loc return series._values[loc] File "C:\ProgramData\Anaconda3\envs\py37\lib\site-packages\geopandas\array.py", line 376, in getitem if isinstance(idx, numbers.Integral): File "C:\ProgramData\Anaconda3\envs\py37\lib\abc.py", line 139, in instancecheck return _abc_instancecheck(cls, instance) File "C:\ProgramData\Anaconda3\envs\py37\lib\abc.py", line 143, in subclasscheck return _abc_subclasscheck(cls, subclass) RecursionError: maximum recursion depth exceeded in comparison

    opened by wkitlasten 0
  • Massive geopandas deprication warnings

    Massive geopandas deprication warnings

    Not sure how to address this, but the repeated warnings from geopandas (0.9.0) are a bit overwhelming.

    My code: ngwf = swn.SwnMf6.from_swn_flopy(n, model=gwf)

    The warning (x heaps): C:\ProgramData\Anaconda3\envs\py37\lib\site-packages\geopandas\geoseries.py:207: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Not sure where the empty series is being being created. Any suggestions?

    opened by wkitlasten 1
  • SwnModflowBase methods using full swn rather than limited to the model?

    SwnModflowBase methods using full swn rather than limited to the model?

    More of an enhancement perhaps: Is the SwnModflowBase class using the full swn object for calculations? For example, is "set_reach_data_from_segments" doing calcs on all of the swn.segments (e.g. line 1050, "segdat = self._swn.pair_segments_frame")? There are about 5,000 reaches in my MF6 model, but it appears calcs are being done on all 300,000 segments in the swn object, unless I am missing something (which is usually the case!).

    opened by wkitlasten 0
  • Another shapely deprecation warning trigger

    Another shapely deprecation warning trigger

    @mwtoews another spot where we a triggering a shapely deprecation warning.

    Are we happy to just be swallowing these for now?

    https://github.com/mwtoews/surface-water-network/blob/63cc21ca72d95e150dbeb7789a4364b1339ae9a8/swn/modflow/_base.py#L559

    opened by briochh 0
Releases(0.5)
Owner
Mike Taves
Hydrogeologist, numerical modeller, GIS guru. Last name is also Toews.
Mike Taves
Ip-Tracker: a script written in python for tracking Someone using targets ip-Tracker address

🔰 𝕀𝕡-𝕋𝕣𝕒𝕔𝕜𝕖𝕣 🔰 Ip-Tracker is a script written in python for tracking Someone using targets ip-Tracker address It was made by Spider Anongre

Spider Anongreyhat 15 Dec 02, 2022
Arp Spoofer using Python 3.

ARP Spoofer / Wifi Killer By Auax Run: Run the application with the following command: python3 spoof.py -t target_ip_address -lh host_ip_address I

Auax 6 Sep 15, 2022
These scripts send notifications to a Webex space when a new IP is banned by Expressway, and allow to request more info or change the ban status

Spam Call and Toll Fraud Mitigation Cisco Expressway release X14 is able to mitigate spam calls and toll fraud attempts by jailing the spam IP address

Luca Pellegrini 6 Aug 05, 2022
This python script can change the mac address after some attack

MAC-changer Hello people, this python script was written for people who want to change the mac address after some attack, I know there are many ways t

5 Oct 10, 2022
Openconnect VPN RPi Gateway

Openconnect-VPN-RPi-Gateway See the blog (Chinese) for how to build an Openconne

Zhongze Tang 2 Jan 30, 2022
An open source bias lighting program which syncs up colored lights to the contents of your screen.

About Firelight Firelight is an open source bias lighting program which syncs up colored lights to the contents of your screen or TV, providing an imm

Roshan 18 Dec 18, 2022
A python shell / chat bot for XMPP and cloud services

XMPP_Shell_Bot A python shell / chat bot for XMPP and cloud services, designed for penetration testers to bypass network filters. To better understand

Abdulkareem Aldeek 1 Jan 09, 2022
Event-driven networking engine written in Python.

Twisted For information on changes in this release, see the NEWS file. What is this? Twisted is an event-based framework for internet applications, su

Twisted Matrix Labs 4.9k Jan 08, 2023
tradingview socket api for fetching real time prices.

tradingView-API tradingview socket api for fetching real time prices. How to run git clone https://github.com/mohamadkhalaj/tradingView-API.git cd tra

MohammadKhalaj 35 Dec 31, 2022
A tool to generate valid ip addresses of 55 countries. These ip's can be used for OpenBullet.

IP-Grabber A tool to generate valid ip addresses of 55 countries. These ip's can be used for OpenBullet. ive added the feature to set the generated ip

Saad 9 Dec 17, 2022
A Python based command line ARP Spoofer utility, which takes input as arguments for the exact target IP and gateway IP for which you wish to Spoof ARP request

A Python based command line ARP Spoofer utility, which takes input as arguments for the exact target IP and gateway IP for which you wish to Spoof ARP request

Abhinandan Khurana 1 Feb 10, 2022
Ctech Didik Auto Script VPN 👨🏻‍💻Youtube: Ctech Didik

CTech Didik Auto Script VPN SUPPORT OPERATING SYSTEM Debian GNU/Linux 11 (Bullseye) Debian GNU/Linux 10 (Buster) Debian GNU/Linux 9 (Stretch) Ubuntu S

Ctech Didik 27 Dec 20, 2022
Utility for converting IP Fabric webhooks into a Teams format.

IP Fabric Webhook Integration for Microsoft Teams and/or Slack Setup IP Fabric Setup Go to Settings Webhooks Add webhook Provide a name URL will b

Community Fabric 1 Jan 26, 2022
A simple electrical network analyzer, BASED ON computer-aided design.

Electrical Network Analyzer A simple electrical network analyzer. Given the oriented graph of the electrical network (circut), BASED ON computer-aided

Ahmad Abdulrahman 4 Oct 15, 2022
Juniper SNMP Migrations For Python

Juniper SNMP Migrations This example will show how to use the PyEZ plugin for Nornir to build a NETCONF connection to a remote device validate that SN

Calvin Remsburg 1 Jan 07, 2022
A Python Packages to make own chat room

Chathon A Python packages for make own chat room Install PyPI pip install chathon

1 Dec 10, 2021
DataShare - Simple library for data sharing between scripts and public functions calling

DataShare - Simple library for data sharing between scripts and public functions calling. Installation. Install code, Delete LICENSE, README, readme.t

Ivan Perzhinsky. 1 Dec 17, 2021
TradingView Interactive Brokers Integration using Webhooks

TradingView Interactive Brokers Integration using Webhooks

84 Dec 19, 2022
An curated collection of awesome resources about networking in cybersecurity

An ongoing curated collection of awesome software, libraries, frameworks, talks & videos, best practices, learning tutorials and important practical resources about networking in cybersecurity

Paul Veillard, P. Eng 7 Nov 30, 2022
Script and library to wait for a DNS authority server to get its configuration.

DNSWait dnswait is a small script to wait for the "propagation" of a namserver configuration. Installing It's as easy as: python -m pip install dnswai

Julien Palard 14 Jan 17, 2022