Converting parameters from ASCII VIC 4 format to netCDF VIC 5 Image Driver Format
This Jupyter Notebook outlines one approach to converting VIC parameters from ASCII to netCDF format. For this tutorial, we'll convert three datasets from ASCII to netCDF:
All of these datasets include the following parameter sets:
For each of the parameter sets above, we'll be producing two files:
In [1]:
%matplotlib inline
import os
import getpass
from datetime import datetime
import numpy as np
import xarray as xr
import matplotlib.pyplot as plt
# For more information on tonic, see: https://github.com/UW-Hydro/tonic/
import tonic.models.vic.grid_params as gp
# Metadata to be used later
user = getpass.getuser()
now = datetime.now()
print('python version : %s' % os.sys.version)
print('numpy version : %s' % np.version.full_version)
print('xarray version : %s' % xr.version.version)
print('User : %s' % user)
print('Date/Time : %s' % now)
In [2]:
# Set the path to the datasets here
dpath = './' # root input data path
opath = './' # output data path
ldpath = os.path.join(dpath, 'Livneh_0.0625_NLDAS') # Path to Livneh Parameters
gdpath = os.path.join(dpath, 'Nijssen_0.5_Global') # Path to Global Parameters
mdpath = os.path.join(dpath, 'Maurer_0.125_NLDAS') # Path to Maurer Parameters
Along with the VIC model parameters, we also need a domain file that describes the spatial extent and active grid cells in the model domain. The domain file must exactly match the parameters and forcings. The Livneh dataset includes a DEM file in netCDF format that we can use to construct the domain file.
Steps:
cdo
In [3]:
dom_file = os.path.join(opath, 'domain.vic.global0.0625deg.%s.nc' % now.strftime('%Y%m%d'))
dem = xr.open_dataset(os.path.join(ldpath, 'Composite.DEM.NLDAS.mex.0625.nc'))
dom_ds = xr.Dataset()
# Set global attributes
dom_ds.attrs['title'] = 'VIC domain data'
dom_ds.attrs['Conventions'] = 'CF-1.6'
dom_ds.attrs['history'] = 'created by %s, %s' % (user, now)
dom_ds.attrs['user_comment'] = 'VIC domain data'
dom_ds.attrs['source'] = 'generated from VIC North American 1/16 deg. model parameters, see Livneh et al. (2015) for more information'
# since we have it, put the elevation in the domain file
dom_ds['elev'] = dem['Band1']
dom_ds['elev'].attrs['long_name'] = 'gridcell_elevation'
dom_ds['elev'].attrs['units'] = 'm'
# Get the mask variable
dom_ds['mask'] = dem['Band1'].notnull().astype(np.int)
dom_ds['mask'].attrs['long_name'] = 'domain mask'
dom_ds['mask'].attrs['comment'] = '0 indicates cell is not active'
# For now, the frac variable is going to be just like the mask
dom_ds['frac'] = dom_ds['mask'].astype(np.float)
dom_ds['frac'].attrs['long_name'] = 'fraction of grid cell that is active'
dom_ds['frac'].attrs['units'] = '1'
# Save the output domain to a temporary file.
dom_ds.to_netcdf('temp.nc')
dom_ds.close()
In [4]:
# This shell command uses cdo step calculates the grid cell area
!cdo -O gridarea temp.nc area.nc
!rm temp.nc
In [5]:
# This step extracts the area from the temporary area.nc file
area = xr.open_dataset('area.nc')['cell_area']
dom_ds['area'] = area
# Write the final domain file
dom_ds.to_netcdf(dom_file)
dom_ds.close()
# Document the domain and plot
print(dom_ds)
dom_ds['mask'].plot()
Out[5]:
VIC 5 uses the same parameters as VIC 4. The following steps will read/parse the ASCII formatted parameter files and construct the netCDF formatted parameter file. We'll use the domain file constructed in the previous step to help define the spatial grid.
Steps:
In [6]:
soil_file = os.path.join(ldpath, 'vic.nldas.mexico.soil.txt')
snow_file = os.path.join(ldpath, 'vic.nldas.mexico.snow.txt.L13')
veg_file = os.path.join(ldpath, 'vic.nldas.mexico.veg.txt')
vegl_file = os.path.join(ldpath, 'LDAS_veg_lib')
out_file = os.path.join(opath, 'livneh_nldas.mexico_vic_5.0.0_parameters.nc')
# Set options that define the shape/type of parameters
cols = gp.Cols(nlayers=3,
snow_bands=5,
organic_fract=False,
spatial_frost=False,
spatial_snow=False,
july_tavg_supplied=False,
veglib_fcan=False,
veglib_photo=False)
n_veg_classes = 11
vegparam_lai = True
lai_src = 'FROM_VEGPARAM'
# ----------------------------------------------------------------- #
# Read the soil parameters
soil_dict = gp.soil(soil_file, c=gp.Cols(nlayers=3))
# Read the snow parameters
snow_dict = gp.snow(snow_file, soil_dict, c=cols)
# Read the veg parameter file
veg_dict = gp.veg(veg_file, soil_dict,
vegparam_lai=vegparam_lai, lai_src=lai_src,
veg_classes=n_veg_classes)
# Read the veg library file
veg_lib, lib_bare_idx = gp.veg_class(vegl_file, c=cols)
# Determine the grid shape
target_grid, target_attrs = gp.read_netcdf(dom_file)
for old, new in [('lon', 'xc'), ('lat', 'yc')]:
target_grid[new] = target_grid.pop(old)
target_attrs[new] = target_attrs.pop(old)
# Grid all the parameters
grid_dict = gp.grid_params(soil_dict,
target_grid,
version_in='4.1.2.c',
vegparam_lai=vegparam_lai,
lib_bare_idx=lib_bare_idx,
lai_src=lai_src,
veg_dict=veg_dict,
veglib_dict=veg_lib,
snow_dict=snow_dict,
lake_dict=None)
# Write a netCDF file with all the parameters
gp.write_netcdf(out_file,
target_attrs,
target_grid=target_grid,
vegparam_lai=vegparam_lai,
lai_src=lai_src,
soil_grid=grid_dict['soil_dict'],
snow_grid=grid_dict['snow_dict'],
veg_grid=grid_dict['veg_dict'])
In [7]:
soil_file = os.path.join(gdpath, 'global_soil_param_new')
snow_file = os.path.join(gdpath, 'global_snowbands_new')
veg_file = os.path.join(gdpath, 'global_veg_param_new')
vegl_file = os.path.join(gdpath, 'world_veg_lib.txt')
out_file = os.path.join(gdpath, 'global_0.5deg.vic_5.0.0_parameters.nc')
# Set options that define the shape/type of parameters
cols = gp.Cols(nlayers=3,
snow_bands=5,
organic_fract=False,
spatial_frost=False,
spatial_snow=False,
july_tavg_supplied=False,
veglib_fcan=False,
veglib_photo=False)
n_veg_classes = 11
root_zones = 2
vegparam_lai = True
lai_src = 'FROM_VEGPARAM'
# ----------------------------------------------------------------- #
# Read the soil parameters
soil_dict = gp.soil(soil_file, c=cols)
# Read the snow parameters
snow_dict = gp.snow(snow_file, soil_dict, c=cols)
# Read the veg parameter file
veg_dict = gp.veg(veg_file, soil_dict,
vegparam_lai=vegparam_lai, lai_src=lai_src,
veg_classes=n_veg_classes, max_roots=root_zones)
# Read the veg library file
veg_lib, lib_bare_idx = gp.veg_class(vegl_file, c=cols)
# Determine the grid shape
target_grid, target_attrs = gp.calc_grid(soil_dict['lats'], soil_dict['lons'])
# Grid all the parameters
grid_dict = gp.grid_params(soil_dict, target_grid, version_in='4',
vegparam_lai=vegparam_lai, lai_src=lai_src,
lib_bare_idx=lib_bare_idx,
veg_dict=veg_dict, veglib_dict=veg_lib,
snow_dict=snow_dict, lake_dict=None)
# Write a netCDF file with all the parameters
gp.write_netcdf(out_file,
target_attrs,
target_grid=target_grid,
vegparam_lai=vegparam_lai,
lai_src=lai_src,
soil_grid=grid_dict['soil_dict'],
snow_grid=grid_dict['snow_dict'],
veg_grid=grid_dict['veg_dict'])
In [8]:
dom_ds = xr.Dataset()
# Set global attributes
dom_ds.attrs['title'] = 'VIC domain data'
dom_ds.attrs['Conventions'] = 'CF-1.6'
dom_ds.attrs['history'] = 'created by %s, %s' % (user, now)
dom_ds.attrs['user_comment'] = 'VIC domain data'
dom_ds.attrs['source'] = 'generated from VIC Global 0.5 deg. model parameters, see Nijssen et al. (2001) for more information'
In [9]:
dom_file = os.path.join(opath, 'domain.vic.global0.5deg.%s.nc' % now.strftime('%Y%m%d'))
# Get the mask variable
dom_ds['mask'] = xr.DataArray(target_grid['mask'], coords={'lat': target_grid['yc'],
'lon': target_grid['xc']},
dims=('lat', 'lon', ))
# For now, the frac variable is going to be just like the mask
dom_ds['frac'] = dom_ds['mask'].astype(np.float)
dom_ds['frac'].attrs['long_name'] = 'fraction of grid cell that is active'
dom_ds['frac'].attrs['units'] = '1'
# Set variable attributes
for k, v in target_attrs.items():
if k == 'xc':
k = 'lon'
elif k == 'yc':
k = 'lat'
dom_ds[k].attrs = v
# Write temporary file for gridarea calculation
dom_ds.to_netcdf('temp.nc')
In [10]:
# This step calculates the grid cell area
!cdo -O gridarea temp.nc area.nc
!rm temp.nc
In [11]:
# Extract the area variable
area = xr.open_dataset('area.nc').load()['cell_area']
dom_ds['area'] = area
# write the domain file
dom_ds.to_netcdf(dom_file)
dom_ds.close()
# document and plot the domain
print(dom_ds)
dom_ds.mask.plot()
Out[11]:
In [12]:
!rm area.nc
In [13]:
soil_file = os.path.join(mdpath, 'soil', 'us_all.soil.wsne')
snow_file = os.path.join(mdpath, 'snow', 'us_all.snowbands.wsne')
veg_file = os.path.join(mdpath, 'veg', 'us_all.veg.wsne')
vegl_file = os.path.join(ldpath, 'LDAS_veg_lib') # from livneh
out_file = os.path.join(mdpath, 'nldas_0.125deg.vic_5.0.0_parameters.nc')
cols = gp.Cols(nlayers=3,
snow_bands=5,
organic_fract=False,
spatial_frost=False,
spatial_snow=False,
july_tavg_supplied=False,
veglib_fcan=False,
veglib_photo=False)
n_veg_classes = 11
root_zones = 2
vegparam_lai = True
lai_src = 'FROM_VEGPARAM'
# ----------------------------------------------------------------- #
# Read the soil parameters
soil_dict = gp.soil(soil_file, c=cols)
# Read the snow parameters
snow_dict = gp.snow(snow_file, soil_dict, c=cols)
# Read the veg parameter file
veg_dict = gp.veg(veg_file, soil_dict,
vegparam_lai=vegparam_lai, lai_src=lai_src,
veg_classes=n_veg_classes, max_roots=root_zones)
# Read the veg library file
veg_lib, lib_bare_idx = gp.veg_class(vegl_file, c=cols)
# Determine the grid shape
target_grid, target_attrs = gp.calc_grid(soil_dict['lats'], soil_dict['lons'])
# Grid all the parameters
grid_dict = gp.grid_params(soil_dict, target_grid, version_in='4',
vegparam_lai=vegparam_lai, lai_src=lai_src,
lib_bare_idx=lib_bare_idx,
veg_dict=veg_dict, veglib_dict=veg_lib,
snow_dict=snow_dict, lake_dict=None)
# Write a netCDF file with all the parameters
gp.write_netcdf(out_file,
target_attrs,
target_grid=target_grid,
vegparam_lai=vegparam_lai,
lai_src=lai_src,
soil_grid=grid_dict['soil_dict'],
snow_grid=grid_dict['snow_dict'],
veg_grid=grid_dict['veg_dict'])
In [14]:
dom_ds = xr.Dataset()
# Set global attributes
dom_ds.attrs['title'] = 'VIC domain data'
dom_ds.attrs['Conventions'] = 'CF-1.6'
dom_ds.attrs['history'] = 'created by %s, %s' % (user, now)
dom_ds.attrs['user_comment'] = 'VIC domain data'
dom_ds.attrs['source'] = 'generated from VIC CONUS 1.8 deg model parameters, see Maurer et al. (2002) for more information'
dom_file = os.path.join(opath, 'domain.vic.conus0.0125deg.%s.nc' % now.strftime('%Y%m%d'))
# Get the mask variable
dom_ds['mask'] = xr.DataArray(target_grid['mask'], coords={'lat': target_grid['yc'],
'lon': target_grid['xc']},
dims=('lat', 'lon', ))
# For now, the frac variable is going to be just like the mask
dom_ds['frac'] = dom_ds['mask'].astype(np.float)
dom_ds['frac'].attrs['long_name'] = 'fraction of grid cell that is active'
dom_ds['frac'].attrs['units'] = '1'
# Set variable attributes
for k, v in target_attrs.items():
if k == 'xc':
k = 'lon'
elif k == 'yc':
k = 'lat'
dom_ds[k].attrs = v
# Write temporary file for gridarea calculation
dom_ds.to_netcdf('temp.nc')
In [15]:
# This step calculates the grid cell area
!cdo -O gridarea temp.nc area.nc
!rm temp.nc
In [16]:
# Extract the area variable
area = xr.open_dataset('area.nc').load()['cell_area']
dom_ds['area'] = area
# write the domain file
dom_ds.to_netcdf(dom_file)
dom_ds.close()
# document and plot the domain
print(dom_ds)
dom_ds.mask.plot()
Out[16]:
In [17]:
plt.close('all')
In [ ]: