File: utils.cpp

package info (click to toggle)
fenics-dolfinx 1%3A0.10.0.post4-1exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 6,028 kB
  • sloc: cpp: 36,535; python: 25,391; makefile: 226; sh: 171; xml: 55
file content (144 lines) | stat: -rw-r--r-- 5,353 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (C) 2025 Garth N. Wells
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
// SPDX-License-Identifier:    LGPL-3.0-or-later

#include "utils.h"
#include <algorithm>
#include <dolfinx/common/MPI.h>
#include <format>
#include <sstream>
#include <vector>

using namespace dolfinx;

//-----------------------------------------------------------------------------
graph::AdjacencyList<std::tuple<int, std::size_t, std::int8_t>,
                     std::pair<std::int32_t, std::int32_t>>
graph::comm_graph(const common::IndexMap& map, int root)
{
  MPI_Comm comm = map.comm();

  std::span<const int> dest = map.dest();
  int ierr;

  // Graph edge out(dest) weights
  const std::vector<std::int32_t> w_dest = map.weights_dest();

  // Group ranks by type
  const auto [local_dest, local_src] = map.rank_type(MPI_COMM_TYPE_SHARED);

  // Get number of edges for each node (rank)
  int num_edges_local = dest.size();
  std::vector<int> num_edges_remote(dolfinx::MPI::size(comm));
  ierr = MPI_Gather(&num_edges_local, 1, MPI_INT, num_edges_remote.data(), 1,
                    MPI_INT, root, comm);
  dolfinx::MPI::check_error(comm, ierr);

  // Compute displacements
  std::vector<int> disp(num_edges_remote.size() + 1, 0);
  std::partial_sum(num_edges_remote.begin(), num_edges_remote.end(),
                   std::next(disp.begin()));
  dolfinx::MPI::check_error(comm, ierr);

  // For each node (rank), get edge indices
  std::vector<int> edges_remote(disp.back());
  edges_remote.reserve(1);
  ierr = MPI_Gatherv(dest.data(), dest.size(), MPI_INT, edges_remote.data(),
                     num_edges_remote.data(), disp.data(), MPI_INT, root, comm);
  dolfinx::MPI::check_error(comm, ierr);

  // For each edge, get edge weight
  std::vector<std::int32_t> weights_remote(disp.back());
  weights_remote.reserve(1);
  ierr = MPI_Gatherv(w_dest.data(), w_dest.size(), MPI_INT32_T,
                     weights_remote.data(), num_edges_remote.data(),
                     disp.data(), MPI_INT32_T, root, comm);
  dolfinx::MPI::check_error(comm, ierr);

  // For node get local and ghost sizes
  std::vector<std::pair<std::int32_t, std::int32_t>> sizes_remote;
  {
    std::vector<std::int32_t> sizes_local(dolfinx::MPI::size(comm));
    std::int32_t size = map.size_local();
    ierr = MPI_Gather(&size, 1, MPI_INT32_T, sizes_local.data(), 1, MPI_INT32_T,
                      root, comm);
    dolfinx::MPI::check_error(comm, ierr);

    std::vector<std::int32_t> sizes_ghost(dolfinx::MPI::size(comm));
    std::int32_t num_ghosts = map.num_ghosts();
    ierr = MPI_Gather(&num_ghosts, 1, MPI_INT32_T, sizes_ghost.data(), 1,
                      MPI_INT32_T, root, comm);
    dolfinx::MPI::check_error(comm, ierr);

    std::transform(sizes_local.begin(), sizes_local.end(), sizes_ghost.begin(),
                   std::back_inserter(sizes_remote),
                   [](auto x, auto y) { return std::pair(x, y); });
  }

  // For each edge, get its local/remote marker
  std::vector<std::int8_t> markers;
  for (auto r : dest)
  {
    auto it = std::ranges::lower_bound(local_dest, r);
    if (it != local_dest.end() and *it == r)
      markers.push_back(1);
    else
      markers.push_back(0);
  }
  std::vector<std::int8_t> markers_remote(disp.back());
  ierr = MPI_Gatherv(markers.data(), markers.size(), MPI_INT8_T,
                     markers_remote.data(), num_edges_remote.data(),
                     disp.data(), MPI_INT8_T, root, comm);
  dolfinx::MPI::check_error(comm, ierr);

  std::vector<std::tuple<int, std::size_t, std::int8_t>> e_data;
  for (std::size_t i = 0; i < edges_remote.size(); ++i)
    e_data.emplace_back(edges_remote[i], weights_remote[i], markers_remote[i]);
  return graph::AdjacencyList(std::move(e_data),
                              std::vector(disp.begin(), disp.end()),
                              std::move(sizes_remote));
}
//-----------------------------------------------------------------------------
std::string graph::comm_to_json(
    const graph::AdjacencyList<std::tuple<int, std::size_t, std::int8_t>,
                               std::pair<std::int32_t, std::int32_t>>& g)
{
  const std::vector<std::pair<std::int32_t, std::int32_t>>& node_weights
      = g.node_data().value();

  std::stringstream out;
  out << std::format("{{\"directed\": true, \"multigraph\": false, \"graph\": "
                     "[], \"nodes\": [");
  for (std::int32_t n = 0; n < g.num_nodes(); ++n)
  {
    // Note: it is helpful to order map keys alphabetically
    out << std::format("{{\"num_ghosts\": {}, \"weight\": {},  \"id\": {}}}",
                       node_weights[n].second, node_weights[n].first, n);
    if (n != g.num_nodes() - 1)
      out << ", ";
  }
  out << "], ";
  out << "\"adjacency\": [";
  for (std::int32_t n = 0; n < g.num_nodes(); ++n)
  {
    out << "[";
    auto links = g.links(n);
    for (std::size_t edge = 0; edge < links.size(); ++edge)
    {
      auto [e, w, local] = links[edge];
      out << std::format("{{\"local\": {}, \"weight\": {}, \"id\": {}}}", local,
                         w, e);
      if (edge != links.size() - 1)
        out << ", ";
    }
    out << "]";
    if (n != g.num_nodes() - 1)
      out << ", ";
  }
  out << "]}";

  return out.str();
}
//-----------------------------------------------------------------------------