Exemplo n.º 1
0
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 priority_flood_epsilon(Array2D<elev_t> &elevations)
{
    grid_cellz_pq<elev_t> open;
    std::queue<grid_cellz<elev_t> > pit;
    ProgressBar progress;
    unsigned long processed_cells = 0;
    unsigned long pitc = 0;
    auto PitTop = elevations.noData();
    int false_pit_cells = 0;

    std::cerr << "\n###Priority-Flood+Epsilon" << std::endl;
    std::cerr << "Setting up boolean flood array matrix..." << std::flush;
    Array2D<int8_t> closed(elevations.viewWidth(), elevations.viewHeight(), false);
    std::cerr << "succeeded." << std::endl;

    std::cerr << "The priority queue will require approximately "
              << (elevations.viewWidth() * 2 + elevations.viewHeight() * 2)*((long)sizeof(grid_cellz<elev_t>)) / 1024 / 1024
              << "MB of RAM."
              << std::endl;
    std::cerr << "Adding cells to the priority queue..." << std::flush;
    for (int x = 0; x < elevations.viewWidth(); x++)
    {
        open.push_cell(x, 0, elevations(x, 0));
        open.push_cell(x, elevations.viewHeight() - 1, elevations(x, elevations.viewHeight() - 1));
        closed(x, 0) = true;
        closed(x, elevations.viewHeight() - 1) = true;
    }
    for (int y = 1; y < elevations.viewHeight() - 1; y++)
    {
        open.push_cell(0, y, elevations(0, y));
        open.push_cell(elevations.viewWidth() - 1, y, elevations(elevations.viewWidth() - 1, y));
        closed(0, y) = true;
        closed(elevations.viewWidth() - 1, y) = true;
    }
    std::cerr << "succeeded." << std::endl;

    std::cerr << "%%Performing Priority-Flood+Epsilon..." << std::endl;
    progress.start(elevations.viewWidth()*elevations.viewHeight());
    while (open.size() > 0 || pit.size()>0)
    {
        grid_cellz<elev_t> c;
        if (pit.size() > 0 && open.size() > 0 && open.top().z == pit.front().z)
        {
            c = open.top();
            open.pop();
            PitTop = elevations.noData();
        }
        else if (pit.size() > 0)
        {
            c = pit.front();
            pit.pop();
            if (PitTop == elevations.noData())
                PitTop = elevations(c.x, c.y);
        }
        else
        {
            c = open.top();
            open.pop();
            PitTop = elevations.noData();
        }
        processed_cells++;

        for (int n = 1; n <= 8; n++)
        {
            int nx = c.x + dx[n];
            int ny = c.y + dy[n];

            if (!elevations.in_grid(nx, ny)) continue;

            if (closed(nx, ny))
                continue;
            closed(nx, ny) = true;

            if (elevations(nx, ny) == elevations.noData())
                pit.push(grid_cellz<elev_t>(nx, ny, elevations.noData()));

            else if (elevations(nx, ny) <= nextafterf(c.z, std::numeric_limits<float>::infinity()))
            {
                if (PitTop != elevations.noData() && PitTop < elevations(nx, ny) && nextafterf(c.z, std::numeric_limits<float>::infinity()) >= elevations(nx, ny))
                    ++false_pit_cells;
                ++pitc;
                elevations(nx, ny) = nextafterf(c.z, std::numeric_limits<float>::infinity());
                pit.push(grid_cellz<elev_t>(nx, ny, elevations(nx, ny)));
            }
            else
                open.push_cell(nx, ny, elevations(nx, ny));
        }
        progress.update(processed_cells);
    }
    std::cerr << "\t\033[96msucceeded in " << progress.stop() << "s.\033[39m" << std::endl;
    std::cerr << processed_cells << " cells processed. " << pitc << " in pits." << std::endl;
    if (false_pit_cells)
        std::cerr << "\033[91mIn assigning negligible gradients to depressions, some depressions rose above the surrounding cells. This implies that a larger storage type should be used. The problem occured for " << false_pit_cells << " of " << elevations.numDataCells() << std::endl;
}