Topography#

Topographic information is an important input to WAsP’s flow models. Specifically, WAsP’s terrain model takes as input maps of surface elevation, surface roughness, and optionally displacement height.

In PyWAsP, instead of dealing with surface roughness maps and displacement height maps as completely separate layers, we deal with them as land cover maps, where patches of land are associated with specific land cover classes, each having specific surface characteristics (i.e. the surface roughness and displacement height).

See also

Topography

Overview, map conversion, and data download.

Elevation Maps

Elevation maps - schema, I/O, working with raster and vector.

Roughness Maps

Roughness maps - schema, I/O, best practices.

Land Cover Maps

Land cover maps - schema, I/O, land cover tables.

Preparing Input for Terrain Modeling#

To predict site effects from topography data with PyWAsP, the data is bundled together in the pywasp.wasp.TopographyMap class. It takes as input an elevation vector map, a land cover vector map, and a land cover table.

In [1]: import windkit as wk

In [2]: import pywasp as pw

In [3]: import matplotlib.pyplot as plt

# Read elevation and land cover maps
In [4]: elev_map = wk.read_elevation_map(
   ...:     "source/tutorials/data/SerraSantaLuzia.map",
   ...:     crs="EPSG:32629",
   ...: )
   ...: 

In [5]: lc_map, lc_tbl = wk.read_roughness_map(
   ...:     "source/tutorials/data/SerraSantaLuzia.map",
   ...:     crs="EPSG:32629",
   ...:     convert_to_landcover=True,
   ...:     polygons=False
   ...: )
   ...: 

# Create TopographyMap for flow modeling
In [6]: topo_map = pw.wasp.TopographyMap(
   ...:     elev_map,
   ...:     lc_map,
   ...:     lc_tbl
   ...: )
   ...: 

In [7]: print(topo_map)
Roughness map
                                              geometry  id_left  id_right
0    LINESTRING (520129.5 4608000, 520157.1 4608018.5)        0         0
1      LINESTRING (522602.4 4608000, 522613.5 4608058)        1         0
2    LINESTRING (518024.6 4608000, 518062.3 4608074.5)        0         1
3    LINESTRING (518062.3 4608074.5, 518160.5 46081...        1         1
4    LINESTRING (522376.2 4608000, 522411.7 4608066...        2         1
..                                                 ...      ...       ...
889  LINESTRING (524303.3 4637000, 524300.4 4636988...        0         1
890  LINESTRING (519338 4636768, 519331.3 4636784.5...        3         0
891  LINESTRING (510688.6 4635512, 510675.5 4635315...        4         9
892  LINESTRING (510166.2 4637000, 510167.2 4636997...        1         9
893  LINESTRING (526903.9 4637000, 526904.1 4636978...        1         1

[894 rows x 3 columns]
Elevation map
      elev                                           geometry
0      0.1  LINESTRING (512460.3 4637000, 512464.4 4636988...
1      0.1  LINESTRING (515280.7 4608000, 515277.1 4608009...
2      0.1  LINESTRING (517893.5 4616000, 517895.9 4615991...
3      0.1  LINESTRING (516457.4 4616000, 516454.6 4615989...
4      0.1  LINESTRING (515413.3 4616000, 515412.8 4615993...
..     ...                                                ...
577  510.0  LINESTRING (515924.7 4623250, 515919.1 4623258...
578  520.0  LINESTRING (515950.9 4623300, 515944.4 4623306...
579  520.0  LINESTRING (516082 4623650, 516074.8 4623655.5...
580  520.0  LINESTRING (515674.8 4623925, 515667 4623931.5...
581  530.0  LINESTRING (515972.6 4623375, 515967.8 4623382...

[582 rows x 2 columns]

Topography maps can be saved to, and loaded from, a ZipFile archive using the pywasp.wasp.TopographyMap.save() and pywasp.wasp.TopographyMap.load() methods.

In WAsP Flow Model we describe the WAsP models in more details and show how terrain effects can be calculated from a topo_map, like the one above.

Best practices for working with roughness maps#

Roughness maps can come from many different sources and can be of varying quality and resolution. When working with roughness maps, it is important to consider the following best practices for making them suitable for use in WAsP:

  1. Water bodies have 0.0 roughness: Water bodies should have a roughness value of 0.0, this is the signal to WAsP that the surface is water. During calculations in WAsP, the roughness value of 0.0 is replaced with the water roughness value set in the pw.wasp.Config (default is 0.0002). This is important for the stability model of WAsP, as it uses different stability functions for water and land.

  2. Land roughness values should be in the range [0.0002, 5.0]: Roughness values should be in the range [0.0002, 5.0] for land surfaces. WAsP assumes the lowest roughness to be the water roughness value (0.0002) and the highest roughness to be 5.0. Any land roughness values outside this range can cause problems in WAsP. If a lower water roughness value was set in the WAsP Config, the lower limit is adjusted accordingly.

  3. Keep the number of unique roughness values to a reasonable number: WindKit reads roughness maps and converts them to land cover classes. The number of unique roughness values in the roughness map should be kept to a reasonable number to avoid too many land cover classes. The suitable number of unique roughness values depends on the application. PyWAsP allows up to 100, but typically 5-50 unique roughness values are sufficient. Internally, WAsP uses a limited number of roughness-change events per sector, so having too many unique roughness values don’t add any value.

In the future, WindKit will provide tools to preprocess roughness maps to adhere to these best practices. In the meantime, QGIS, xarray, xarray-spatial, and other GIS tools can be used.

Converting Raster Maps to Vector Maps#

While WindKit and PyWAsP have great support for working with both raster and vector maps and the PyWAsP terrain model can work with elevation maps as both rasters and vector maps, for land cover maps PyWAsP expects vector maps as input. Therefore, PyWAsP enables conversion from raster maps to vector maps, through the pywasp.raster_to_vector() function.

# Read a raster elevation map
In [8]: elev_raster = wk.read_elevation_map("source/tutorials/data/elev.tif")

# Convert to vector (contour lines)
In [9]: elev_vector = pw.raster_to_vector(elev_raster)

In [10]: print(f"Raster shape: {elev_raster.shape}")
Raster shape: (800, 800)

In [11]: print(f"Vector features: {len(elev_vector)}")
Vector features: 2386