Skip to content

Commit e09d489

Browse files
committed
update
1 parent 0aaccd9 commit e09d489

File tree

8 files changed

+127
-25
lines changed

8 files changed

+127
-25
lines changed
19.3 KB
Loading

content/tutorials/hydro_flattening/hydro_flatenning.qmd

Lines changed: 127 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: "Hydro-flattening a Digitial Elevation Model"
2+
title: "Hydro-flattening a Digital Elevation Model"
33
author: "Doug Newcomb & Anna Petrasova"
44
date: 2025-06-17
55
date-modified: today
@@ -11,7 +11,7 @@ format:
1111
code-tools: true
1212
code-copy: true
1313
code-fold: false
14-
categories: [Python, beginner, intermediate, topography, lidar]
14+
categories: [Python, intermediate, topography, lidar, GUI]
1515
description: Learn how to do hydro-flattening of a DEM.
1616
engine: knitr
1717
execute:
@@ -29,6 +29,8 @@ The result is a DEM with unnatural ripples or slopes on water surfaces, which no
2929
Hydro-flattening addresses this by incorporating breaklines that enforce flat, level water surfaces and preserve topographic realism.
3030
Read more [at USGS website](https://www.usgs.gov/ngp-standards-and-specifications/lidar-base-specification-appendix-2-hydro-flattening-reference).
3131

32+
![Example of no breaklines: Geomorphon Analysis of DEM in Roanoke Rapids Reservoir, NC 2014 DEM from QL2 data](triangles.webp)
33+
3234
In this tutorial, you’ll learn how to use GRASS to apply hydro-flattening techniques to lidar-derived DEMs
3335
using [r.hydro.flatten](https://grass.osgeo.org/grass-stable/manuals/addons/r.hydro.flatten.html) addon
3436
following these steps:
@@ -41,7 +43,7 @@ following these steps:
4143
- Create automatic river transects
4244
- Create hydro-flattened river raster data for inclusion in a DEM
4345
- Create a filled DEM layer combining the mean ground data, hydro-flattened data, and other interpolated data.
44-
- Export the resulting data from a GRASS project to a TIF file.
46+
- Export the resulting data from a GRASS project to a GeoTIFF file.
4547

4648
## Getting ready
4749

@@ -51,10 +53,12 @@ To get ready for the analysis, we will need to download lidar data, orthoimagery
5153
If you are not sure how to download and get started with GRASS using its graphical user interface or using Python, checkout the tutorials [Get started with GRASS GUI](../get_started/fast_track.qmd) and [Get started with GRASS & Python in Jupyter Notebooks](../get_started/fast_track_grass_and_python.qmd).
5254
:::
5355

56+
To create a raster surface from LiDAR point cloud data, GRASS must be compiled with the [PDAL libraries](https://pdal.io/en/stable/). This capability is currently only available on Linux and OSX platforms and will be available on Windows when GRASS switches to the cmake-based build system (in development). In the meantime, the mean ground raster surface needed for the hydroflattening portion of the tutorial can be created on Windows using the [QGIS point cloud tools](https://docs.qgis.org/3.40/en/docs/user_manual/processing_algs/qgis/pointcloudconversion.html) (selecting classes 2,10,13 and setting the output resolution to 3.2808 ft).
57+
5458
### Download data
5559

5660
We will download lidar dataset from [USGS website](https://apps.nationalmap.gov/downloader/).
57-
Search for _Lake Logan, North Carolina_ or use this bounding box:
61+
Search for *Lake Logan, North Carolina* or use this bounding box:
5862

5963
-82.933790°, 35.423316°
6064
-82.922031°, 35.407718°
@@ -78,12 +82,16 @@ We will use this file later on.
7882

7983
### Start GRASS and create a new project
8084

85+
::::::::: {.panel-tabset group="language"}
86+
87+
#### GUI
88+
8189
If this is the first time you have opened GRASS you will see the default startup
8290
screen with a WGS84 world project. Click on the Create new project button on the left
8391
or look for ![Add project icon](../get_started/images/project-add.png)
8492
on the upper left.
8593

86-
![Creating a new project in GUI](../get_started/images/grass_gui_first_time_and_cli_combined.png)
94+
![Creating a new project in GUI](new_firstscreen.webp)
8795

8896
This will open a wizard where you:
8997

@@ -93,6 +101,20 @@ This will open a wizard where you:
93101
4. select default datum transformation, click _Next_
94102
5. see summary and click _Finish_
95103

104+
#### Command line
105+
106+
```{bash}
107+
grass -c EPSG:6543 /path/to/nc6543
108+
```
109+
110+
#### Python
111+
112+
```{python}
113+
gs.create_project("/path/to/nc6543", epsg="6543")
114+
```
115+
116+
:::::::::
117+
96118
### Import data
97119

98120
The next step is to import the ground point data from the 6 lidar
@@ -168,6 +190,8 @@ The most current data set for this location is from 2023.
168190
The URL to access the WMS data set is
169191
`https://services.gis.nc.gov/secure/services/Imagery/Orthoimagery_2023/ImageServer/WMSServer`.
170192

193+
Data is also available for 2019, 2015, and 2010, just substitute those years for 2023 in the URL above if you wish to review those years.
194+
171195
::::::::: {.panel-tabset group="language"}
172196

173197
#### GUI
@@ -181,11 +205,13 @@ Select the newly populated layer _Orthoimagery (2023)_.
181205
Select _Source projection_ EPSG:6543 to match your project's CRS for faster response.
182206
Also select the jpeg radio button in the _Source image format_.
183207

184-
![WMS dialog](wmsdialog.webp)
185-
186208
To remember the URL, click on the _Save_ button on the top of the dialog and enter
187209
a descriptive name to quickly recall the image service between sessions.
188210

211+
![WMS dialog](wmsdialog.webp)
212+
213+
Click *Add layer*.
214+
Your GUI should now have _Orthoimagery (2023)_ listed as one of the layers.
189215
Uncheck the orthoimagery layer and zoom into one of the void areas to the left of the lake. Once
190216
you have zoomed in, check the orthoimagery layer and see what the void represents.
191217

@@ -218,7 +244,7 @@ gs.run_command(
218244
#### GUI
219245

220246
::::: grid
221-
::: g-col-4
247+
::: g-col-6
222248
GRASS Addons are installed in the GUI with
223249
_Addons extensions→ Install extensions from addons_.
224250
In the dialog, search for the addon and _Install_.
@@ -232,7 +258,7 @@ Start GRASS again. You should now see an Addons option in the Tools tab with r.h
232258
Double click on r.hydro.flatten tool to open a dialog.
233259

234260
:::
235-
::: g-col-8
261+
::: g-col-6
236262

237263
![](new_install_hydroflatten.webp)
238264
:::
@@ -329,11 +355,13 @@ from the [Map Display toolbar](https://grass.osgeo.org/grass-devel/manuals/wxGUI
329355
_New vector map_ and type a name for it, such as _centerlines_.
330356
Create it and then you can close the newly opened attribute manager dialog, we won't need it.
331357

332-
3. Now start digitizing a centerline, it doesn't have to be perfect. Select _Ditize new line_ tool
358+
3. Now start digitizing a centerline, it doesn't have to be perfect. Select _Digitize new line_ tool
333359
from the [toolbar](https://grass.osgeo.org/grass-devel/manuals/wxGUI.vdigit.html#digitizer-toolbar)
334360
and start digitizing from the edge with right click. To end line, use left click. Do it for both segments of the river.
335361
Quit digitizer.
336362

363+
![Digitized centerline](new_centerline_digitized.webp)
364+
337365
::: {.callout-note title="Automated centerlines"}
338366
For longer river segments you can use [v.centerline](https://grass.osgeo.org/grass-devel/manuals/addons/v.centerline.html)
339367
for automated centerline generation.
@@ -411,7 +439,7 @@ approximately the downstream edge of the plunge pool below the dam. It’s proba
411439
a break line at the base of the dam as well.
412440
Digitize the line along where you see the dam structure meet the water and save it.
413441

414-
![Ditizing the dam](new_damwaterline.webp)
442+
![Digitizing the dam](new_damwaterline.webp)
415443

416444
## Hydro-flattening with break lines
417445

@@ -479,19 +507,33 @@ with [r.fillnulls](https://grass.osgeo.org/grass-devel/manuals/r.fillnulls.html)
479507
#### GUI
480508

481509
Re-run the r.hydro.flatten with parameter **max_stddev=5** to avoid flattening
482-
areas with standard deviation > 5.
510+
areas with standard deviation greater than 5.
511+
Name the resulting layer *lake_logan_1m_filled_DEM_null_above_5_stddev*.
483512

484-
Then call r.fillnulls with input layer *lake_logan_1m_filled_DEM*
485-
and output *lake_logan_1m_filled_DEM_fillnulls* and default values.
513+
::::: grid
514+
515+
::: g-col-6
516+
517+
Then find [r.fillnulls](https://grass.osgeo.org/grass-devel/manuals/r.fillnulls.html) tool
518+
in menu *Raster → Interpolate surfaces → Fill NULL cells*
519+
and call r.fillnulls with input layer *lake_logan_1m_filled_DEM*, output layer *lake_logan_1m_filled_DEM_fillnulls* and keep the rest with the default values.
520+
521+
![r.fillnulls dialog](new_rfillnulls_dialog1.webp)
522+
:::
523+
::: g-col-6
524+
525+
![Open r.fillnulls dialog](new_rfillnulls.webp)
526+
:::
527+
:::::
486528

487529
Finally, run [r.relief](https://grass.osgeo.org/grass-devel/manuals/r.relief.html) to see the resulting topography.
488530

489531
#### Command line
490532

491533
```{bash}
492-
r.hydro.flatten input=lake_logan_1m water_elevation=lake_logan_1m_wat_elev_2dbreak water_elevation_stddev=lake_logan_1m_wat_stddev_2dbreak percentile=14 breaklines=centerlines_120_trans filled_elevation=lake_logan_1m_filled_DEM max_stddev=5
493-
r.fillnulls input=lake_logan_1m_filled_DEM output=lake_logan_1m_filled_DEM_fillnulls method=rst
494-
r.relief input=lake_logan_1m_filled_DEM_fillnulls output=relief
534+
r.hydro.flatten input=lake_logan_1m water_elevation=lake_logan_1m_wat_elev_2dbreak water_elevation_stddev=lake_logan_1m_wat_stddev_2dbreak percentile=14 breaklines=centerlines_120_trans filled_elevation=lake_logan_1m_filled_DEM_null_above_5_stddev max_stddev=5
535+
r.fillnulls input=lake_logan_1m_filled_DEM_null_above_5_stddev output=lake_logan_1m_filled_DEM_final method=rst
536+
r.relief input=lake_logan_1m_filled_DEM_final output=relief
495537
```
496538

497539
#### Python
@@ -504,40 +546,100 @@ gs.run_command(
504546
water_elevation_stddev="lake_logan_1m_wat_stddev_2dbreak",
505547
percentile=14,
506548
breaklines="centerlines_120_trans",
507-
filled_elevation="lake_logan_1m_filled_DEM",
549+
filled_elevation="lake_logan_1m_filled_DEM_null_above_5_stddev",
508550
max_stddev=5,
509551
)
510552
gs.run_command(
511553
"r.fillnulls",
512-
input="lake_logan_1m_filled_DEM",
513-
output="lake_logan_1m_filled_DEM_fillnulls",
554+
input="lake_logan_1m_filled_DEM_null_above_5_stddev",
555+
output="lake_logan_1m_filled_DEM_final",
514556
method="rst",
515557
)
516-
gs.run_command("r.relief", input="lake_logan_1m_filled_DEM_fillnulls", output="relief")
558+
gs.run_command("r.relief", input="lake_logan_1m_filled_DEM_final", output="relief")
517559
```
518560

519561
:::::::::
520562

521563
::::: grid
522564

523-
::: g-col-6
565+
::: g-col-4
524566

525-
![Shaded relief of the hydro-flattened DEM](relief.webp)
567+
![Hydroflattened DEM before r.fillnulls](before_fillnuls.webp)
526568

527569
:::
528570

529-
::: g-col-6
571+
::: g-col-4
572+
573+
![Shaded relief of the final hydro-flattened and filled DEM](relief.webp)
574+
575+
:::
576+
577+
::: g-col-4
530578

531579
![Zoomed-in on the dam and river segment](relief_zoom.webp)
532580

533581
:::
534582
::::::
535583

584+
## Export to GeoTIFF
585+
586+
The last step is to export the filled DEM to the open standard GeoTIFF file format.
587+
588+
::::::::: {.panel-tabset group="language"}
589+
590+
#### GUI
591+
592+
Right click on the filled DEM layer (*lake_logan_1m_filled_DEM_final*) and select *Export*.
593+
This will bring up the [r.out.gdal](https://grass.osgeo.org/grass-devel/manuals/r.out.gdal.html) dialog.
594+
595+
Click on the browse button next to the *Name for output raster file* option
596+
to browse to the directory where you want the geotiff file to be written.
597+
Keep the default file format as GTiff (GeoTIFF).
598+
599+
![](new_routgdal1.webp)
600+
601+
Click on the *Creation* tab. On this tab you can select the *Data type* and compression level for the output image. From the Data type drop-down select *Float64*.
602+
603+
Then go to the *Creation option(s) to pass to the output format driver* section.
604+
The different options for writing out a GeoTIFF raster can be found at the
605+
[GDAL GeoTiff format description page](https://gdal.org/en/latest/drivers/raster/gtiff.html).
606+
Type in "compress=deflate,predictor=3". Click Run.
607+
608+
#### Command line
609+
610+
```{bash}
611+
r.out.gdal input=lake_logan_1m_filled_DEM_final output=lake_logan_1m_filled_DEM_final.tif format=GTiff type=Float64 createopt="compress=deflate,predictor=3"
612+
```
613+
614+
#### Python
615+
616+
```{python}
617+
gs.run_command(
618+
"r.out.gdal",
619+
input="lake_logan_1m_filled_DEM_final",
620+
output="lake_logan_1m_filled_DEM_final.tif",
621+
format="GTiff",
622+
type="Float64",
623+
createopt="compress=deflate,predictor=3",
624+
)
625+
```
626+
627+
:::::::::
628+
629+
::: {.callout-note title="Compression and large datasets"}
630+
Deflate compression is the most recognized lossless compression for GeoTIFFs. It is supported by other software and is relatively fast for reads. The predictor option allows the deflate compression to be more efficient. You can leave the GeoTIFFs uncompressed, but the file size will be about 4 times larger than the deflate compressed version. This difference adds up as you scale this process up to larger data sets.
631+
632+
For GeoTIFFs larger than 4GB, you will need to use the BIGTIFF=YES option to successfully write an output raster. You may want to also add the num_threads=4 to enable the multi-threaded writing option as well.
633+
:::
634+
635+
![](thumbnail.webp)
636+
637+
Congratulations! You have completed this tutorial! {{< fa rocket >}}
536638

537639
***
538640

539641
:::{.smaller}
540642
The development of this tutorial was in part funded by the US
541643
[National Science Foundation (NSF)](https://www.nsf.gov/),
542644
award [2303651](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2303651).
543-
:::
645+
:::
35.9 KB
Loading
123 KB
Loading
69.8 KB
Loading
29.4 KB
Loading
29.3 KB
Loading
272 KB
Loading

0 commit comments

Comments
 (0)