Skip to content

Commit 8148930

Browse files
author
Joe Hamman
committed
major overhaul of package:
- renamed package from vicpy to tonic - reog of package structure - command line utils are handled via single vic_utils script using subprocessors. - some pep8 syntax and styling updates
1 parent 0440a5b commit 8148930

30 files changed

+795
-454
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,5 @@ plots/
5151
ehthumbs.db
5252
Thumbs.db
5353
*.sublime-*
54+
55+
tonic.egg-info

.travis.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
language: python
2+
3+
python:
4+
- "2.6"
5+
- "2.7"
6+
- "3.3"
7+
8+
install:
9+
- python setup.py install
10+
11+
# command to run tests
12+
script:
13+
- vic_utils -h

README.md

+22-32
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,33 @@
1-
VICpy
1+
TONIC
22
=====
33

4-
A pre/post processing toolbox for the [VIC model](https://github.com/UW-Hydro/VIC)
4+
`tonic` is a toolkit for working with distributed hydrologic models and their output.
55

6-
Truely a work in progress...
6+
This is truely a work in progress...
77

8-
This is a library of python scripts to go along with the pre/post
9-
processing of VIC model forcings/parameters/outputs.
8+
## Models:
9+
1. [the Vairable Infiltration Capacity (VIC) model](https://github.com/UW-Hydro/VIC)
10+
1. [the Community Land Model (CLM)](http://www.cgd.ucar.edu/tss/clm/)
11+
1. [the Unified Land Model (ULM)](https://github.com/UW-Hydro/ULM)
12+
1. [the Precipitation Runoff Modeling System (PRMS)](http://wwwbrr.cr.usgs.gov/projects/SW_MoWS/PRMS.html)
13+
1. [the Noah Land Surface Model](http://www.ral.ucar.edu/research/land/technology/lsm.php)
14+
1. [the Structure for Unifying Multiple Modeling Alternatives (SUMMA)](http://www.ral.ucar.edu/projects/summa/)
1015

11-
Right now this is just a collection of a few scripts but as the toolbox grows,
12-
a more formal structure may be put together.
16+
## Scripts:
17+
`tonic` currently has 1 script available for use on the command line.
1318

14-
Most of the tools contained here are run from the command line and use a combination of command line arguments and configuration files. For tool specific usage try raising the help flag, -h (e.g. vic2netcdf.py -h).
19+
**vic_utils**: is a utility script that runs a number of VIC related processing tools. Once `tonic` is installed, `vic_utils` will be available in your path. Run `vic_utils -h` for a description of the utilities available.
1520

16-
-----
21+
## Install:
22+
Dependencies:
23+
- python 3
24+
- netCDF4
25+
- xray
26+
- matplotlib
27+
- basemap
28+
- pandas
1729

18-
### vic2netcdf.py
19-
This tool converts binary or ASCII VIC output to a netCDF format. Options and settings are input via configuration file (e.g. VIC2nc_example.cfg).
20-
21-
Usage: `vic2netcdf.py some_config_file.cfg`
22-
23-
-----
24-
25-
### netcdf2vic.py
26-
This tool converts netCDF meteorological forcings to VIC binary or ASCII format. Options and settings are input via configuration file (e.g. example_netcdf2vic.cfg).
27-
28-
Usage: `netcdf2vic.py some_config_file.cfg`
29-
30-
-----
31-
32-
### grid_params.py
33-
This tool grids VIC soil, snow, and vegetation parameter files and stores them in a single netCDF file. This allows for easy viewing of parameters using tools like [ncview](http://meteora.ucsd.edu/~pierce/ncview_home_page.html). This tool take a list of command line arguments:
34-
35-
Usage:
36-
For soil only: `grid_params.py --soil_file=global_soil_param_new -o outfile.nc`
37-
38-
For soil and veg: `grid_params.py -s global_soil_param_new -o outfile.nc -v global_lai_0.25deg.txt`
39-
40-
-----
30+
To install `tonic`, run `python setup.py install` from this directory.
4131

4232
Questions? Sure, Joe Hamman - jhamman at hydro.washington.edu
4333

scripts/vicpy scripts/vic_utils

+24-12
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#!/usr/bin/env python
22
# PYTHON_ARGCOMPLETE_OK
33

4-
"""VICpy command line interface"""
4+
"""tonic - vic_utils command line interface"""
55
from __future__ import print_function
6-
# import argcomplete
76
import argparse
87
import subprocess
9-
from vic import version, netcdf2vic, compare_soil_params, grid_params, \
8+
from tonic import version
9+
from tonic.models.vic import netcdf2vic, compare_soil_params, grid_params, \
1010
ncparam2ascii, vic2netcdf
1111

1212

@@ -17,13 +17,15 @@ def main():
1717
"""
1818
# ---------------------------------------------------------------- #
1919
# create the top-level parser
20-
parser = argparse.ArgumentParser(prog='VICpy',
21-
description='Python toolkit for the '
22-
'VIC model')
20+
format = lambda prog: argparse.HelpFormatter(prog, max_help_position=25)
21+
22+
parser = argparse.ArgumentParser(prog='vic_utils',
23+
description='vic_utils command line '
24+
'interface.',
25+
formatter_class=format)
2326
parser.add_argument('--version', action='version',
2427
version=version.short_version)
25-
subparsers = parser.add_subparsers(title='VICpy subcommands')
26-
subparsers.completer = complete_subparser_action
28+
subparsers = parser.add_subparsers(title='vic_utils subcommands')
2729
# ---------------------------------------------------------------- #
2830

2931
# ---------------------------------------------------------------- #
@@ -40,8 +42,8 @@ def main():
4042
# ---------------------------------------------------------------- #
4143
# create the parser for the "grid_params" command
4244
grid_params_parser = subparsers.add_parser('grid_params',
43-
help=grid_params.help,
44-
description=grid_params.description)
45+
help=grid_params.help,
46+
description=grid_params.description)
4547
grid_params_parser.set_defaults(func=grid_params._run)
4648
grid_params_parser.add_argument("soil_file",
4749
type=str,
@@ -177,14 +179,24 @@ def main():
177179
help=vic2netcdf.help,
178180
description=vic2netcdf.description)
179181
vic2netcdf_parser.set_defaults(func=vic2netcdf._run)
180-
vic2netcdf_parser.add_argument("config",
182+
vic2netcdf_parser.add_argument("config_file",
181183
type=str,
182184
help="Input vic2netcdf Configuration File")
185+
vic2netcdf_parser.add_argument("--create_batch", type=str,
186+
choices=['days', 'months',
187+
'years', 'variables'],
188+
default=False,
189+
help="Create a batch of config files")
190+
vic2netcdf_parser.add_argument("--batch_dir", type=str, default="./",
191+
help="Location to put batch config files")
183192
# ---------------------------------------------------------------- #
184193

185194
# argcomplete.autocomplete(parser)
186195
args = parser.parse_args()
187-
args.func(args)
196+
try:
197+
args.func(args)
198+
except AttributeError:
199+
parser.print_help()
188200
return
189201
# -------------------------------------------------------------------- #
190202

setup.py

+9-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env python
22
import os
33
import re
44
import sys
@@ -27,7 +27,7 @@ def write_version_py(filename=None):
2727
"""
2828
if not filename:
2929
filename = os.path.join(
30-
os.path.dirname(__file__), 'vic', 'version.py')
30+
os.path.dirname(__file__), 'tonic', 'version.py')
3131

3232
a = open(filename, 'w')
3333
try:
@@ -60,9 +60,9 @@ def write_version_py(filename=None):
6060

6161
if pipe is None or pipe.returncode != 0:
6262
# no git, or not in git dir
63-
if os.path.exists('VICpy/version.py'):
63+
if os.path.exists('tonic/version.py'):
6464
warnings.warn("WARNING: Couldn't get git revision, using existing "
65-
"VICpy/version.py")
65+
"tonic/version.py")
6666
write_version = False
6767
else:
6868
warnings.warn("WARNING: Couldn't get git revision, using generic "
@@ -92,20 +92,12 @@ def write_version_py(filename=None):
9292

9393
# -------------------------------------------------------------------- #
9494
# Run Setup
95-
setup(name='VICpy',
95+
setup(name='tonic',
9696
version=FULLVERSION,
97-
description='VICpy is a Python toolkit for the VIC Hydrology Model',
98-
long_description='http://www.hydro.washington.edu/Lettenmaier/Models/VIC/Overview/ModelOverview.shtml',
97+
description='tonic is a Python toolkit for distributed hydrologic modeling',
9998
author='Joe Hamman',
10099
author_email='[email protected]',
101-
install_requires=['scipy >= 0.13', 'numpy >= 1.8',
102-
'netCDF4 >= 1.0.6', 'matplotlib >= 1.3.1'],
103-
tests_require=['pytest >= 2.5.2'],
104-
url='https://github.com/jhamman/VICpy',
105-
test_suite='pytest.collector',
106-
packages=['vic'],
107-
platform=['any'],
108-
# py_modules=['vic.forcing_tools', 'vic.param_tools',
109-
# 'vic.processing_tools'],
110-
scripts=['scripts/vicpy'])
100+
url='https://github.com/jhamman/tonic',
101+
packages=['tonic', 'tonic.models', 'tonic.data_tools'],
102+
scripts=['scripts/vic_utils'])
111103
# -------------------------------------------------------------------- #

tonic/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .version import version as __version__

tonic/data_tools/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .vic import VIC, VIC_RuntimeError
2+
from .testing import VIC_TestError
3+
from .version import version as __version__
File renamed without changes.

tonic/io.py

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/usr/bin/env python
2+
"""Input/Output functions"""
3+
from netCDF4 import Dataset
4+
try:
5+
from cyordereddict import OrderedDict
6+
except:
7+
from collections import OrderedDict
8+
try:
9+
from configparser import SafeConfigParser
10+
except:
11+
from ConfigParser import SafeConfigParser
12+
import configobj
13+
14+
15+
# -------------------------------------------------------------------- #
16+
def read_config(config_file, default_config=None):
17+
"""
18+
Return a dictionary with subdictionaries of all configFile options/values
19+
"""
20+
config = SafeConfigParser()
21+
config.optionxform = str
22+
config.read(config_file)
23+
sections = config.sections()
24+
dict1 = OrderedDict()
25+
for section in sections:
26+
options = config.options(section)
27+
dict2 = OrderedDict()
28+
for option in options:
29+
dict2[option] = config_type(config.get(section, option))
30+
dict1[section] = dict2
31+
32+
if default_config is not None:
33+
for name, section in dict1.items():
34+
if name in default_config.keys():
35+
for option, key in default_config[name].items():
36+
if option not in section.keys():
37+
dict1[name][option] = key
38+
39+
return dict1
40+
# -------------------------------------------------------------------- #
41+
42+
43+
# -------------------------------------------------------------------- #
44+
def read_configobj(config_file, default_config=None):
45+
"""
46+
Return a dictionary with nested dictionaries
47+
"""
48+
49+
config = configobj.ConfigObj(config_file)
50+
51+
config = type_configobj(config)
52+
53+
return config
54+
# -------------------------------------------------------------------- #
55+
56+
57+
# -------------------------------------------------------------------- #
58+
def type_configobj(d):
59+
"""recursively loop through dictionary calling config_type"""
60+
for k, v in d.items():
61+
if isinstance(v, dict):
62+
type_configobj(v)
63+
else:
64+
d[k] = config_type(v)
65+
return d
66+
# -------------------------------------------------------------------- #
67+
68+
69+
# -------------------------------------------------------------------- #
70+
def config_type(value):
71+
"""
72+
Parse the type of the configuration file option.
73+
First see the value is a bool, then try float, finally return a string.
74+
"""
75+
val_list = [x.strip() for x in value.split(',')]
76+
if len(val_list) == 1:
77+
value = val_list[0]
78+
if value in ['true', 'True', 'TRUE', 'T']:
79+
return True
80+
elif value in ['false', 'False', 'FALSE', 'F']:
81+
return False
82+
elif value in ['none', 'None', 'NONE', '']:
83+
return None
84+
else:
85+
try:
86+
return int(value)
87+
except:
88+
pass
89+
try:
90+
return float(value)
91+
except:
92+
return value
93+
else:
94+
try:
95+
return list(map(int, val_list))
96+
except:
97+
pass
98+
try:
99+
return list(map(float, val_list))
100+
except:
101+
return val_list
102+
# -------------------------------------------------------------------- #
103+
104+
105+
# -------------------------------------------------------------------- #
106+
def read_netcdf(nc_file, variables=[], coords=False, verbose=True):
107+
"""
108+
Read data from input netCDF. Will read all variables if none provided.
109+
Will also return all variable attributes.
110+
Both variables (data and attributes) are returned as dictionaries named by
111+
variable.
112+
"""
113+
114+
f = Dataset(nc_file, 'r')
115+
116+
if variables == []:
117+
variables = f.variables.keys()
118+
119+
if verbose:
120+
print('Reading input data variables: '
121+
' {0} from file: {1}'.format(variables, nc_file))
122+
123+
d = OrderedDict()
124+
a = OrderedDict()
125+
126+
if coords:
127+
if isinstance(variables, str):
128+
d[variables] = f.variables[variables][coords]
129+
a[variables] = f.variables[variables].__dict__
130+
else:
131+
for var in variables:
132+
d[var] = f.variables[var][coords]
133+
a[var] = f.variables[var].__dict__
134+
else:
135+
if isinstance(variables, str):
136+
d[variables] = f.variables[variables][:]
137+
a[variables] = f.variables[variables].__dict__
138+
else:
139+
for var in variables:
140+
d[var] = f.variables[var][:]
141+
a[var] = f.variables[var].__dict__
142+
f.close()
143+
return d, a
144+
# -------------------------------------------------------------------- #
File renamed without changes.

tonic/models/clm/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import warnings
2+
3+
warnings.warn('clm module is currently empty')

tonic/models/noah/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import warnings
2+
3+
warnings.warn('noah module is currently empty')

tonic/models/prms/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import warnings
2+
3+
warnings.warn('prms module is currently empty')

tonic/models/summa/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import warnings
2+
3+
warnings.warn('summa module is currently empty')

tonic/models/ulm/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import warnings
2+
3+
warnings.warn('ulm module is currently empty')

tonic/models/vic/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)