void pack_graph_edge_and_chosen_side_id_to_proc(stk::CommSparse& commSparse, int otherProc, const stk::mesh::GraphEdge& graphEdge, stk::mesh::EntityId chosenSideId)
{
    commSparse.send_buffer(otherProc).pack<stk::mesh::EntityId>(graphEdge.elem1);
    commSparse.send_buffer(otherProc).pack<int>(graphEdge.side1);
    commSparse.send_buffer(otherProc).pack<stk::mesh::EntityId>(graphEdge.elem2);
    commSparse.send_buffer(otherProc).pack<int>(graphEdge.side2);
    commSparse.send_buffer(otherProc).pack<stk::mesh::EntityId>(chosenSideId);
}
void NoGhostGameofLife::pack_num_active_neighbors_into_buffer(stk::CommSparse& buffer,
                                                              int numActive, stk::mesh::EntityKey
                                                              remoteElemKey)
{
    int procNum = m_remoteElementKeyToOwningProcessor[remoteElemKey];
    buffer.send_buffer(procNum).pack<stk::mesh::EntityKey>(remoteElemKey);
    buffer.send_buffer(procNum).pack<int>(numActive);
}
void pack_edge(stk::CommSparse &comm, const ElemElemGraph& graph, const stk::mesh::BulkData& bulkData, const stk::mesh::GraphEdge& edge, int other_proc)
{
    stk::mesh::EntityId id1 = bulkData.identifier(graph.get_entity(edge.elem1()));
    unsigned side1 = edge.side1();
    stk::mesh::EntityId id2 = -edge.elem2();
    unsigned side2 = edge.side2();
    comm.send_buffer(other_proc).pack<stk::mesh::EntityId>(id1);
    comm.send_buffer(other_proc).pack<unsigned>(side1);
    comm.send_buffer(other_proc).pack<stk::mesh::EntityId>(id2);
    comm.send_buffer(other_proc).pack<unsigned>(side2);
}
void NoGhostGameofLife::fill_buffer_with_local_neighbors_of_remote_element_key(stk::mesh::EntityKey
                                                                               remoteKey,
                                                                               stk::CommSparse&
                                                                               buffer)
{
    int procNum = m_remoteElementKeyToOwningProcessor[remoteKey];
    size_t numNeighbors = m_remoteElementKeyToLocalNeighborElements[remoteKey].size();
    buffer.send_buffer(procNum).pack<stk::mesh::EntityKey>(remoteKey);
    buffer.send_buffer(procNum).pack<size_t>(numNeighbors);
    for (stk::mesh::Entity localElem : m_remoteElementKeyToLocalNeighborElements[remoteKey])
        buffer.send_buffer(procNum).pack<stk::mesh::EntityKey>(m_bulkData->entity_key(localElem));
}
void NoGhostGameofLife::fill_buffer_with_map_info(stk::mesh::Entity elem, stk::CommSparse& buffer,
                                                  std::unordered_map<int,std::unordered_set
                                                  <stk::mesh::EntityKey, std::hash
                                                  <stk::mesh::EntityKey>>>& map)
{
    for (std::pair< const int,std::unordered_set<stk::mesh::EntityKey,
            std::hash<stk::mesh::EntityKey>>>& pair : map)
    {
        int remoteProc = pair.first;
        buffer.send_buffer(remoteProc).pack<stk::mesh::EntityKey>(m_bulkData->entity_key(elem));
        buffer.send_buffer(remoteProc).pack<size_t>(pair.second.size());
        for (stk::mesh::EntityKey nodeKey : pair.second)
            buffer.send_buffer(remoteProc).pack<stk::mesh::EntityKey>(nodeKey);
    }
}
void pack_data_for_part_ordinals(stk::CommSparse &comm, const ElemElemGraph& graph, const stk::mesh::BulkData& bulkData)
{
    const stk::mesh::impl::ParallelGraphInfo& parallel_info = graph.get_parallel_graph().get_parallel_graph_info();
    for(const auto& item : parallel_info)
    {
        const stk::mesh::GraphEdge &edge = item.first;
        const stk::mesh::impl::ParallelInfo &pinfo = item.second;
        stk::mesh::Entity local_element = graph.get_entity(edge.elem1());
        std::vector<stk::mesh::PartOrdinal> partOrdinals = stk::mesh::impl::get_element_block_part_ordinals(local_element, bulkData);

        pack_edge(comm, graph, bulkData, edge, pinfo.get_proc_rank_of_neighbor());

        comm.send_buffer(pinfo.get_proc_rank_of_neighbor()).pack<size_t>(partOrdinals.size());
        for(stk::mesh::PartOrdinal partOrdinal : partOrdinals)
            comm.send_buffer(pinfo.get_proc_rank_of_neighbor()).pack<stk::mesh::PartOrdinal>(partOrdinal);
    }
}
void NoGhostGameofLife::communicate_remote_element_keys_to_check(stk::CommSparse& buffer)
{
    for (int phase = 0; phase < 2; phase++)
    {
        for (stk::mesh::EntityKey remoteElemKey : m_remoteElementKeysToVisit)
            buffer.send_buffer(m_remoteElementKeyToOwningProcessor[remoteElemKey]).
            pack<stk::mesh::EntityKey>(remoteElemKey);
        if (0 == phase)
            buffer.allocate_buffers();
        else
            buffer.communicate();
    }
}
void pack_data(stk::CommSparse& comm, const std::vector<SideSharingData>& sideSharingDataThisProc, const std::vector<stk::mesh::impl::IdViaSidePair>& idAndSides)
{
    for(size_t i=0;i<idAndSides.size();++i)
    {
        int other_proc = sideSharingDataThisProc[i].sharingProc;
        comm.send_buffer(other_proc).pack<stk::mesh::EntityId>(idAndSides[i].id);
        comm.send_buffer(other_proc).pack<int>(idAndSides[i].side);
        comm.send_buffer(other_proc).pack<stk::mesh::EntityId>(sideSharingDataThisProc[i].chosenSideId);
        comm.send_buffer(other_proc).pack<size_t>(sideSharingDataThisProc[i].sideNodes.size());
        for(stk::mesh::EntityId nodeId : sideSharingDataThisProc[i].sideNodes) {
            comm.send_buffer(other_proc).pack<stk::mesh::EntityId>(nodeId);
        }
        comm.send_buffer(other_proc).pack<size_t>(sideSharingDataThisProc[i].partOrdinals.size());
        for(stk::mesh::PartOrdinal partOrd : sideSharingDataThisProc[i].partOrdinals) {
            comm.send_buffer(other_proc).pack<stk::mesh::PartOrdinal>(partOrd);
        }
    }
}
void pack_vector_to_proc(stk::CommSparse& comm, const T& data, int otherProc)
{
    comm.send_buffer(otherProc).pack<unsigned>(data.size());
    for(size_t i=0; i<data.size(); ++i)
        comm.send_buffer(otherProc).pack<typename T::value_type>(data[i]);
}
void pack_selected_value_for_par_info(stk::CommSparse &comm, int procRank, const stk::mesh::BulkData& bulkData, stk::mesh::Entity local_element, stk::mesh::Selector sel)
{
    if(sel(bulkData.bucket(local_element)))
        comm.send_buffer(procRank).pack<int64_t>(bulkData.identifier(local_element));
}