Day 2: Input Data Preparation Tasks #140
Replies: 6 comments 1 reply
|
A good workaround for my_path = Path("..").resolve()
print(my_path)Assuming you went into the |
|
Solution Exercise1: Paths: # Set paths as environment so that it is available to all cells in this notebook
my_path = Path("..").resolve() # if you opened jupyter lab from the path where you also downloaded the data to
os.environ["PATH_DATA_SRC"] = os.path.join(my_path, "data/data_raw/")
os.environ["PATH_DATA_TGT"] = os.path.join(my_path, "data/data_processed/")
os.environ["PATH_WORK"] = os.path.join(my_path, "data/work_dir/")
os.environ["PATH_NMLS"] = os.path.join(my_path, "nmls/")
os.environ["PATH_MHM_OUTPUT"] = os.path.join(my_path, "mhm_output/")
os.environ["PATH_SCRIPTS"] = os.path.join(my_path, "scripts/")If there is Solution Exercise 1.1 # Plot and visualize the raw DEM file
# Path to DEM
dem_raw_file = os.path.join(os.environ["PATH_DATA_SRC"], "static/morph/dem.asc")
# Load DEM as xarray
dem_xr = rxr.open_rasterio(dem_raw_file, masked=True).squeeze(drop=True)
# Visualize the DEM
dem_xr.plot()
plt.show()
# ====== FILL THE DEM FILE =========
# You can easily fill a DEM file using the pyflwdir command as below:
# Convert to NumPy array
dem_np = dem_xr.values.squeeze() # 2D numpy array
# Fill depressions using pyflowdir
dem_filled_np, filled_mask = pfd.dem.fill_depressions(dem_np)
# convert back to xarray which preserves metadata
dem_filled_xr = xr.DataArray(dem_filled_np,
coords=dem_xr.coords,
dims=dem_xr.dims,
attrs=dem_xr.attrs)
# Visualize the filled DEM
dem_filled_xr.plot()
plt.show()Solution Exercise 1.2 # >>>>>> Exercise 1.2 <<<<<<<<
# Visualize the difference between the raw and filled DEM
# Diff the two DEMs
dem_diff_xr = dem_filled_xr - dem_xr
dem_diff_xr.plot()
plt.show()
# Include nodata attribute
dem_filled_xr.rio.write_nodata(-9999, inplace=True)
# The DEM is currently still in the raw extent and needs to be clipped later.
# For now save these intermediate files to PATH_WORK
# Save as ASCII
filled_dem_path = Path(os.environ["PATH_WORK"]) / "full_extent/static/morph/dem_filled.asc"
filled_dem_path.parent.mkdir(exist_ok=True, parents=True)
dem_filled_xr.rio.to_raster(filled_dem_path, driver="AAIGrid")Solution Exercise 1.3: # Compute flow direction (D8 nomenclature for mHM)
fdir_pfd = pfd.from_dem(dem_filled_np) # using np and not xr object as the function needs numpy array as input
# convert the pyflwdir object to numpy array
fdir_np = fdir_pfd.to_array()
# convert back to xarray which preserves metadata
fdir_xr = xr.DataArray(fdir_np,
coords=dem_xr.coords,
dims=dem_xr.dims,
attrs=dem_xr.attrs)
# Visualize the flow direction
fdir_xr.plot()
plt.show()
# Include nodata attribute
fdir_xr.rio.write_nodata(0, inplace=True) # 1 to 128 are the valid directions. Storing -9999 would require signed integer data type. So, 0 for nodata.
# Save as ASCII
fdir_xr.rio.to_raster(os.path.join(os.environ["PATH_WORK"], "full_extent/static/morph/fdir.asc"), driver="AAIGrid")Solution Exercise 1.4: # Look for pyflwdir command to generate facc.asc.
# Compute flow accumulation
facc_pfd = fdir_pfd.upstream_area(unit = 'cell') # needs FlwdirRaster
# convert back to xarray which preserves metadata
facc_xr = xr.DataArray(facc_pfd,
coords=dem_xr.coords,
dims=dem_xr.dims,
attrs=dem_xr.attrs)
# Visualize the flow direction
facc_xr.plot()
plt.show()
# Include nodata attribute
facc_xr.rio.write_nodata(-9999, inplace=True)
# Save as ASCII
facc_xr.rio.to_raster(os.path.join(os.environ["PATH_WORK"], "full_extent/static/morph/facc.asc"), driver="AAIGrid")Solution Exercise 1.5 gdaldem slope -p -s 111120 ${PATH_WORK}/full_extent/static/morph/dem_filled.asc ${PATH_WORK}/full_extent/static/morph/slope.asc && echo "slope file created and saved!"
# visualize the slopepython cell: # Path to slope file
slope_file = os.path.join(os.environ["PATH_WORK"], "full_extent/static/morph/slope.asc")
# Load DEM as xarray
slope_xr = rxr.open_rasterio(slope_file, masked=True).squeeze(drop=True)
# plot
slope_xr.plot()
plt.show()Solution Exercise 1.6: gdaldem aspect ${PATH_WORK}/full_extent/static/morph/dem_filled.asc ${PATH_WORK}/full_extent/static/morph/aspect.asc && echo "aspect file created and saved!"
# visualize the aspectpython cell: # Path to aspect file
aspect_file = os.path.join(os.environ["PATH_WORK"], "full_extent/static/morph/aspect.asc")
# Load DEM as xarray
aspect_xr = rxr.open_rasterio(aspect_file, masked=True).squeeze(drop=True)
# plot
aspect_xr.plot()
plt.show() |
|
Extend you need to set in a python cell: # Set the extents
%env XMIN = 10.125
%env XMAX = 11.875
%env YMIN = 50.625
%env YMAX = 51.875 |
|
Description of the era5 grid: https://confluence.ecmwf.int/display/CKB/ERA5%3A+What+is+the+spatial+reference |
|
Due to some exception some of use were having an error where the extent of the merged idgauge file changed when doing with gdalwarp for the work around suggest to use a python script shared here (Exercise 2.9) : import rasterio
from rasterio.merge import merge
def merge_rasters_preserve_extent(input_folder, output_file, nodata_value=-9999,reference_file=None):
"""
Merge all raster files (.tif) from a folder into one output raster.
Skips the output file if it already exists in the folder.
Parameters
----------
input_folder : str or Path
Folder containing raster files to merge.
output_file : str
Path to the merged raster output.
nodata_value : int or float, optional
NoData value for input and output rasters. Default is -9999.
reference_file : str or Path, optional
Reference raster to align extent/resolution to. Default is None.
Returns
-------
str
Path to the merged raster file.
"""
input_folder = Path(input_folder)
output_file = Path(output_file)
# Find all .tif files but exclude the output file if present
tif_files = sorted([f for f in input_folder.glob("*.tif") if f.resolve() != output_file.resolve()])
if not tif_files:
raise ValueError(f"No .tif files found to merge in folder: {input_folder}")
print(f"Found {len(tif_files)} .tif files to merge (output file skipped if present).")
# Open all source rasters
srcs = [rasterio.open(f) for f in tif_files]
if reference_file:
with rasterio.open(reference_file) as ref:
out_transform = ref.transform
out_crs = ref.crs
out_shape = (ref.height, ref.width)
print(f"Aligning to reference grid: {reference_file}")
merged_array, merged_transform = merge(
srcs,
bounds=ref.bounds,
res=ref.res,
nodata=nodata_value,
method='first'
)
else:
merged_array, merged_transform = merge(srcs, nodata=nodata_value, method='first')
out_crs = srcs[0].crs
# Prepare metadata
out_meta = srcs[0].meta.copy()
out_meta.update({
"driver": "GTiff",
"height": merged_array.shape[1],
"width": merged_array.shape[2],
"transform": merged_transform,
"crs": out_crs,
"nodata": nodata_value,
"dtype": merged_array.dtype
})
# Write merged raster
with rasterio.open(output_file, "w", **out_meta) as dest:
dest.write(merged_array)
for src in srcs:
src.close()
print(f"All idgauges merged and raster saved as: {output_file}")
return str(output_file)
merge_rasters_preserve_extent(
input_folder=Path(os.environ["PATH_WORK"]) / "process",
output_file=Path(os.environ["PATH_WORK"]) / "process" / "idgauges.tif",
nodata_value=-9999,
reference_file=None
) |
|
Thanks! However, it is important to double check if there are any other tifs in the directory. If yes, it will also merge these and the output gets corrupted. This can be fixed by filtering the |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Session Preparation
Download:
This includes:
Environment and Jupyter
mhm_day2(change name if wanted)data_prep_mhm_workshop_2026.ipynbFirst Block
Exercise 1 [
Morphology] Prepare DEM, slope, aspect, flow direction, and flow accummulationraw DEMand visualize.rawandfilled DEMs?filled DEMas ASCIIpyflowdirpackage to generateflow directionfrom thefilled DEMflow directioncan have different nomenclature, are you familiar to one required by mHM?flow directionfdiras an ASCII in pythonpyflowdirpackage to generateflow accumulationflow accumulationfdiras an ASCII in pythonGDALto generateslopefrom the filled DEMslope. Should the slope be in percentage rise or angle of elevation in mHM?slopeas an ASCIIGDALto generate aspect from thefilled DEMaspect.aspectas an ASCIIExercise 2 [
Morphology] Prepare the catchment shape and gauge location datamhm-tools create_catchment. As input either use your filleddemor yourfdirfile.basins_ids.ncfilefacc.ascfile you created in Ex1, plot it again and plot the gauge you get fromidgauges.ascon top of it. If you want you can also overlapp theuparea_gridfrom thebasin_ids.ncfile.gdalinfoto find the latlon extend that covers both catchments.idgauges.ascfiles to cover the whole domain and merge them into one file.dem.ascfile(s) using the mask from catchment delineation and expand it/them to the whole domain. Merge if necessary.CDO,GDALormhm-tools crop_mhm_setup.Exercise 3 [
Morphology] Crop the rest of the morphological input files.mhm-tools crop_mhm_setupfor to clip/crop the remaining morphological data. Try to find a smart way.mhm-tools -hmhm-tools <TOOL_NAME> -h.Second Block
Exercise 4 [
latlon file] Generate the relationship that connects model resolution to morphologymhm-toolscan helps you to make latlon files.mhm-tools latloncommand--level0 LEVEL0--level1 LEVEL1--level11 LEVEL11(optional, but necessary when routing streamflow)mhm-tools latloncommandExercise 5 [
Meteorology] Prepare the meteorological forcingsPrepare the meterological data such that mHM can use it. Steps that might or might not be needed:
If you need inspiration: We provide a bash and a python workflow for precipitation data
Third Block
Exercise 6 [
Observations] Prepare the observed discharge datadata_raw/observation/grdc/test domaininput data from Day 1Exercise 7 [
mHM test run] Run mHM with the input data prepared from this sessionPATH_NMLSin the preablemhm.nml6340200catchment with themhm_parameter.nmlfile provided.discharge.nc6340200catchment with themhm_parameter_calibrated.nmlfile provided.discharge.nc6340200and6340220catchments with themhm_parameter_calibrated.nmlfile provided.6340200and6340220catchments this time with the resolution of0.0625 degree.Optional Exercise 8
6340220using its corresponding DEM mask at0.0625 degree.6340220to mHM gauge input time series format.6340200using6340220as inflow gauge.Optional Exercise 9
6340220at0.0625 degreeresolution.6340200.All reactions