CombinedGridWellGraph::CombinedGridWellGraph(const CpGrid& grid,
                                             const Opm::EclipseStateConstPtr eclipseState,
                                             const double* transmissibilities,
                                             bool pretendEmptyGrid)
    : grid_(grid), eclipseState_(eclipseState), transmissibilities_(transmissibilities)
{
    if ( pretendEmptyGrid )
    {
        // wellsGraph not needed
        return;
    }
    wellsGraph_.resize(grid.numCells());
    const auto& cpgdim = grid.logicalCartesianSize();
    // create compressed lookup from cartesian.
    std::vector<Opm::WellConstPtr> wells  = eclipseState->getSchedule()->getWells();
    std::vector<int> cartesian_to_compressed(cpgdim[0]*cpgdim[1]*cpgdim[2], -1);
    int last_time_step = eclipseState->getSchedule()->getTimeMap()->size()-1;
    for( int i=0; i < grid.numCells(); ++i )
    {
        cartesian_to_compressed[grid.globalCell()[i]] = i;
    }
    // We assume that we know all the wells.
    for (auto wellIter= wells.begin(); wellIter != wells.end(); ++wellIter) {
        Opm::WellConstPtr well = (*wellIter);
        std::set<int> well_indices;
        Opm::CompletionSetConstPtr completionSet = well->getCompletions(last_time_step);
        for (size_t c=0; c<completionSet->size(); c++) {
            Opm::CompletionConstPtr completion = completionSet->get(c);
            int i = completion->getI();
            int j = completion->getJ();
            int k = completion->getK();
            int cart_grid_idx = i + cpgdim[0]*(j + cpgdim[1]*k);
            int compressed_idx = cartesian_to_compressed[cart_grid_idx];
            if ( compressed_idx >= 0 ) // Ignore completions in inactive cells.
            {
                well_indices.insert(compressed_idx);
            }
        }
        addCompletionSetToGraph(well_indices);
    }
}
CombinedGridWellGraph::CombinedGridWellGraph(const CpGrid& grid,
                                             const Opm::EclipseState* eclipseState,
                                             const double* transmissibilities,
                                             bool pretendEmptyGrid)
    : grid_(grid), transmissibilities_(transmissibilities)
{
    if ( pretendEmptyGrid )
    {
        // wellsGraph not needed
        return;
    }
    wellsGraph_.resize(grid.numCells());
    const auto& cpgdim = grid.logicalCartesianSize();
    // create compressed lookup from cartesian.
    std::vector<int> cartesian_to_compressed(cpgdim[0]*cpgdim[1]*cpgdim[2], -1);

    for( int i=0; i < grid.numCells(); ++i )
    {
        cartesian_to_compressed[grid.globalCell()[i]] = i;
    }
    well_indices_.init(*eclipseState, cpgdim, cartesian_to_compressed);
    std::vector<int>().swap(cartesian_to_compressed); // free memory.
    addCompletionSetToGraph();
}
std::vector<int> zoltanGraphPartitionGridOnRoot(const CpGrid& cpgrid,
                                          const CollectiveCommunication<MPI_Comm>& cc,
                                          int root)
{
    int rc;
    float ver;
    struct Zoltan_Struct *zz;
    int changes, numGidEntries, numLidEntries, numImport, numExport;
    ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
    int *importProcs, *importToPart, *exportProcs, *exportToPart;
    int argc=0;
    char** argv;
    rc = Zoltan_Initialize(argc, argv, &ver);
    zz = Zoltan_Create(cc);
    if ( rc != ZOLTAN_OK )
    {
        OPM_THROW(std::runtime_error, "Could not initialize Zoltan!");
    }

    Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
    Zoltan_Set_Param(zz, "LB_METHOD", "GRAPH");
    Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION");
    Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
    Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
    Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");
    Zoltan_Set_Param(zz, "DEBUG_LEVEL", "3");
    Zoltan_Set_Param(zz, "CHECK_GRAPH", "2");
    Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35");  /* 0-remove all, 1-remove none */

    bool pretendEmptyGrid = cc.rank()!=root;

    Dune::cpgrid::setCpGridZoltanGraphFunctions(zz, cpgrid, pretendEmptyGrid);

    rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
                             &changes,        /* 1 if partitioning was changed, 0 otherwise */
                             &numGidEntries,  /* Number of integers used for a global ID */
                             &numLidEntries,  /* Number of integers used for a local ID */
                             &numImport,      /* Number of vertices to be sent to me */
                             &importGlobalGids,  /* Global IDs of vertices to be sent to me */
                             &importLocalGids,   /* Local IDs of vertices to be sent to me */
                             &importProcs,    /* Process rank for source of each incoming vertex */
                             &importToPart,   /* New partition for each incoming vertex */
                             &numExport,      /* Number of vertices I must send to other processes*/
                             &exportGlobalGids,  /* Global IDs of the vertices I must send */
                             &exportLocalGids,   /* Local IDs of the vertices I must send */
                             &exportProcs,    /* Process to which I send each of the vertices */
                             &exportToPart);  /* Partition to which each vertex will belong */
    int size = cpgrid.numCells();
    int         rank  = cc.rank();
    std::vector<int> parts=std::vector<int>(size, rank);

    for ( int i=0; i < numExport; ++i )
    {
        parts[exportLocalGids[i]] = exportProcs[i];
    }
    cc.broadcast(&parts[0], parts.size(), root);
    Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids, &exportProcs, &exportToPart);
    Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids, &importProcs, &importToPart);
    Zoltan_Destroy(&zz);
    return parts;
}