DOLFINx
DOLFINx C++ interface
utils.h
1// Copyright (C) 2009-2022 Anders Logg and Garth N. Wells
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include <algorithm>
10#include <boost/functional/hash.hpp>
11#include <dolfinx/common/MPI.h>
12#include <mpi.h>
13#include <utility>
14#include <vector>
15
16namespace dolfinx::common
17{
18
19namespace impl
20{
22template <int N, class InputIt, class OutputIt>
23inline void copy_N(InputIt first, OutputIt result)
24{
25 for (int i = 0; i < N; ++i)
26 *result++ = *first++;
27}
28} // namespace impl
29
36template <typename U, typename V>
37std::pair<std::vector<typename U::value_type>,
38 std::vector<typename V::value_type>>
39sort_unique(const U& indices, const V& values)
40{
41 if (indices.size() != values.size())
42 throw std::runtime_error("Cannot sort two arrays of different lengths");
43
44 using T = typename std::pair<typename U::value_type, typename V::value_type>;
45 std::vector<T> data(indices.size());
46 std::transform(indices.cbegin(), indices.cend(), values.cbegin(),
47 data.begin(),
48 [](auto& idx, auto& v) -> T {
49 return {idx, v};
50 });
51
52 // Sort make unique
53 std::sort(data.begin(), data.end());
54 auto it = std::unique(data.begin(), data.end(),
55 [](auto& a, auto& b) { return a.first == b.first; });
56
57 std::vector<typename U::value_type> indices_new;
58 std::vector<typename V::value_type> values_new;
59 indices_new.reserve(data.size());
60 values_new.reserve(data.size());
61 std::transform(data.begin(), it, std::back_inserter(indices_new),
62 [](auto& d) { return d.first; });
63 std::transform(data.begin(), it, std::back_inserter(values_new),
64 [](auto& d) { return d.second; });
65
66 return {std::move(indices_new), std::move(values_new)};
67}
68
76template <class T>
77std::size_t hash_local(const T& x)
78{
79 boost::hash<T> hash;
80 return hash(x);
81}
82
94template <class T>
95std::size_t hash_global(MPI_Comm comm, const T& x)
96{
97 // Compute local hash
98 std::size_t local_hash = hash_local(x);
99
100 // Gather hash keys on root process
101 std::vector<std::size_t> all_hashes(dolfinx::MPI::size(comm));
102 MPI_Gather(&local_hash, 1, dolfinx::MPI::mpi_type<std::size_t>(),
103 all_hashes.data(), 1, dolfinx::MPI::mpi_type<std::size_t>(), 0,
104 comm);
105
106 // Hash the received hash keys
107 boost::hash<std::vector<std::size_t>> hash;
108 std::size_t global_hash = hash(all_hashes);
109
110 // Broadcast hash key to all processes
111 MPI_Bcast(&global_hash, 1, dolfinx::MPI::mpi_type<std::size_t>(), 0, comm);
112
113 return global_hash;
114}
115
116} // namespace dolfinx::common
int size(MPI_Comm comm)
Return size of the group (number of processes) associated with the communicator.
Definition: MPI.cpp:83
Miscellaneous classes, functions and types.
std::pair< std::vector< typename U::value_type >, std::vector< typename V::value_type > > sort_unique(const U &indices, const V &values)
Sort two arrays based on the values in array indices. Any duplicate indices and the corresponding val...
Definition: utils.h:39
std::size_t hash_global(MPI_Comm comm, const T &x)
Compute a hash for a distributed (MPI) object.
Definition: utils.h:95
std::size_t hash_local(const T &x)
Compute a hash of a given object.
Definition: utils.h:77