Source code for dataretrieval.nadp

"""
Tools for retrieving data from the National Atmospheric Deposition Program
(NADP) including the National Trends Network (NTN), the Mercury Deposition
Network (MDN).

National Trends Network
-----------------------
The  NTN provides long-term records of precipitation chemistry across the
United States. See https://nadp.slh.wisc.edu/ntn for more info.

Mercury Deposition Network
--------------------------
The MDN provides long-term records of total mercury (Hg) concentration and
deposition in precipitation in the United States and Canada. For more
information visit https://nadp.slh.wisc.edu/networks/mercury-deposition-network/

Notes
-----
Gridded data on NADP is served as zipped tif files. Functions in this module
will either download and extract the data, when a path is specified, or open
the data as a GDAL memory-mapped file when no path is specified.

.. todo::

    - include AIRMoN, AMNet, and AMoN
    - flexible handling of strings for parameters and measurement types
    - add errorchecking
    - add tests

"""

import io
import os
import re
import zipfile
from os.path import basename

import requests

NADP_URL = 'https://nadp.slh.wisc.edu'
NADP_MAP_EXT = 'filelib/maps'

NTN_CONC_PARAMS = ['pH', 'So4', 'NO3', 'NH4', 'Ca', 'Mg', 'K', 'Na', 'Cl', 'Br']
NTN_DEP_PARAMS = [
    'H',
    'So4',
    'NO3',
    'NH4',
    'Ca',
    'Mg',
    'K',
    'Na',
    'Cl',
    'Br',
    'N',
    'SPlusN',
]

NTN_MEAS_TYPE = ['conc', 'dep', 'precip']  # concentration or deposition


[docs] class NADP_ZipFile(zipfile.ZipFile): """Extend zipfile.ZipFile for working on data from NADP"""
[docs] def tif_name(self): """Get the name of the tif file in the zip file.""" filenames = self.namelist() r = re.compile('.*tif$') tif_list = list(filter(r.match, filenames)) return tif_list[0]
[docs] def tif(self): """Read the tif file in the zip file.""" return self.read(self.tif_name())
[docs] def get_annual_MDN_map(measurement_type, year, path): """Download a MDN map from NDAP. This function looks for a zip file containing gridded information at: https://nadp.slh.wisc.edu/maps-data/mdn-gradient-maps/. The function will download the zip file and extract it, exposing the tif file if a path is provided. Parameters ---------- measurement_type: string The type of measurement (concentration or deposition) as a string, either 'conc' or 'dep' respectively. year: string Year as a string 'YYYY' path: string Download directory. Returns ------- path: string Path that zip file was extracted into if path was specified. Examples -------- .. code:: >>> # get map of mercury concentration in 2010 and extract it to a path >>> data_path = dataretrieval.nadp.get_annual_MDN_map( ... measurement_type='conc', year='2010', path='somepath' ... ) """ url = f'{NADP_URL}/{NADP_MAP_EXT}/MDN/grids/' filename = f'Hg_{measurement_type}_{year}.zip' z = get_zip(url, filename) if path: z.extractall(path) return f'{path}{os.sep}{basename(filename)}'
[docs] def get_annual_NTN_map(measurement_type, measurement=None, year=None, path='.'): """Download a NTN map from NDAP. This function looks for a zip file containing gridded information at: https://nadp.slh.wisc.edu/maps-data/ntn-gradient-maps/. The function will download the zip file and extract it, exposing the tif file at the provided path. .. note:: Measurement type abbreviations for concentration and deposition are all lower-case, but for precipitation data, the first letter must be capitalized! Parameters ---------- measurement : string The measured constituent to return. measurement_type : string The type of measurement, 'conc', 'dep', or 'Precip', which represent concentration, deposition, or precipitation respectively. year : string Year as a string 'YYYY' path : string Download directory, defaults to current directory if not specified. Returns ------- path: string Path that zip file was extracted into if path was specified. Examples -------- .. code:: >>> # get a map of precipitation in 2015 and extract it to a path >>> data_path = dataretrieval.nadp.get_annual_NTN_map( ... measurement_type='Precip', year='2015', path='somepath' ... ) """ url = f'{NADP_URL}/{NADP_MAP_EXT}/NTN/grids/{year}/' filename = f'{measurement_type}_{year}.zip' if measurement: filename = f'{measurement}_{filename}' z = get_zip(url, filename) if path: z.extractall(path) return f'{path}{os.sep}{basename(filename)}'
[docs] def get_zip(url, filename): """Gets a ZipFile at url and returns it Parameters ---------- url : string URL to zip file filename : string Name of zip file Returns ------- ZipFile .. todo:: finish docstring """ req = requests.get(url + filename) req.raise_for_status() # z = zipfile.ZipFile(io.BytesIO(req.content)) z = NADP_ZipFile(io.BytesIO(req.content)) return z