void Garbrecht_GradientTowardsLower(const Array2D<T> &elevations, const Array2D<d8_flowdir_t> &flowdirs, garbrecht_flat_type &flats, Array2D<int32_t> &inc1){ int loops = 0; int number_incremented = -1; std::cerr<<"Setting up the inc1 matrix..."<<std::endl; inc1.resize(elevations); inc1.setAll(0); while(number_incremented!=0){ number_incremented=0; for(int i=0;i<(int)flats.size();i++){ bool increment_elevation=true; int x=flats[i].x; int y=flats[i].y; for(int n=1;n<=8;n++){ if( elevations(x+dx[n],y+dy[n])<elevations(x,y) && flowdirs(x+dx[n],y+dy[n])!=NO_FLOW && !flowdirs.isNoData(x+dx[n],y+dy[n]) ){ increment_elevation=false; break; } else if(inc1(x+dx[n],y+dy[n])<loops && elevations(x+dx[n],y+dy[n])==elevations(x,y) ){ increment_elevation=false; break; } } if(increment_elevation){ inc1(x,y)++; number_incremented++; } } loops++; } }
void FindFlats( const Array2D<T> &elevations, Array2D<int8_t> &flats ){ flats.resize(elevations); flats.setNoData(FLAT_NO_DATA); ProgressBar progress; progress.start( elevations.size() ); #pragma omp parallel for for(int y=0;y<elevations.height();y++) for(int x=0;x<elevations.width();x++){ if(elevations.isNoData(x,y)){ flats(x,y) = FLAT_NO_DATA; continue; } if(elevations.isEdgeCell(x,y)){ flats(x,y) = NOT_A_FLAT; continue; } //We'll now assume that the cell is a flat unless proven otherwise flats(x,y) = IS_A_FLAT; for(int n=1;n<=8;n++){ const int nx = x+dx[n]; const int ny = y+dy[n]; if(elevations(nx,ny)<elevations(x,y) || elevations.isNoData(nx,ny)){ flats(x,y) = NOT_A_FLAT; break; } } //We handled the base case just above the for loop } RDLOG_TIME_USE<<"Succeeded in = "<<progress.stop()<<" s"; }
static inline void TerrainProcessor(F func, const Array2D<T> &elevations, const float zscale, Array2D<float> &output){ if(elevations.getCellLengthX()!=elevations.getCellLengthY()) RDLOG_WARN<<"Cell X and Y dimensions are not equal!"; output.resize(elevations); ProgressBar progress; progress.start(elevations.size()); #pragma omp parallel for for(int y=0;y<elevations.height();y++){ progress.update(y*elevations.width()); for(int x=0;x<elevations.width();x++) if(elevations.isNoData(x,y)) output(x,y) = output.noData(); else output(x,y) = func(elevations,x,y,zscale); } RDLOG_TIME_USE<<"Wall-time = "<<progress.stop(); }
void dinf_upslope_area( const Array2D<T> &flowdirs, Array2D<U> &area ){ Array2D<int8_t> dependency; std::queue<GridCell> sources; ProgressBar progress; std::cerr<<"\nA D-infinity Upslope Area"<<std::endl; std::cerr<<"C Tarboton, D.G. 1997. A new method for the determination of flow directions and upslope areas in grid digital elevation models. Water Resources Research. Vol. 33. pp 309-319."<<std::endl; std::cerr<<"p Setting up the dependency matrix..."<<std::endl; dependency.resize(flowdirs); dependency.setAll(0); std::cerr<<"p Setting up the area matrix..."<<std::endl; area.resize(flowdirs); area.setAll(0); area.setNoData(dinf_NO_DATA); bool has_cells_without_flow_directions=false; std::cerr<<"p Calculating dependency matrix & setting noData() cells..."<<std::endl; progress.start( flowdirs.size() ); /////////////////////// //Calculate the number of "dependencies" each cell has. That is, count the //number of cells which flow into each cell. #pragma omp parallel for reduction(|:has_cells_without_flow_directions) for(int y=0;y<flowdirs.height();y++){ progress.update( y*flowdirs.width() ); for(int x=0;x<flowdirs.width();x++){ //If the flow direction of the cell is NoData, mark its area as NoData if(flowdirs.isNoData(x,y)){ area(x,y) = area.noData(); dependency(x,y) = 9; //TODO: This is an unnecessary safety precaution. This prevents the cell from ever being enqueued (an unnecessary safe guard? TODO) continue; //Only necessary if there are bugs below (TODO) } //If the cell has no flow direction, note that so we can warn the user if(flowdirs(x,y)==NO_FLOW){ has_cells_without_flow_directions=true; continue; } //TODO: More explanation of what's going on here int n_high, n_low; int nhx,nhy,nlx,nly; where_do_i_flow(flowdirs(x,y),n_high,n_low); nhx=x+dinf_dx[n_high]; nhy=y+dinf_dy[n_high]; if(n_low!=-1){ nlx = x+dinf_dx[n_low]; nly = y+dinf_dy[n_low]; } if( n_low!=-1 && flowdirs.inGrid(nlx,nly) && flowdirs(nlx,nly)!=flowdirs.noData() ) dependency(nlx,nly)++; if( flowdirs.inGrid(nhx,nhy) && flowdirs(nhx,nhy)!=flowdirs.noData() ) dependency(nhx,nhy)++; } } std::cerr<<"t Succeeded in = "<<progress.stop()<<" s"<<std::endl; if(has_cells_without_flow_directions) std::cerr<<"W \033[91mNot all cells had defined flow directions! This implies that there will be digital dams!\033[39m"<<std::endl; /////////////////////// //Find those cells which have no dependencies. These are the places to start //the flow accumulation calculation. std::cerr<<"p Locating source cells..."<<std::endl; progress.start( flowdirs.size() ); for(int y=0;y<flowdirs.height();y++){ progress.update( y*flowdirs.width() ); for(int x=0;x<flowdirs.width();x++) if(flowdirs(x,y)==flowdirs.noData()) continue; else if(flowdirs(x,y)==NO_FLOW) continue; else if(dependency(x,y)==0) sources.emplace(x,y); } std::cerr<<"t Source cells located in = "<<progress.stop()<<" s"<<std::endl; /////////////////////// //Calculate the flow accumulation by "pouring" a cell's flow accumulation //value into the cells below it, as indicated by the D-infinite flow routing //method. std::cerr<<"p Calculating up-slope areas..."<<std::endl; progress.start( flowdirs.numDataCells() ); long int ccount=0; while(sources.size()>0){ auto c = sources.front(); sources.pop(); progress.update(ccount++); if(flowdirs.isNoData(c.x,c.y)) //TODO: This line shouldn't be necessary since NoData's do not get added below continue; area(c.x,c.y)+=1; if(flowdirs(c.x,c.y)==NO_FLOW) continue; int n_high,n_low,nhx,nhy,nlx,nly; where_do_i_flow(flowdirs(c.x,c.y),n_high,n_low); nhx = c.x+dinf_dx[n_high]; nhy = c.y+dinf_dy[n_high]; float phigh,plow; area_proportion(flowdirs(c.x,c.y), n_high, n_low, phigh, plow); if(flowdirs.inGrid(nhx,nhy) && flowdirs(nhx,nhy)!=flowdirs.noData()) area(nhx,nhy)+=area(c.x,c.y)*phigh; if(n_low!=-1){ nlx = c.x+dinf_dx[n_low]; nly = c.y+dinf_dy[n_low]; if(flowdirs.inGrid(nlx,nly) && flowdirs(nlx,nly)!=flowdirs.noData()){ area(nlx,nly)+=area(c.x,c.y)*plow; if((--dependency(nlx,nly))==0) sources.emplace(nlx,nly); } } if( flowdirs.inGrid(nhx,nhy) && flowdirs(nhx,nhy)!=flowdirs.noData() && (--dependency(nhx,nhy))==0) sources.emplace(nhx,nhy); } std::cerr<<"p Succeeded in = "<<progress.stop()<<" s"<<std::endl; }
void FM_Freeman( const Array2D<E> &elevations, Array3D<float> &props, const double xparam ){ RDLOG_ALG_NAME<<"Freeman (1991) Flow Accumulation (aka MFD, MD8)"; RDLOG_CITATION<<"Freeman, T.G., 1991. Calculating catchment area with divergent flow based on a regular grid. Computers & Geosciences 17, 413–422."; RDLOG_CONFIG<<"p = "<<xparam; props.setAll(NO_FLOW_GEN); props.setNoData(NO_DATA_GEN); ProgressBar progress; progress.start(elevations.size()); #pragma omp parallel for collapse(2) for(int y=0;y<elevations.height();y++) for(int x=0;x<elevations.width();x++){ ++progress; if(elevations.isNoData(x,y)){ props(x,y,0) = NO_DATA_GEN; continue; } if(elevations.isEdgeCell(x,y)) continue; const E e = elevations(x,y); double C = 0; for(int n=1;n<=8;n++){ const int nx = x+dx[n]; const int ny = y+dy[n]; if(!elevations.inGrid(nx,ny)) continue; if(elevations.isNoData(nx,ny)) //TODO: Don't I want water to drain this way? continue; const E ne = elevations(nx,ny); if(ne<e){ const double rise = e-ne; const double run = dr[n]; const double grad = rise/run; const auto cval = std::pow(grad,xparam); props(x,y,n) = cval; C += cval; } } if(C>0){ props(x,y,0) = HAS_FLOW_GEN; C = 1/C; //TODO for(int n=1;n<=8;n++){ auto &this_por = props(x,y,n); if(this_por>0) this_por *= C; else this_por = 0; } } } progress.stop(); }