bmi_nwis

bmi_nwis package is an implementation of the Basic Model Interface (BMI) for the USGS NWIS dataset. This package uses the dataretrieval package to download the NWIS dataset and wraps the dataset with BMI for data control and query.

This package is not implemented for people to use but is the key element to convert the NWIS dataset into a data component (pymt_nwis) for the PyMT modeling framework developed by Community Surface Dynamics Modeling System (CSDMS).

Please note that the current bmi_nwis implementation only supports to download time series data for instantaneous values and daily mean values (‘iv’ or ‘dv’ service option in the dataretrieval package).

Getting Started

Installation

Stable Release

The bmi_nwis package and its dependencies can be installed with pip.

pip install bmi_nwis
conda install -c conda-forge bmi_nwis

From Source

After downloading the source code, run the following command from top-level folder to install bmi_nwis.

pip install -e .

Download NWIS Data

Example 1: Use the dataretrieval package to download data

import dataretrieval.nwis as nwis

# get data from NWIS
dataset = nwis.get_record(
    sites="03339000", service="iv", start="2022-01-01", end="2022-01-03"
)

# plot data
ax = dataset.plot(
    y=["00060", "00065"],
    subplots=True,
    figsize=(10, 8),
    xlabel="Time",
    title="Time Series Data at USGS Gage 03339000",
)
ax[0].set_ylabel("Stream flow (ft3/s)")
ax[1].set_ylabel("Gage height (ft)")
_images/plot.png

Example 2: use BmiNwis class to download data (Demonstration of how to use BMI).

import numpy as np
import cftime
import pandas as pd

from bmi_nwis import BmiNwis


# initiate a data component
data_comp = BmiNwis()
data_comp.initialize("config_file.yaml")

# get variable info
for var_name in data_comp.get_output_var_names():
    var_unit = data_comp.get_var_units(var_name)
    var_location = data_comp.get_var_location(var_name)
    var_type = data_comp.get_var_type(var_name)
    var_grid = data_comp.get_var_grid(var_name)
    var_itemsize = data_comp.get_var_itemsize(var_name)
    var_nbytes = data_comp.get_var_nbytes(var_name)

    print(f"{var_name=}")
    print(f"{var_unit=}")
    print(f"{var_location=}")
    print(f"{var_type=}")
    print(f"{var_grid=}")
    print(f"{var_itemsize=}")
    print(f"{var_nbytes=}\n")

# get time info
start_time = data_comp.get_start_time()
end_time = data_comp.get_end_time()
time_step = data_comp.get_time_step()
time_unit = data_comp.get_time_units()
time_steps = int((end_time - start_time) / time_step) + 1

print(f"{start_time=}")
print(f"{end_time=}")
print(f"{time_step=}")
print(f"{time_unit=}")
print(f"{time_steps=}")

# get variable grid info
grid_type = data_comp.get_grid_type(var_grid)
grid_rank = data_comp.get_grid_rank(var_grid)
grid_node_count = data_comp.get_grid_node_count(var_grid)

site_lon = np.empty(grid_node_count)
data_comp.get_grid_x(var_grid, site_lon)

site_lat = np.empty(grid_node_count)
data_comp.get_grid_y(var_grid, site_lat)

print(f"{grid_type=}")
print(f"{grid_rank=}")
print(f"{grid_node_count=}")
print(f"{site_lon[0]=}")
print(f"{site_lat[0]=}")

# initiate dataframe to store data
dataset = pd.DataFrame(columns=["00060", "00065", "time"])

for i in range(0, time_steps):
    # get stream flow data
    stream_flow = np.empty(1)
    data_comp.get_value("Stream flow", stream_flow)

    # get gage height data
    gage_height = np.empty(1)
    data_comp.get_value("Height", gage_height)

    # get time data
    cftime_value = data_comp.get_current_time()
    time = cftime.num2pydate(cftime_value, time_unit)

    # add new row to dataframe
    dataset.loc[len(dataset)] = [stream_flow[0], gage_height[0], time]

    # update to next time step
    data_comp.update()

# convert time to local time
dataset = dataset.set_index("time").tz_localize(tz="UTC").tz_convert(tz="US/Central")

# plot data
ax = dataset.plot(
    y=["00060", "00065"],
    subplots=True,
    figsize=(10, 8),
    xlabel="Time",
    title="Time Series Data at USGS Gage 03339000",
)
ax[0].set_ylabel("Stream flow (ft3/s)")
ax[1].set_ylabel("Gage height (ft)")

# finalize the data component
data_comp.finalize()

Parameter settings

To initiate a data component, a configuration file (e.g., config_file.yaml ) can be used to specify the parameters for downloading the data. The major parameters are listed below:

  • sites: The site number for the USGS gage, which is a unique 8- to 15-digit identification number for each site. ‘sites’ can be a string value for one site or a list of string values for multiple sites.

  • start: The start date of the time series data (example string format as “YYYY-MM-DD”).

  • end: The end date of the time series data (example string format as “YYYY-MM-DD”).

  • service: The service option for data download. Options include ‘dv’- daily mean value and ‘iv’- instantaneous value.

  • parameterCd: The parameter code defined by USGS for the variables (e.g., 00060 represents Stream flow). ‘parameterCd’ can be a string value for one variable or a list of string values for multiple variables.

  • output: The file path of the NetCDF file to store the data.