The method that I've implemented in a couple of languages and believe that ESRI uses (sorry, no references other than Jenson and Domingue cited elsewhere in this page) is to start at a user-supplied "pour-point" cell or a cell at the edge of the flow direction grid (fdr), examine its eight neighbors to find which of those direct flow into the current cell, and assign those cells to the current "watershed" in the output grid. Then the function recursively calls itself once for each of the inflowing neighbors. This process repeats until all inflowing cells are exhausted for a pour-point, and will then repeat for all pour-points.
The recursive algorithm design can be pretty expensive because it can end up trying to hold lots of data in memory, having to swap/page to the disk, and therefore generally suffering i/o slow downs.
(see whuber's comment below about different methods of recursion, if you're gonna RYO)
_____________ EDIT _____________
Dug out my old C code as an example (note: Although most pythoners may want to run from the room, shouldn't be too bad). Thought it might be of interest to illustrate. Although I'm only now superficially familiar w/breadth-first vs depth-first recursion, I'm thinking that my routine is indeed depth-first (and that my natural language description above was misleading) based on this stackoverflow posting (hopefully @whuber or another person smarter than me can confirm/deny).
Code: explanation: idir
is the raster of flow direction values. offset
refers to the center cell that is currently being analyzed, and off
checks each of that cell's neighbors. This calls another function, does_it_flow_into_me
, which returns a boolean as to whether the neighboring cell's flowdir points to the current cell. If true for a neighbor, then recurse to that location.
void shed(int init_x, int init_y, int basin_id){
int i, j, offset, off, flow_dir;
offset = ((init_y - 1) * nc) + (init_x - 1);
*(basin + offset) = basin_id;
/* kernel analysis */
for (i = -1; i < 2; i++) {
for (j = -1; j < 2; j++) {
if ((i) || (j)) {
off = offset + (j * nc + i);
flow_dir = *(idir + off);
if (does_it_flow_into_me(i,j,flow_dir)){
shed(init_x+i, init_y+j,basin_id);
}
} /*not center */
} /* do - j */
} /* do - i */
}