void original_priority_flood(Array2D<elev_t> &elevations)
{
    grid_cellz_pq<elev_t> open;
    unsigned long processed_cells = 0;
    unsigned long pitc = 0;
    //ProgressBar progress;

    //std::cerr << "\n###Barnes Flood" << 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::endl;
    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 the original Priority Flood..." << std::endl;
    //progress.start( elevations.viewWidth()*elevations.viewHeight() );
    while (open.size() > 0)
    {
        grid_cellz<elev_t> c = open.top();
        open.pop();
        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(c.x, c.y)) ++pitc;
            elevations(nx, ny) = std::max(elevations(nx, ny), elevations(c.x, c.y));
            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;
}
void priority_flood_watersheds(
    Array2D<elev_t> &elevations, Array2D<int32_t> &labels, bool alter_elevations
)
{
    grid_cellz_pq<elev_t> open;
    std::queue<grid_cellz<elev_t> > pit;
    unsigned long processed_cells = 0;
    unsigned long pitc = 0, openc = 0;
    int clabel = 1;  //TODO: Thought this was more clear than zero in the results.
    ProgressBar progress;

    std::cerr << "\n###Priority-Flood+Watershed Labels" << 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 << "Setting up watershed label matrix..." << std::flush;
    labels.resize(elevations.viewWidth(), elevations.viewHeight(), -1);
    labels.setNoData(-1);
    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::endl;
    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+Watershed Labels..." << std::endl;
    progress.start(elevations.viewWidth()*elevations.viewHeight());
    while (open.size() > 0 || pit.size()>0)
    {
        grid_cellz<elev_t> c;
        if (pit.size() > 0)
        {
            c = pit.front();
            pit.pop();
            pitc++;
        }
        else
        {
            c = open.top();
            open.pop();
            openc++;
        }
        processed_cells++;

        //Since all interior cells will be flowing into a cell which has already
        //been processed, the following line identifies only the edge cells of the
        //DEM. Each edge cell seeds its own watershed/basin. The result of this will
        //be many small watersheds/basins around the edge of the DEM.
        if (labels(c.x, c.y) == labels.noData() && elevations(c.x, c.y) != elevations.noData())  //Implies a cell without a label which borders the edge of the DEM or a region of no_data
            labels(c.x, c.y) = clabel++;

        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;

            //Since the neighbouring cell is not closed, its flow is directed to this
            //cell. Therefore, it is part of the same watershed/basin as this cell.
            labels(nx, ny) = labels(c.x, c.y);

            closed(nx, ny) = true;
            if (elevations(nx, ny) <= c.z)
            {
                if (alter_elevations)
                    elevations(nx, ny) = c.z;
                pit.push(grid_cellz<elev_t>(nx, ny, c.z));
            }
            else
                open.push(grid_cellz<elev_t>(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, "
              << openc << " not in pits."
              << std::endl;
}
void pit_mask(const Array2D<elev_t> &elevations, Array2D<int32_t> &pit_mask)
{
    grid_cellz_pq<elev_t> open;
    std::queue<grid_cellz<elev_t> > pit;
    unsigned long processed_cells = 0;
    unsigned long pitc = 0;
    ProgressBar progress;

    std::cerr << "\n###Pit Mask" << 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 << "Setting up the pit mask matrix..." << std::endl;
    pit_mask.resize(elevations.viewWidth(), elevations.viewHeight());
    pit_mask.setNoData(3);
    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 the pit mask..." << std::endl;
    progress.start(elevations.viewWidth()*elevations.viewHeight());
    while (open.size() > 0 || pit.size()>0)
    {
        grid_cellz<elev_t> c;
        if (pit.size() > 0)
        {
            c = pit.front();
            pit.pop();
        }
        else
        {
            c = open.top();
            open.pop();
        }
        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) <= c.z)
            {
                if (elevations(nx, ny) < c.z)
                    pit_mask(nx, ny) = 1;
                pit.push(grid_cellz<elev_t>(nx, ny, c.z));
            }
            else
            {
                pit_mask(nx, ny) = 0;
                open.push_cell(nx, ny, elevations(nx, ny));
            }
        }

        if (elevations(c.x, c.y) == elevations.noData())
            pit_mask(c.x, c.y) = pit_mask.noData();

        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;
}
void priority_flood_flowdirs(const Array2D<elev_t> &elevations, Array2D<int8_t> &flowdirs)
{
    grid_cellzk_pq<elev_t> open;
    unsigned long processed_cells = 0;
    ProgressBar progress;

    std::cerr << "\n###Priority-Flood+Flow Directions" << 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 << "Setting up the flowdirs matrix..." << std::flush;
    flowdirs.resize(elevations.viewWidth(), elevations.viewHeight());
    flowdirs.setNoData(NO_FLOW);
    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::endl;
    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));
        flowdirs(x, 0) = 3;
        flowdirs(x, elevations.viewHeight() - 1) = 7;
        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));
        flowdirs(0, y) = 1;
        flowdirs(elevations.viewWidth() - 1, y) = 5;
        closed(0, y) = true;
        closed(elevations.viewWidth() - 1, y) = true;
    }
    std::cerr << "succeeded." << std::endl;

    flowdirs(0, 0) = 2;
    flowdirs(flowdirs.viewWidth() - 1, 0) = 4;
    flowdirs(0, flowdirs.viewHeight() - 1) = 8;
    flowdirs(flowdirs.viewWidth() - 1, flowdirs.viewHeight() - 1) = 6;

    const int d8_order[9] = { 0,1,3,5,7,2,4,6,8 };
    std::cerr << "%%Performing Priority-Flood+Flow Directions..." << std::endl;
    progress.start(elevations.viewWidth()*elevations.viewHeight());
    while (open.size() > 0)
    {
        grid_cellz<elev_t> c = open.top();
        open.pop();
        processed_cells++;

        for (int no = 1; no <= 8; no++)
        {
            int n = d8_order[no];
            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())
                flowdirs(nx, ny) = flowdirs.noData();
            else
                flowdirs(nx, ny) = inverse_flow[n];

            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." << 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;
}