[GRASS-user] How to find elevation drop for all cells in a basin

Specifically, I have outlets and basins. I can find the (x,y) location of the outlet for every cell in each basin using the following code. Note that I'm doing this for all cells in the basin, not just stream cells. The r.stream.order does provide elev_drop. I'd like this for non-stream cells too, for each basin.

Assuming that I have a outlets with unique IDs, I can create basins for each outlet with:

# dir comes from r.stream.extract
r.stream.basins -m direction=dir points=outlets basins=basins

g.copy basins,cat_x
g.copy basins,cat_y

I can then export the x and y location of each outlet to a file:

r.out.xyz input=outlets | awk -F'|' '{print $3, $1}' > ./tmp/outlets_x
r.out.xyz input=outlets | awk -F'|' '{print $3, $2}' > ./tmp/outlets_y

I can then copy my basins (same categories as outlets) and change the category to x and y.

r.category map=cat_x rules=./tmp/outlets_x separator=space
r.category map=cat_y rules=./tmp/outlets_y separator=space

Note: There is probably a way to combine the above r.out.xyz and r.category commands so that I don't need to use a temporary disk file.

Finally, convert x and y from category to value

r.mapcalc "outlet_x = @cat_x"
r.mapcalc "outlet_y = @cat_y"

I can then use outlet_x and outlet_y, for example in r.mapcalc to find the direct distance between each inland cell and the outlet:

r.mapcalc "dist = (outlet_x^2 + outlet_y^2)^(0.5)"

Rather than finding the distance from each inland cell to its outlet, I'd like to find the elevation change from each inland cell to its outlet. Is this possible to do efficiently in the Bash interface to GRASS? I can do it with some loops in Python but prefer to stay in Bash if possible.

Thanks,

  -k.

On Tue, Dec 15, 2020 at 1:10 PM Ken Mankoff <mankoff@gmail.com> wrote:

Specifically, I have outlets and basins. I can find the (x,y) location of the outlet for every cell in each basin using the following code. Note that I’m doing this for all cells in the basin, not just stream cells. The r.stream.order does provide elev_drop. I’d like this for non-stream cells too, for each basin.

Assuming that I have a outlets with unique IDs, I can create basins for each outlet with:

dir comes from r.stream.extract

r.stream.basins -m direction=dir points=outlets basins=basins

g.copy basins,cat_x
g.copy basins,cat_y

I can then export the x and y location of each outlet to a file:

r.out.xyz input=outlets | awk -F’|’ ‘{print $3, $1}’ > ./tmp/outlets_x
r.out.xyz input=outlets | awk -F’|’ ‘{print $3, $2}’ > ./tmp/outlets_y

I can then copy my basins (same categories as outlets) and change the category to x and y.

r.category map=cat_x rules=./tmp/outlets_x separator=space
r.category map=cat_y rules=./tmp/outlets_y separator=space

Note: There is probably a way to combine the above r.out.xyz and r.category commands so that I don’t need to use a temporary disk file.

Finally, convert x and y from category to value

r.mapcalc “outlet_x = @cat_x
r.mapcalc “outlet_y = @cat_y

I can then use outlet_x and outlet_y, for example in r.mapcalc to find the direct distance between each inland cell and the outlet:

r.mapcalc “dist = (outlet_x^2 + outlet_y^2)^(0.5)”

Rather than finding the distance from each inland cell to its outlet, I’d like to find the elevation change from each inland cell to its outlet. Is this possible to do efficiently in the Bash interface to GRASS? I can do it with some loops in Python but prefer to stay in Bash if possible.

I admit I haven’t read the entire email, but isn’t r.stream.distance what you need?

Anna

Thanks,

-k.


grass-user mailing list
grass-user@lists.osgeo.org
https://lists.osgeo.org/mailman/listinfo/grass-user

Hi Ken,

What exactly do you mean by elevation drop (at each cell)? I can only guess…

Tom

···

Thomas E Adams, III
1724 Sage Lane
Blacksburg, VA 24060
tea3rd@gmail.com (personal)
tea@terrapredictions.org (work)

1 (513) 739-9512 (cell)

Hi Anna,

On 2020-12-15 at 11:29 -08, Anna Petrášová <kratochanna@gmail.com> wrote...

isn't r.stream.distance what you need?

Yes that is what I need. I did not realize it worked for the non-stream cells too.

Thank you,

  -k.

Hi Thomas,

On 2020-12-15 at 11:34 -08, Thomas Adams <tea3rd@gmail.com> wrote...

What exactly do you mean by elevation drop (at each cell)? I can only guess…

I meant the change in each cell between their elevation and the elevation of the associated hydrologic outlet cell.

I actually need to query a different raster than change in elevation, but it seems like I can pass any cost surface I want as the elevation parameter to r.stream.distance and it works. I think it uses the input direction raster to calculate the outlet for each source, then queries the input and output "elevation" raster (in my case some other cost surface), regardless of what those values represent.

  -k.

Hi Ken,

So, if I understand, that seems pretty simple and could be done with r.mapcalc:

diff = elev - outlet_elev

where elev is a raster map of elevations and outlet_elev is the elevation at the basin outlet. Using a basin mask the calculation could be confined to any basin of interest. But, I am probably missing something, I think…

Tom

···

Thomas E Adams, III
1724 Sage Lane
Blacksburg, VA 24060
tea3rd@gmail.com (personal)
tea@terrapredictions.org (work)

1 (513) 739-9512 (cell)

On 2020-12-15 at 12:28 -08, Thomas Adams <tea3rd@gmail.com> wrote...

So, if I understand, that seems pretty simple and could be done with
r.mapcalc:

diff = elev - outlet_elev

where elev is a raster map of elevations and outlet_elev is the elevation
at the basin outlet. Using a basin mask the calculation could be confined
to any basin of interest. But, I am probably missing something, I think…

One of us is missing something, but I'm happy to assume it is me :).

If outlet_elev is only defined at the outlets, diff is only defined at the outlets. I want it defined for every inland cell in every basin. I have 1,000s of basins.

How do I define outlet_elev everywhere? I can do it now using r.stream.distance but prior to Anna suggesting that, I didn't know how to do it. Is there some trick like for each basin I set the category to the elevation of the outlet, and then use mapcalc @math function to create the outlet_elev raster?

  -k.

Hi Ken!

So, presumably, you know the locations of all the basin outlets (lat-long, e.g.). Using v.what.rast, query the elevation map to get the elevation at the basin outlet (locations) that the vector points identify. This associates the basin outlet elevation with its location. Assuming you have a single elevation map, you’ll need to mask the elevation map to use the method I suggested. You can get the basin boundary – if these are not already identified – to create a mask using r.water.outlet. For each basin, set the MASK and do the r.mapcalc calculation I proposed, because you know the outlet elevation and the elevation at all cells within the MASKed basin area. r.mapcalc will create a new map ‘diff’ comprised of the elevation differences between the elevation at the basin outlet and all other cells in the basin. The elevation difference at the basin outlet will be ZERO.

The whole process is easily scriptable. I have done this kind of thing a fair amount, FWIW…

Later, after all the diff maps have been created, you could (if you wanted/needed to) patch them together or do statistics on them, etc. I hope all this makes sense…

Best,
Tom

···

Thomas E Adams, III
1724 Sage Lane
Blacksburg, VA 24060
tea3rd@gmail.com (personal)
tea@terrapredictions.org (work)

1 (513) 739-9512 (cell)

I agree this would work. Given that I have 65036 basins, I was trying to avoid a loop. But if it's fast, who cares... I will try this method.

Thanks,

  -k.

On 2020-12-16 at 08:29 -08, Thomas Adams <tea3rd@gmail.com> wrote...

Hi Ken!

So, presumably, you know the locations of all the basin outlets
(lat-long, e.g.). Using *v.what.rast*, query the elevation map to get
the elevation at the basin outlet (locations) that the vector points
identify. This associates the basin outlet elevation with its
location. Assuming you have a single elevation map, you'll need to
mask the elevation map to use the method I suggested. You can get the
basin boundary -- if these are not already identified -- to create a
mask using *r.water.outlet*. For each basin, set the MASK and do the
r.mapcalc calculation I proposed, because you know the outlet
elevation and the elevation at all cells within the MASKed basin area.
r.mapcalc will create a new map 'diff' comprised of the elevation
differences between the elevation at the basin outlet and all other
cells in the basin. The elevation difference at the basin outlet will
be ZERO.

The whole process is easily scriptable. I have done this kind of thing
a fair amount, FWIW...

Later, after all the diff maps have been created, you could (if you
wanted/needed to) patch them together or do statistics on them, etc. I
hope all this makes sense...

Best, Tom

On Tue, Dec 15, 2020 at 3:52 PM Ken Mankoff <mankoff@gmail.com> wrote:

On 2020-12-15 at 12:28 -08, Thomas Adams <tea3rd@gmail.com> wrote...
> So, if I understand, that seems pretty simple and could be done
> with r.mapcalc:
>
> diff = elev - outlet_elev
>
> where elev is a raster map of elevations and outlet_elev is the
> elevation at the basin outlet. Using a basin mask the calculation
> could be confined to any basin of interest. But, I am probably
> missing something, I think…

One of us is missing something, but I'm happy to assume it is me :).

If outlet_elev is only defined at the outlets, diff is only defined
at the outlets. I want it defined for every inland cell in every
basin. I have 1,000s of basins.

How do I define outlet_elev everywhere? I can do it now using
r.stream.distance but prior to Anna suggesting that, I didn't know
how to do it. Is there some trick like for each basin I set the
category to the elevation of the outlet, and then use mapcalc @math
function to create the outlet_elev raster?

  -k.