Skip to content

Commit

Permalink
Updated the manual concerning RiverMeshTools for the new developments.
Browse files Browse the repository at this point in the history
  • Loading branch information
feiye-vims committed Aug 7, 2023
1 parent 5f0f4ca commit eb50ebd
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 41 deletions.
Binary file added docs/assets/sample-barrier-island-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/sample-levee-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/sample-river-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 86 additions & 41 deletions docs/mesh-generation/meshing-for-compound-floods/generate-river-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
## Usage
RiverMapper requires two inputs:

1. \*.tif, which are DEM tiles in lon/lat from one or more sources (such as CuDEM).
1. \*.tif, which are DEM tiles in lon/lat from one or more sources.

2. a shapefile with a 'LineString' type, which contains a 1D river network.

!!!note
!!!Note
The 1D river network can be any reasonable approximation of the thalwegs. It can be:
<ul>
<li>extracted from DEM using the method presented in the [previous section](./extract-thalweg.md)</li>
Expand All @@ -27,15 +27,13 @@ A sample output looks like this:

![Sample river map](../../assets/sample-river-map.png)

The exact mpi command may vary based on your system.


## Sample applications
To test the RiverMapper tool, you can begin by extracting the "RiverMapper_Samples/" directory from [RiverMapper_Samples.tar](http://ccrm.vims.edu/yinglong/feiye/Public/RiverMapper_Samples.tar).
It contains two subdirectories: "Serial" and "Parallel", providing sample applications for a smaller domain and a larger domain respectively.
Each subdirectory contains a sample Python script and the necessary input files.

### Serial mode
### Meshing rivers in a small domain (Serial mode)
For a small domain (covering one or two states), a direct function call to the serial "make_river_map" suffices.
See the sample script:
```
Expand All @@ -62,7 +60,14 @@ Under the directory "RiverMapper_Samples/Serial/", execute the serial script li
./sample_serial.py
```

### Parallel mode
!!!Note
* Although only one DEM tile is used in this example, but multiple DEM tiles are allowed.
* If the tiles are from different DEM sources, they should be arranged from high to low priority in the list.
Tiles from the high priority DEM source should have high fidelity and high resolution.
* The script allows DEM tiles of different sizes and shapes.


### Meshing rivers in a large domain (Parallel mode)
For a large domain such as [STOFS3D Atlantic](https://nauticalcharts.noaa.gov/updates/introducing-the-inland-coastal-flooding-operational-guidance-system-icogs/),
a parallel driver is provided to automatically group thalwegs based on their parent tiles, then distribute the groups to parallel processors.

Expand All @@ -75,13 +80,12 @@ RiverMapper_Samples/Parallel/sample_parallel.py
from mpi4py import MPI
import os
from RiverMapper.river_map_mpi_driver import river_map_mpi_driver
from RiverMapper.make_river_map import Config_make_river_map

if __name__ == "__main__":
comm=MPI.COMM_WORLD
# ------------------------- sample input ---------------------------
dems_json_file = '/sciclone/schism10/Hgrid_projects/STOFS3D-V6/v16/Inputs/dems.json' # specifying files for all DEM tiles
thalweg_shp_fname='/sciclone/schism10/Hgrid_projects/STOFS3D-V6/v16/Shapefiles/CUDEM_Merged_for_v16.shp'
dems_json_file = './Inputs/DEMs/dems.json' # specifying files for all DEM tiles
thalweg_shp_fname='./Inputs/Shapefiles/LA_local.shp'
output_dir = './Outputs/' + f'{os.path.basename(thalweg_shp_fname).split(".")[0]}_{comm.Get_size()}-core/'
# ------------------------- end input section ---------------------------
river_map_mpi_driver(
Expand All @@ -92,7 +96,8 @@ if __name__ == "__main__":
)
```

The first argument takes a \*.json file that specifies multiple sets of DEMs, for example:
In stead of specifying a file list for the DEM tiles as in the serial example,
the first argument takes a \*.json file that specifies multiple sets of DEMs, for example:
```json
{
"CuDEM": {
Expand All @@ -109,30 +114,31 @@ The first argument takes a \*.json file that specifies multiple sets of DEMs, fo
}
}
```
There are a few things to be noted:

* In stead of specifying a file list for the DEM tiles (as in the serial example),
you can either specify a glob pattern or a list of file names;
if both are specified, the script will automatically pool all files together and take the unique files.

* No need to manually specify the bounding "boxes", just leave it empty.

* Different DEM products should be arranged from high priority to low priority.
In the above example, "CuDEM" precedes "CRM", meaning that if a point is within CuDEM's spatial coverage,
then its elevation value is solely based on CuDEM.
!!!Note
* For each DEM source, specify a glob pattern and/or a list of file names;
if both are specified, the script will pool all files together and take the unique files.

* No need to manually specify the bounding "boxes", just leave them empty.

> The order of the dictionary key is preserved as long as you are using Python 3.7 or a later version.
> We may replace the regular dictionary to OrderedDict in the future.
* Different DEM products should be arranged from high priority to low priority.
The order of the dictionary key ("CuDEM" and "CRM") is preserved as long as you are using Python 3.7 or a later version.
We may replace the regular dictionary to OrderedDict if there is a need.

Under the directory "RiverMapper_Samples/Parallel/", execute the parallel script like this:

```
mpirun -n 20 ./sample_parallel.py
```

The exact mpi command may vary based on your system.


## Advanced Parameterization

### Mandatory inputs
### Mandatory input parameters

In the "Serial" and "Parallel" examples above, you may have noticed there are 3 mandatory Inputs:

Expand All @@ -142,7 +148,7 @@ In the "Serial" and "Parallel" examples above, you may have noticed there are 3
| thalweg_shp_fname | name of a polyline shapefile containing the thalwegs |
| output_dir | must specify one. |

### Optional inputs
### Optional input parameters

In addition to the mandatory inpouts, RiverMapper provides a few parameters to fine tune the output polylines or generate special features like levees or pseudo-channels.

Expand All @@ -153,6 +159,7 @@ In addition to the mandatory inpouts, RiverMapper provides a few parameters to f
| mpi_print_prefix | string | a prefix string to identify the calling mpi processe in the output messages; can be empty |
| MapUnit2METER = 1 | float | no need to change; to be replaced by projection code, e.g., epsg: 4326, esri: 120008, etc. |
| river_threshold | float | minimum and maximum river widths (in meters) to be resolved |
| elev_scale | float | scaling factor for elevations; a number of -1 (invert elevations) is useful for finding ridges (e.g., of a barrier island) |
| outer_arc_positions | a list/tuple of floats | relative position of outer arcs, e.g., (0.1, 0.2) will add 2 outer arcs on each side of the river (4 in total), 0.1 \* riverwidth and 0.2 \* riverwidth from the banks. |
| length_width_ratio | float | a ratio of element length in the along-channel direction to river width; when a river is narrower than the lower limit, the bank will be nudged (see next parameter) to widen the river |
| i_close_poly | bool | whether to add cross-channel arcs to enclose river arcs into a polygon |
Expand Down Expand Up @@ -182,15 +189,19 @@ For example, if you want to add two pairs of outer arcs that flank the main rive
In this case two outer arcs will be placed to the left of the channel at distances of "$0.1 \times$ channel width" and "$0.2 \times$ channel width" from the left bank;
the same goes for the right bank, so 4 outer arcs in total.

However, tuning the parameters may not be easy at first because there are many of them.
To simplify the parameter configuration, RiverMapper offers a class called "Config_make_river_map",
## Parameter presets
Tuning the parameters may not be easy at first because there are many of them.
To simplify the parameter configuration, RiverMapper offers a class called "ConfigRiverMap",
which provides commonly used parameter presets.
You can use these presets to directly configure the parameters.
For example,
These presets are "class methods" in [config_river_map.py](https://github.com/schism-dev/RiverMeshTools/blob/main/RiverMapper/RiverMapper/config_river_map.py),
and each preset (class method, or factory method) comes with a short description in the code.

For example, the preset "LooselyFollowRivers" means that "Small-scale river curvatures may not be exactly followed, but channel connectivity is still preserved",
and this is the sample code:
```python
from RiverMapper.make_river_map import Config_make_river_map
from RiverMapper.config_river_map import ConfigRiverMap

river_map_config = Config_make_river_map.LooselyFollowRivers()
river_map_config = ConfigRiverMap.LooselyFollowRivers()
make_river_map(
tif_fnames = ['./Inputs/DEMs/GA_dem_merged_ll.tif'],
thalweg_shp_fname = './Inputs/Shapefiles/GA_local.shp',
Expand All @@ -199,30 +210,25 @@ For example,
)

```
, where "LooselyFollowRivers" is a parameter preset defined in the "Config_make_river_map" class,
and the operator "\*\*" unpacks the optional parameters from the configuration.

You can also peruse the "class methods" inside "Config_make_river_map" at the beginning of "make_river_map.py" to familiarize with different parameter settings.
Each preset (class method, or factory method) comes with a short description in the code, for example,
"LooselyFollowRivers" means that "Small-scale river curvatures may not be exactly followed, but channel connectivity is still preserved".
The presets may be regularly updated, so their descriptions are not repeated here to avoid duplication and inconsistency.

Another utility of the "Config_make_river_map" class is to facilitate the parameter transfer from the parallel driver to the core routine.
Another utility of the "ConfigRiverMap" class is to facilitate the parameter transfer from the parallel driver to the core routine.
The stardard way of setting the parameters in the parallel mode is as follows:

```python
from mpi4py import MPI
import os
from RiverMapper.river_map_mpi_driver import river_map_mpi_driver
from RiverMapper.make_river_map import Config_make_river_map
from RiverMapper.config_river_map import ConfigRiverMap

if __name__ == "__main__":
comm=MPI.COMM_WORLD
# ------------------------- sample input ---------------------------
dems_json_file = '/sciclone/schism10/Hgrid_projects/STOFS3D-V6/v16/Inputs/dems.json' # specifying files for all DEM tiles
thalweg_shp_fname='/sciclone/schism10/Hgrid_projects/STOFS3D-V6/v16/Shapefiles/CUDEM_Merged_for_v16.shp'
output_dir = './Outputs/' + f'{os.path.basename(thalweg_shp_fname).split(".")[0]}_{comm.Get_size()}-core/'
river_map_config = Config_make_river_map()
river_map_config = ConfigRiverMap()
# ------------------------- end input section ---------------------------
river_map_mpi_driver(
dems_json_file=dems_json_file,
Expand All @@ -235,22 +241,61 @@ if __name__ == "__main__":

Comparing with the parallel [example](#parallel-mode) in the previous section, the above example adds a few lines of code that does the following:

* importing the "Config_make_river_map"
* creating a default configuration,
* importing the "ConfigRiverMap" class
* creating a default configuration "river_map_config",
* passing the configration to the parallel driver.

Since the default configuration is used, this example is essentially the same as the previous parallel example.
But it facilitates further parameter tweaking, e.g.:
```python
river_map_config = Config_make_river_map.LooselyFollowRivers()
river_map_config.optional['i_DiagnosticOutput'] = True
river_map_config = ConfigRiverMap.LooselyFollowRivers()
river_map_config.optional['outer_arc_positions'] = (0.1, 0.2)
river_map_config.optional['i_real_clean'] = True
```
, without changing other parts of the code.


## More parameter presets
By tweaking the parameters, RiverMapper can also aid in the meshing of other channel-like features.

### Levees
In the STOFS-3D-Atlantic domain, levees are important features to be incorporated in the model mesh.
Instead of parameterizing them as hydraulic structures, the levees are explicitly represented by meter-scale elements,
with two rows of nodes resolving the feet of the levee and another two rows resolving the top of the levee:

![Sample river map](../../assets/sample-levee-map.png)

With the levee centerlines available from National Levee Database,
the levee map can be easily made by invoking the pseudo channel option of RiverMapper:

```python
river_map_config = ConfigRiverMap.Levees()
```

Notice that the along-channel (in this case along-levee) resolution also adapts for bends,
just like for rivers.

### Barrier islands
Barrier islands are long and narrow topographical features similar to river channels.
In fact, the map of a barrier island can be made in the same way as river channels
if the sign of the DEM's elevation values is inverted.

![Sample river map](../../assets/sample-barrier-island-map.png)

This can be done by setting the optional parameter "elev_scale" to "-1",
or directly invoking the preset "BarrierIsland":

```python
river_map_config = ConfigRiverMap.BarrierIsland()
```

!!!Note
The above two sample applications can also be found in
[RiverMapper_Samples.tar](http://ccrm.vims.edu/yinglong/feiye/Public/RiverMapper_Samples.tar)

## Experimental Features
### Global arc cleaning
There is an optional input in Config_make_river_map called "i_real_clean",
There is an optional input in for "make_river_map" called "i_real_clean",
which defaults to False.
When turned on, an extra cleaning process will be applied to all arcs.
However, this process is not efficient enough for large applications at the time being,
Expand Down

0 comments on commit eb50ebd

Please sign in to comment.