void WellConnections::init(const Opm::EclipseStateConstPtr eclipseState,
                           const std::array<int, 3>& cartesianSize,
                           const std::vector<int>& cartesian_to_compressed)
{
    std::vector<const Opm::Well*>  wells  = eclipseState->getSchedule()->getWells();
    int last_time_step = eclipseState->getSchedule()->getTimeMap()->size()-1;
    well_indices_.resize(wells.size());

    // We assume that we know all the wells.
    int index=0;
    for (const auto well : wells) {
        std::set<int>& well_indices = well_indices_[index];
        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 + cartesianSize[0]*(j + cartesianSize[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);
            }
        }
        ++index;
    }
}
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);
    }
}
void verifyWellState(const std::string& rst_filename,
                     Opm::EclipseGridConstPtr ecl_grid,
                     Opm::ScheduleConstPtr schedule) {

  well_info_type * well_info = well_info_alloc(ecl_grid->c_ptr());
  well_info_load_rstfile(well_info, rst_filename.c_str(), false);

  //Verify numwells
  int numwells = well_info_get_num_wells(well_info);
  BOOST_CHECK(numwells == (int)schedule->numWells());

  std::vector<Opm::WellConstPtr> wells = schedule->getWells();

  for (int i = 0; i < numwells; ++i) {

    //Verify wellnames
    const char * wellname = well_info_iget_well_name(well_info, i);
    Opm::WellConstPtr well = wells.at(i);
    BOOST_CHECK(wellname == well->name());

    // Verify well-head position data
    well_ts_type * well_ts = well_info_get_ts(well_info , wellname);
    well_state_type * well_state = well_ts_iget_state(well_ts, 0);
    const well_conn_type * well_head = well_state_get_wellhead(well_state, ECL_GRID_GLOBAL_GRID);
    BOOST_CHECK(well_conn_get_i(well_head) == well->getHeadI());
    BOOST_CHECK(well_conn_get_j(well_head) == well->getHeadJ());

    for (int j = 0; j < well_ts_get_size(well_ts); ++j) {
      well_state = well_ts_iget_state(well_ts, j);

      //Verify welltype
      int ert_well_type = well_state_get_type(well_state);
      WellType welltype = well->isProducer(j) ? PRODUCER : INJECTOR;
      Opm::WellInjector::TypeEnum injectortype = well->getInjectionProperties(j).injectorType;
      int ecl_converted_welltype = Opm::EclipseWriter::eclipseWellTypeMask(welltype, injectortype);
      int ert_converted_welltype = well_state_translate_ecl_type_int(ecl_converted_welltype);
      BOOST_CHECK(ert_well_type == ert_converted_welltype);

      //Verify wellstatus
      int ert_well_status = well_state_is_open(well_state) ? 1 : 0;

      Opm::WellCommon::StatusEnum status = well->getStatus(j);
      int wellstatus = Opm::EclipseWriter::eclipseWellStatusMask(status);

      BOOST_CHECK(ert_well_status == wellstatus);

      //Verify number of completion connections
      const well_conn_collection_type * well_connections = well_state_get_global_connections( well_state );
      size_t num_wellconnections = well_conn_collection_get_size(well_connections);

      int report_nr = well_state_get_report_nr(well_state);
      Opm::CompletionSetConstPtr completions_set = well->getCompletions((size_t)report_nr);

      BOOST_CHECK(num_wellconnections == completions_set->size());

      //Verify coordinates for each completion connection
      for (size_t k = 0; k < num_wellconnections; ++k) {
          const well_conn_type * well_connection = well_conn_collection_iget_const(well_connections , k);

          Opm::CompletionConstPtr completion = completions_set->get(k);

          BOOST_CHECK(well_conn_get_i(well_connection) == completion->getI());
          BOOST_CHECK(well_conn_get_j(well_connection) == completion->getJ());
          BOOST_CHECK(well_conn_get_k(well_connection) == completion->getK());
      }
    }
  }

  well_info_free(well_info);
}
void CombinedGridWellGraph::postProcessPartitioningForWells(std::vector<int>& parts)
{
    if( ! wellsGraph_.size() )
    {
        // No wells to be processed
        return;
    }
    // create compressed lookup from cartesian.
    const auto& cpgdim = grid_.logicalCartesianSize();
    std::vector<Opm::WellConstPtr> wells  = eclipseState_->getSchedule()->getWells();
    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;
    }
    int last_time_step = eclipseState_->getSchedule()->getTimeMap()->size()-1;
    // Check that all completions of a well have ended up on one process.
    // If that is not the case for well then move them manually to the
    // process that already has the most completions on it.
    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);
        if( ! completionSet->size() )
        {
            continue;
        }
        std::map<int,std::size_t> no_completions_on_proc;
        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
            {
                continue;
            }
            ++no_completions_on_proc[parts[compressed_idx]];
        }
        if ( no_completions_on_proc.size() > 1 )
        {
            // partition with the most completions on it becomes new owner
            int new_owner = std::max_element(no_completions_on_proc.begin(),
                                             no_completions_on_proc.end(),
                                             [](const std::pair<int,std::size_t>& p1,
                                                const std::pair<int,std::size_t>& p2){
                                                 return ( p1.second > p2.second );
                                             })->first;
            std::cout << "Manually moving well " << well->name() << " to partition "
                      << new_owner << std::endl;
             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
                 {
                     continue;
                 }
                 parts[compressed_idx] = new_owner;
             }
        }
    }
}