Program Listing for File ProcWorld.hpp

Return to documentation for file (include/dish2/world/ProcWorld.hpp)

#pragma once
#ifndef DISH2_WORLD_PROCWORLD_HPP_INCLUDE
#define DISH2_WORLD_PROCWORLD_HPP_INCLUDE

#include <cmath>
#include <functional>
#include <iostream>
#include <utility>

#include "../../../third-party/conduit/include/netuit/assign/AssignIntegrated.hpp"
#include "../../../third-party/conduit/include/netuit/assign/AssignPerfectHypercube.hpp"
#include "../../../third-party/conduit/include/netuit/assign/GenerateMetisAssignments.hpp"
#include "../../../third-party/conduit/include/uitsl/debug/audit_cast.hpp"
#include "../../../third-party/conduit/include/uitsl/debug/safe_cast.hpp"
#include "../../../third-party/conduit/include/uitsl/math/is_perfect_hypercube.hpp"
#include "../../../third-party/conduit/include/uitsl/mpi/mpi_utils.hpp"
#include "../../../third-party/conduit/include/uitsl/nonce/ThreadUidNormalizer.hpp"
#include "../../../third-party/Empirical/include/emp/base/vector.hpp"

#include "../config/cfg.hpp"
#include "../config/num_cells_global.hpp"
#include "../config/thread_idx.hpp"

#include "ThreadWorld.hpp"

namespace dish2 {

template<typename Spec>
struct ProcWorld {

  using topology_factory_t = typename Spec::topology_factory_t;

  const double dim_width {
    std::pow( dish2::num_cells_global(), 1.0 / dish2::cfg.N_DIMS() )
  };
  const emp::vector< size_t > dims =
    emp::vector< size_t >( dish2::cfg.N_DIMS(), dim_width );

  const netuit::Topology topology{ topology_factory_t{}( dims ) };

  #ifndef __EMSCRIPTEN__
  const size_t total_threads = uitsl::get_nprocs() * dish2::cfg.N_THREADS();
  const bool use_metis = !(
    (dish2::num_cells_global() % uitsl::get_nprocs() == 0)
    && (dish2::num_cells_global() % total_threads == 0)
    && uitsl::is_perfect_hypercube(
      dish2::num_cells_global(), dish2::cfg.N_DIMS()
    )
    && uitsl::is_perfect_hypercube(
      uitsl::get_nprocs(), dish2::cfg.N_DIMS()
    )
    && uitsl::is_perfect_hypercube(
      total_threads, dish2::cfg.N_DIMS()
    )
  );

  const std::pair<
    std::function<uitsl::proc_id_t(size_t)>,
    std::function<uitsl::thread_id_t(size_t)>
  > assignments = use_metis
  ? netuit::GenerateMetisAssignmentFunctors(
    uitsl::safe_cast<size_t>( uitsl::get_nprocs() ),
    dish2::cfg.N_THREADS(),
    topology
  )
  : std::pair{
    netuit::AssignPerfectHypercube<uitsl::proc_id_t>(
      dish2::cfg.N_DIMS(), dish2::num_cells_global(), uitsl::get_nprocs()
    ),
    uitsl::ThreadUidNormalizer(
      netuit::AssignPerfectHypercube<uitsl::proc_id_t>(
        dish2::cfg.N_DIMS(), dish2::num_cells_global(), uitsl::get_nprocs()
      ),
      netuit::AssignPerfectHypercube<uitsl::thread_id_t>(
        dish2::cfg.N_DIMS(), dish2::num_cells_global(), total_threads
      )
    )
  };
  #else // #ifndef __EMSCRIPTEN__
  const bool use_metis = false;
  const std::pair<
    uitsl::AssignIntegrated<uitsl::proc_id_t>,
    uitsl::AssignIntegrated<uitsl::thread_id_t>
  > assignments;
  #endif // #ifndef __EMSCRIPTEN__

  using genome_mesh_spec_t = typename Spec::genome_mesh_spec_t;
  netuit::Mesh<genome_mesh_spec_t> genome_mesh{
    topology,
    assignments.second,
    assignments.first
  };

  using message_mesh_spec_t = typename Spec::message_mesh_spec_t;
  netuit::Mesh<message_mesh_spec_t> message_mesh{
    topology,
    assignments.second,
    assignments.first
  };

  using push_mesh_spec_t = typename Spec::push_mesh_spec_t;
  netuit::Mesh<push_mesh_spec_t> push_mesh{
    topology,
    assignments.second,
    assignments.first
  };

  using quorum_mesh_spec_t = typename Spec::quorum_mesh_spec_t;
  netuit::Mesh<quorum_mesh_spec_t> quorum_mesh{
    topology,
    assignments.second,
    assignments.first
  };

  using resource_mesh_spec_t = typename Spec::resource_mesh_spec_t;
  netuit::Mesh<resource_mesh_spec_t> resource_mesh{
    topology,
    assignments.second,
    assignments.first
  };

  using state_mesh_spec_t = typename Spec::state_mesh_spec_t;
  netuit::Mesh<state_mesh_spec_t> state_mesh{
    topology,
    assignments.second,
    assignments.first
  };

  ProcWorld() { if (use_metis) std::cout << "assign used metis" << std::endl; }

  dish2::ThreadWorld<Spec> MakeThreadWorld() {
    return dish2::ThreadWorld<Spec>(
      genome_mesh.GetSubmesh( dish2::thread_idx ),
      message_mesh.GetSubmesh( dish2::thread_idx ),
      push_mesh.GetSubmesh( dish2::thread_idx ),
      quorum_mesh.GetSubmesh( dish2::thread_idx ),
      resource_mesh.GetSubmesh( dish2::thread_idx ),
      state_mesh.GetSubmesh( dish2::thread_idx )
    );
  }

};

} // namespace dish2

#endif // #ifndef DISH2_WORLD_PROCWORLD_HPP_INCLUDE