Download Daymet#
Daymet provides gridded meteorological data for North American at 1km spatial resolution with daily timestep from 1980 ~ present. website and user guide
Available variables:
Variable |
Description (units) |
---|---|
tmax |
Daily maximum 2-meter air temperature (°C) |
tmin |
Daily minimum 2-meter air temperature (°C) |
prcp |
Daily total precipitation (mm/day) |
srad |
Incident shortwave radiation flux density (W/m2) |
vp |
Water vapor pressure (Pa) |
swe |
Snow water equivalent (kg/m2) |
dayl |
Duration of the daylight period (seconds) |
Notes:
The Daymet calendar is based on a standard calendar year. All Daymet years, including leap years, have 365 days. Keep this in mind during post-processing of model results! For leap years, the Daymet database includes leap day (February 29) and values for December 31 are discarded from leap years to maintain a 365-day year.
DayMet’s incident shortwave radiation is the “daylit” radiation. To get the daily average radiation, one must multiply by daylit fraction, given by dayl / 86400.
%matplotlib inline
%load_ext autoreload
%autoreload 2
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 150
import logging,yaml
import numpy as np
import rasterio
import fiona
import os
import datetime
import watershed_workflow
import watershed_workflow.ui
import watershed_workflow.sources.manager_daymet
import watershed_workflow.daymet
import watershed_workflow.io
watershed_workflow.ui.setup_logging(1,None)
watershed_workflow.config.set_data_directory('../../data')
watershed_shapefile = '../../data/examples/CoalCreek/sources/shapefile/CoalCreek.shp'
config_fname = '../../data/examples/CoalCreek/processed/config.yaml'
# Load the dictionary from the file
with open(config_fname, 'r') as file:
config = yaml.load(file, Loader=yaml.FullLoader)
# dates are in YYYY-MM-DD
# start and end of simulation -- one year of simulation that is in both the MODIS and DayMet dataset ranges
start_date = config['start_date']
end_date = config['end_date']
origin_date = config['origin_date']
import watershed#
crs, watershed = watershed_workflow.get_split_form_shapes(watershed_shapefile)
logging.info(f'crs: {crs}')
bounds = watershed.exterior().bounds
print(bounds)
print(bounds[2] - bounds[0], bounds[3] - bounds[1])
2024-04-17 05:21:44,069 - root - INFO:
2024-04-17 05:21:44,072 - root - INFO: Loading shapes
2024-04-17 05:21:44,075 - root - INFO: ------------------------------
2024-04-17 05:21:44,077 - root - INFO: Loading file: '../../data/examples/CoalCreek/sources/shapefile/CoalCreek.shp'
2024-04-17 05:21:44,213 - root - INFO: ... found 1 shapes
2024-04-17 05:21:44,216 - root - INFO: Converting to shapely
2024-04-17 05:21:44,240 - root - INFO: crs: epsg:26913
(317251.2640131897, 4299711.408984916, 328473.7039815487, 4307062.45088187)
11222.439968359016 7351.041896954179
watershed.exterior()
Download#
returned raw data has dim(nband, ncol, nrow)
# setting vars = None to download all available variables
source = watershed_workflow.sources.manager_daymet.FileManagerDaymet()
data = source.get_data(bounds, crs, start = start_date, end = end_date, buffer=0.02)
2024-04-17 05:21:44,487 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,492 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_tmin_2015_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,494 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,498 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_tmin_2016_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,501 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,506 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_tmax_2015_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,509 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,514 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_tmax_2016_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,517 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,523 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_prcp_2015_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,526 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,532 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_prcp_2016_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,536 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,541 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_srad_2015_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,544 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,551 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_srad_2016_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,555 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,561 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_vp_2015_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,566 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,571 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_vp_2016_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,573 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,579 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_dayl_2015_38.9157x-107.1272_38.8072x-106.9560.nc
2024-04-17 05:21:44,582 - root - INFO: Collecting DayMet file to tile bounds: [-107.1272, 38.8072, -106.956, 38.9157]
2024-04-17 05:21:44,588 - root - INFO: Using existing: ../../data/meteorology/daymet/daymet_dayl_2016_38.9157x-107.1272_38.8072x-106.9560.nc
Reproject Daymet CRS#
Reproject daymet CRS to the same as the watershed. This is necessary if watershed meshes are using watershed CRS.
data_new = watershed_workflow.warp.state(data, dst_crs=crs)
plot Daymet#
ivar = 'tmax'
islice = 100
daymet_crs = watershed_workflow.crs.daymet_crs()
fig = plt.figure()
ax1 = watershed_workflow.plot.get_ax(daymet_crs, fig, 1, 2, 1)
ax2 = watershed_workflow.plot.get_ax(crs, fig, 1, 2, 2)
watershed_ext_daymet = watershed_workflow.warp.shply(watershed.exterior(),
crs, daymet_crs)
watershed_workflow.plot.raster(data[ivar].profile, data[ivar].data[islice,:,:], ax1)
watershed_workflow.plot.shply(watershed_ext_daymet, daymet_crs, ax=ax1, color='r')
watershed_workflow.plot.raster(data_new[ivar].profile, data_new[ivar].data[islice,:,:], ax2)
watershed_workflow.plot.hucs(watershed, crs, ax=ax2, color='r')
ax1.set_title("Raw Daymet")
ax2.set_title("Reprojected Daymet")
/opt/conda/envs/watershed_workflow/lib/python3.10/site-packages/pyproj/crs/crs.py:1282: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems
proj = self._crs.to_proj4(version=version)
2024-04-17 05:21:47,829 - root - INFO: BOUNDS: (-591250.0, -367000.0, -576250.0, -355000.0)
2024-04-17 05:21:47,889 - root - INFO: BOUNDS: (314692.7009557779, 4296566.393670194, 331256.0668364619, 4310206.812630757)
Text(0.5, 1.0, 'Reprojected Daymet')
save daymet#
Write data to HDF5#
This will write daymet in a format that ATS can read. E.g., this will calculate mean air temperature, convert units, partition precipitation into rain and snow based on mean temp, and so on.
dout has dims of
(ntime, nrow, ncol)
or(ntime, ny, nx)
assert(len(data_new.collections) == 1)
met_data = data_new.collections[0]
met_data_ats = watershed_workflow.daymet.daymet_to_daily_averages(met_data)
config['daymet_filename'] = os.path.join('..', '..', 'data', 'examples','CoalCreek', 'processed','watershed_daymet_raw.h5')
attrs = watershed_workflow.daymet.getAttributes(bounds, start_date, end_date)
attrs['name']="Daymet forcing reformatted for ats modeling"
watershed_workflow.io.write_dataset_to_hdf5(
filename = config['daymet_filename'],
dataset= met_data_ats.collections[0],
attributes= attrs,
time0 = origin_date
)
2024-04-17 05:21:48,664 - root - INFO: Converting to ATS met input
2024-04-17 05:21:48,693 - root - INFO: Writing HDF5 file: ../../data/examples/CoalCreek/processed/watershed_daymet_raw.h5
Write typical Daymet#
This will average days, smooths the forcing and generate a “typical year” data, then looped 10 years. The dataset will be used during cyclic spinup.
config['daymet_typical_filename'] = os.path.join('..', '..', 'data', 'examples','CoalCreek', 'processed','watershed_daymet_typical.h5')
met_data_typical = watershed_workflow.datasets.State()
ntypical_years = 10
# here we make up some new times.
# It does not really matter what timeframe you choose as long as the nunmber of days are consistent.
new_times = np.array([datetime.date(1980,10,1) + datetime.timedelta(days=i) for i in range(365*ntypical_years)])
for (ds_key, ds_val) in met_data_ats.items():
# average and smooth forcing data. Hint: make filter=False if no smoothing is needed.
smooth_dat = watershed_workflow.utils.compute_average_year(ds_val.data, output_nyears=ntypical_years, filter=True)
met_data_typical[ds_key] = watershed_workflow.datasets.Dataset(ds_val.profile, new_times, smooth_dat)
attrs = watershed_workflow.daymet.getAttributes(bounds, new_times[0], new_times[-1])
attrs['name']=f"{ntypical_years}-yrs typical Daymet forcing generated using data from {start_date} to {end_date}"
watershed_workflow.io.write_dataset_to_hdf5(config['daymet_typical_filename'], met_data_typical.collections[0],
attributes=attrs, time0=origin_date)
2024-04-17 05:21:54,108 - root - INFO: Writing HDF5 file: ../../data/examples/CoalCreek/processed/watershed_daymet_typical.h5
# after smoothing, the forcing can look quite different!
ivar = 'air temperature [K]'
islice = 100
# daymet_crs = watershed_workflow.crs.daymet_crs()
profile = met_data_ats.collections[0].profile
fig = plt.figure()
ax1 = watershed_workflow.plot.get_ax(crs, fig, 1, 2, 1)
ax2 = watershed_workflow.plot.get_ax(crs, fig, 1, 2, 2)
watershed_workflow.plot.raster(profile, met_data_ats.collections[0].data[ivar][islice,:,:], ax1)
watershed_workflow.plot.hucs(watershed, crs, ax=ax1, color='r')
watershed_workflow.plot.raster(profile, met_data_typical.collections[0].data[ivar][islice,:,:], ax2)
watershed_workflow.plot.hucs(watershed, crs, ax=ax2, color='r')
ax1.set_title("Raw Daymet")
ax2.set_title("Typical Daymet")
2024-04-17 05:22:35,489 - root - INFO: BOUNDS: (314692.7009557779, 4296566.393670194, 331256.0668364619, 4310206.812630757)
2024-04-17 05:22:35,509 - root - INFO: BOUNDS: (314692.7009557779, 4296566.393670194, 331256.0668364619, 4310206.812630757)
Text(0.5, 1.0, 'Typical Daymet')
Get mean precipitation for spinup
# calculate the basin-averaged, annual-averaged precip rate
precip_total = met_data_typical.collections[0].data['precipitation rain [m s^-1]'] + met_data_typical.collections[0].data['precipitation snow [m SWE s^-1]']
mean_precip = precip_total.mean()
config['mean_precip [m s^-1]'] = float(mean_precip)
logging.info(f'Mean annual precip rate [m s^-1] = {mean_precip}')
2024-04-17 05:22:36,101 - root - INFO: Mean annual precip rate [m s^-1] = 2.2158981015347973e-08
with open(config_fname, 'w') as file:
yaml.dump(config, file)