diff --git a/.travis.yml b/.travis.yml index 5e08005..b7c5334 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ matrix: - python: 2.7 - python: 3.4 - python: 3.5 + - python: 3.6 # Setup anaconda before_install: @@ -23,13 +24,13 @@ before_install: - conda config --set always_yes yes --set changeps1 no - conda update -q conda - conda info -a + # Install packages install: - - conda create --yes --name=test python=$TRAVIS_PYTHON_VERSION numpy scipy pandas netcdf4 matplotlib pytest + - conda create --yes --name=test python=$TRAVIS_PYTHON_VERSION numpy scipy pandas netcdf4 matplotlib pytest -c conda-forge - source activate test - # - conda install -c https://conda.anaconda.org/ioos cdo - # - pip install cdo - python setup.py install + # Run test script: - py.test diff --git a/README.md b/README.md index 463b06a..ea791e6 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@ # RVIC Streamflow Routing Model - - | VIC Links & Badges | | |------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | VIC Documentation | [![Documentation Status](https://readthedocs.org/projects/rvic/badge/?version=latest)](https://readthedocs.org/projects/rvic/?badge=latest) | | Travis Build | [![Build Status](https://travis-ci.org/UW-Hydro/RVIC.svg?branch=master)](https://travis-ci.org/UW-Hydro/RVIC) | | Code Health | [![Code Health](https://landscape.io/github/UW-Hydro/RVIC/master/landscape.svg?style=flat)](https://landscape.io/github/UW-Hydro/RVIC/master) | | License | [![GitHub license](https://img.shields.io/badge/license-GPLv3-blue.svg)](https://raw.githubusercontent.com/UW-Hydro/RVIC/master/LICENSE.txt) | -| Current Release DOI | [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.32620.svg)](http://dx.doi.org/10.5281/zenodo.32620) | - +| Current Release DOI | [![DOI](https://zenodo.org/badge/11590212.svg)](https://zenodo.org/badge/latestdoi/11590212) | The RVIC streamflow routing model is an adapted version of the model the model typically used as a post-processor with the Variable Infiltration Capacity (VIC) hydrology model. The routing model is a source-to-sink model that solves a linearized version of the Saint-Venant equations. This model, developed by Lohmann et al. (1996, 1998a, 1998b), has been used in many offline studies at a variety of spatial scales. Furthermore, the development of the impulse response functions (IRFs) is done as a preprocessing step, which considerably reduces the computation time in subsequent routing steps. diff --git a/docs/development/whats_new.md b/docs/development/whats_new.md index adba2d5..bfa8678 100644 --- a/docs/development/whats_new.md +++ b/docs/development/whats_new.md @@ -1,5 +1,18 @@ # What's New +v1.1.1 (7 February 2017 + +This release contains a number of bug and compatibility fixes. + +### Enhancements + +- Ability to pass a dictionary to top level RVIC functions (instead of only a file path). This allows for the generation of large ensembles of RVIC simulations in an interactive environment ([GH78](https://github.com/UW-Hydro/RVIC/pull/78)). + +### Bug Fixes + +- Fixed bug that in `tools/fraction2domain.bash` by using a temporary variable name ([GH88](https://github.com/UW-Hydro/RVIC/pull/88)). +- Fixed off-by-one error in `history.py` ([GH86](https://github.com/UW-Hydro/RVIC/pull/86)). + v1.1.0 (25 October 2015) This release contains a number of bug and compatibility fixes. diff --git a/docs/user-guide/api.md b/docs/user-guide/api.md index 69b755f..f79c12c 100644 --- a/docs/user-guide/api.md +++ b/docs/user-guide/api.md @@ -6,6 +6,8 @@ Almost all of RVIC is available via a public API. import rvic ``` +`rvic.parameters.parameters` and `rvic.convolution.convolution` both support either a path (string) to an INI style configuration file or a dictionary including configuration options. This feature is quite useful when generating ensembles of RVIC simulations. + Most of the internals of RVIC are stored int the `rvic.core` module: ```Python diff --git a/mkdocs.yml b/mkdocs.yml index 5ccdf64..79e85d1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,7 @@ site_name: RVIC site_description: RVIC Streamflow Routing Model site_author: UW Hydro | Computational Hydrology -copyright: 'Copyright © 2015, University of Washington Computational Hydrology Group.' +copyright: 'Copyright © 2017, University of Washington Computational Hydrology Group.' repo_url: https://github.com/UW-Hydro/RVIC theme: readthedocs diff --git a/rvic/convolution.py b/rvic/convolution.py index eb656b7..fee3b93 100644 --- a/rvic/convolution.py +++ b/rvic/convolution.py @@ -31,26 +31,21 @@ # -------------------------------------------------------------------- # # Top Level Driver -def convolution(config_file): +def convolution(config): ''' Top level driver for RVIC convolution model. Parameters ---------- - config_file : str - Path to RVIC convolution configuration file. + config : str or dict. + Path to RVIC convolution configuration file or dictionary of + configuration options. ''' # ---------------------------------------------------------------- # # Initilize hist_tapes, data_model, rout_var, \ - time_handle, directories = convolution_init(config_file) - # ---------------------------------------------------------------- # - - # ---------------------------------------------------------------- # - # Setup the pool of processors - # if numofproc > 1: - # pool = LoggingPool(processes=numofproc) + time_handle, directories = convolution_init(config) # ---------------------------------------------------------------- # # ---------------------------------------------------------------- # @@ -69,7 +64,7 @@ def convolution(config_file): # -------------------------------------------------------------------- # # Initialize RVIC -def convolution_init(config_file): +def convolution_init(config): ''' Initialize the RVIC convolution routine @@ -85,8 +80,9 @@ def convolution_init(config_file): Parameters ---------- - config_file : str - Path to RVIC convolution configuration file. + config : str or dict + Path to RVIC convolution configuration file or dictionary of + configuration options. Returns ---------- @@ -109,7 +105,10 @@ def convolution_init(config_file): # ---------------------------------------------------------------- # # Read Configuration files - config_dict = read_config(config_file) + if isinstance(config, dict): + config_dict = config + else: + config_dict = read_config(config) # ---------------------------------------------------------------- # # ---------------------------------------------------------------- # diff --git a/rvic/core/history.py b/rvic/core/history.py index e8e1af1..df11bec 100644 --- a/rvic/core/history.py +++ b/rvic/core/history.py @@ -518,7 +518,7 @@ def __write_grid(self): f.createDimension('time', None) time = f.createVariable('time', self._ncprec, ('time',)) - time[:] = self._out_times[:self._out_data_i + 1] + time[:] = self._out_times[:self._out_data_i] for key, val in iteritems(share.time): if val: setattr(time, key, val.encode()) @@ -531,7 +531,7 @@ def __write_grid(self): time_bnds = f.createVariable('time_bnds', self._ncprec, ('time', 'nv',), **self.ncvaropts) - time_bnds[:, :] = self._out_time_bnds[:self._out_data_i + 1] + time_bnds[:, :] = self._out_time_bnds[:self._out_data_i] # ------------------------------------------------------------ # # ------------------------------------------------------------ # @@ -585,7 +585,7 @@ def __write_grid(self): for field in self._fincl: var = f.createVariable(field, self._ncprec, tcoords, **self.ncvaropts) - var[:, :] = self._out_data[field][:self._out_data_i + 1] + var[:, :] = self._out_data[field][:self._out_data_i] for key, val in iteritems(getattr(share, field)): if val: diff --git a/rvic/core/make_uh.py b/rvic/core/make_uh.py index aa8ba46..a504f65 100644 --- a/rvic/core/make_uh.py +++ b/rvic/core/make_uh.py @@ -192,8 +192,8 @@ def read_direction(fdr, dy, dx): ''' log.debug('Reading direction input and finding target row/columns') - to_y = np.zeros_like(fdr, dtype=np.int16) - to_x = np.zeros_like(fdr, dtype=np.int16) + to_y = np.zeros_like(fdr, dtype=np.int32) + to_x = np.zeros_like(fdr, dtype=np.int32) valid_dirs = list(dy.keys()) @@ -238,7 +238,7 @@ def search_catchment(to_y, to_x, pour_point, basin_ids, basin_id): # -1 - not in catchment # 0 - unknown # 1 - in catchment - in_catch = np.zeros_like(to_x, dtype=np.int16) - 1 + in_catch = np.zeros_like(to_x, dtype=np.int32) - 1 in_catch[byinds, bxinds] = 0 # set basin inds as 0 # temporary variables for tracking flow path diff --git a/rvic/core/param_file.py b/rvic/core/param_file.py index 742e927..56f28c5 100644 --- a/rvic/core/param_file.py +++ b/rvic/core/param_file.py @@ -73,7 +73,7 @@ def finish_params(outlets, dom_data, config_dict, directories): 'SUBSET_DAYS= 0, source_decomp_ind + assert outlet_decomp_ind.min() >= 0, outlet_decomp_ind # ---------------------------------------------------------------- # # ---------------------------------------------------------------- # @@ -322,7 +326,7 @@ def subset(outlets, subset_length=None): axis=1) outlet.offset = np.empty(outlet.unit_hydrograph.shape[1], - dtype=np.int16) + dtype=np.int32) out_uh = np.zeros((subset_length, outlet.unit_hydrograph.shape[1]), dtype=np.float64) @@ -402,23 +406,23 @@ def group(outlets, subset_length): gd['frac_sources'] = np.empty(n_sources, dtype=np.float64) gd['source_lon'] = np.empty(n_sources, dtype=np.float64) gd['source_lat'] = np.empty(n_sources, dtype=np.float64) - gd['source_x_ind'] = np.empty(n_sources, dtype=np.int16) - gd['source_y_ind'] = np.empty(n_sources, dtype=np.int16) - gd['source_decomp_ind'] = np.empty(n_sources, dtype=np.int16) - gd['source_time_offset'] = np.empty(n_sources, dtype=np.int16) - gd['source2outlet_ind'] = np.empty(n_sources, dtype=np.int16) + gd['source_x_ind'] = np.empty(n_sources, dtype=np.int32) + gd['source_y_ind'] = np.empty(n_sources, dtype=np.int32) + gd['source_decomp_ind'] = np.empty(n_sources, dtype=np.int32) + gd['source_time_offset'] = np.empty(n_sources, dtype=np.int32) + gd['source2outlet_ind'] = np.empty(n_sources, dtype=np.int32) # ---------------------------------------------------------------- # # ---------------------------------------------------------------- # # outlet specific inputs gd['outlet_lon'] = np.empty(n_outlets, dtype=np.float64) gd['outlet_lat'] = np.empty(n_outlets, dtype=np.float64) - gd['outlet_x_ind'] = np.empty(n_outlets, dtype=np.int16) - gd['outlet_y_ind'] = np.empty(n_outlets, dtype=np.int16) - gd['outlet_decomp_ind'] = np.empty(n_outlets, dtype=np.int16) - gd['outlet_number'] = np.empty(n_outlets, dtype=np.int16) + gd['outlet_x_ind'] = np.empty(n_outlets, dtype=np.int32) + gd['outlet_y_ind'] = np.empty(n_outlets, dtype=np.int32) + gd['outlet_decomp_ind'] = np.empty(n_outlets, dtype=np.int32) + gd['outlet_number'] = np.empty(n_outlets, dtype=np.int32) gd['outlet_name'] = np.empty(n_outlets, dtype='S{0}'.format(MAX_NC_CHARS)) - gd['outlet_upstream_gridcells'] = np.empty(n_outlets, dtype=np.int16) + gd['outlet_upstream_gridcells'] = np.empty(n_outlets, dtype=np.int32) gd['outlet_upstream_area'] = np.empty(n_outlets, dtype=np.float64) # ---------------------------------------------------------------- # diff --git a/rvic/core/plots.py b/rvic/core/plots.py index e5df0ec..902f66a 100644 --- a/rvic/core/plots.py +++ b/rvic/core/plots.py @@ -40,7 +40,7 @@ def uhs(data, title, case_id, plot_dir): plt.xlabel('timesteps') plt.ylabel('unit-hydrograph') fig.savefig(pfname) - + plt.close() return pfname # -------------------------------------------------------------------- # @@ -71,6 +71,7 @@ def _fractions_grid(data, dom_x, dom_y, title, case_id, plot_dir): plt.ylim([0, dom_y.shape[0]]) plt.xlim([0, dom_x.shape[1]]) fig.savefig(pfname) + plt.close() # ---------------------------------------------------------------- # return pfname # -------------------------------------------------------------------- # @@ -129,6 +130,7 @@ def _fractions_map(data, dom_x, dom_y, title, case_id, plot_dir): m.colorbar(cs, location='right', pad='5%') plt.title(title) fig.savefig(pfname) + plt.close() # ---------------------------------------------------------------- # return pfname # -------------------------------------------------------------------- # diff --git a/rvic/core/utilities.py b/rvic/core/utilities.py index 4cc2c92..66dbd1b 100644 --- a/rvic/core/utilities.py +++ b/rvic/core/utilities.py @@ -320,8 +320,10 @@ def read_domain(domain_dict, lat0_is_min=False): # ---------------------------------------------------------------- # # Create the cell_ids variable dom_mask = domain_dict['LAND_MASK_VAR'] - temp = np.arange(dom_data[dom_mask].size) - dom_data['cell_ids'] = temp.reshape(dom_data[dom_mask].shape) + dom_data['cell_ids'] = np.arange( + dom_data[dom_mask].size).reshape(dom_data[dom_mask].shape) + # Make sure the inds are all greater than zero, ref: Github #79 + assert dom_data['cell_ids'].min() >= 0 # ---------------------------------------------------------------- # # ---------------------------------------------------------------- # diff --git a/rvic/parameters.py b/rvic/parameters.py index 3123bc9..e98c7aa 100644 --- a/rvic/parameters.py +++ b/rvic/parameters.py @@ -33,14 +33,15 @@ # -------------------------------------------------------------------- # # Top level driver -def parameters(config_file, numofproc=1): +def parameters(config, numofproc=1): ''' Top level function for RVIC parameter generation function. Parameters ---------- - config_file : str - Path to RVIC parameters configuration file. + config : str or dict + Path to RVIC parameters configuration file or dictionary of + configuration options. numofproc : int Number of processors to use when developing RVIC parameters. ''' @@ -48,7 +49,7 @@ def parameters(config_file, numofproc=1): # ---------------------------------------------------------------- # # Initilize uh_box, fdr_data, fdr_vatts, dom_data, \ - outlets, config_dict, directories = gen_uh_init(config_file) + outlets, config_dict, directories = gen_uh_init(config) # ---------------------------------------------------------------- # # ---------------------------------------------------------------- # @@ -100,7 +101,7 @@ def parameters(config_file, numofproc=1): # -------------------------------------------------------------------- # -def gen_uh_init(config_file): +def gen_uh_init(config): '''Initialize RVIC parameters script. This function: @@ -113,8 +114,9 @@ def gen_uh_init(config_file): Parameters ---------- - config_file : str - Path to RVIC parameters configuration file. + config : str or dict + Path to RVIC parameters configuration file or dictionary of + configuration options. Returns ---------- @@ -138,7 +140,10 @@ def gen_uh_init(config_file): # ---------------------------------------------------------------- # # Read Configuration files - config_dict = read_config(config_file) + if isinstance(config, dict): + config_dict = config + else: + config_dict = read_config(config) # ---------------------------------------------------------------- # # ---------------------------------------------------------------- # @@ -158,7 +163,8 @@ def gen_uh_init(config_file): # ---------------------------------------------------------------- # # copy inputs to $case_dir/inputs and update configuration - config_dict = copy_inputs(config_file, directories['inputs']) + if not isinstance(config, dict): + config_dict = copy_inputs(config, directories['inputs']) options = config_dict['OPTIONS'] # ---------------------------------------------------------------- # @@ -570,6 +576,11 @@ def gen_uh_run(uh_box, fdr_data, fdr_vatts, dom_data, outlet, config_dict, outlet.cell_id_source = dom_data['cell_ids'][y, x] outlet.x_source = x outlet.y_source = y + + # Make sure the inds are all greater than zero, ref: Github #79 + assert all(outlet.cell_id_source >= 0) + assert all(outlet.x_source >= 0) + assert all(outlet.y_source >= 0) # ---------------------------------------------------------------- # return outlet # -------------------------------------------------------------------- # diff --git a/setup.py b/setup.py index 5fec1e1..d1fb387 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ MAJOR = 1 MINOR = 1 -MICRO = 0 +MICRO = 1 ISRELEASED = True VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) QUALIFIER = '' diff --git a/tests/unit/test_history.py b/tests/unit/test_history.py index 9768ff6..a015f61 100644 --- a/tests/unit/test_history.py +++ b/tests/unit/test_history.py @@ -5,6 +5,8 @@ from rvic.core.history import Tape +@pytest.mark.skipif(os.getenv('TRAVIS', 'false').lower() == 'true', + reason='on travis') @pytest.fixture() def rvar(scope='function'): dirname = os.path.dirname(__file__) @@ -14,6 +16,8 @@ def rvar(scope='function'): return rv +@pytest.mark.skipif(os.getenv('TRAVIS', 'false').lower() == 'true', + reason='on travis') def test_create_tape_instance(rvar): history_tape = Tape(1.25, 'test', rvar, grid_area=np.zeros((10, 11)), outtype='array') diff --git a/tests/unit/unit_test_data/gunnison_parameters_01.rvic.prm.BLMSA.20150226.nc b/tests/unit/unit_test_data/gunnison_parameters_01.rvic.prm.BLMSA.20150226.nc index cb26482..567c39b 100644 Binary files a/tests/unit/unit_test_data/gunnison_parameters_01.rvic.prm.BLMSA.20150226.nc and b/tests/unit/unit_test_data/gunnison_parameters_01.rvic.prm.BLMSA.20150226.nc differ diff --git a/tools/fraction2domain.bash b/tools/fraction2domain.bash index 6af772e..8cff556 100755 --- a/tools/fraction2domain.bash +++ b/tools/fraction2domain.bash @@ -52,13 +52,14 @@ echo 'done making area variable' # -------------------------------------------------------------------- # # Make land mask file (1 = land, 0 = not land) echo 'making mask variable' -ncap2 -O -v -s 'mask=frac' temp_frac.nc $temp_mask1 -ncap2 -O -v -s 'where(mask>0.0000001) mask=1; elsewhere mask=0;' $temp_mask1 $temp_mask -ncatted -O -a long_name,mask,a,c,"domain mask" $temp_mask -ncatted -O -a note,mask,a,c,"unitless" $temp_mask -ncatted -O -a comment,mask,a,c,"0 value indicates cell is not active" $temp_mask +ncap2 -O -v -s 'm=frac' $temp_frac $temp_mask1 +ncap2 -O -v -s 'where(m>0.0000001) m=1; elsewhere m=0;' $temp_mask1 $temp_mask +ncatted -O -a long_name,m,a,c,"domain mask" $temp_mask +ncatted -O -a note,m,a,c,"unitless" $temp_mask +ncatted -O -a comment,m,a,c,"0 value indicates cell is not active" $temp_mask -ncks -A -v mask $temp_mask $outfile +ncks -A -v m $temp_mask $outfile +ncrename -O -v m,mask $outfile $outfile echo 'done making mask variable' # -------------------------------------------------------------------- #