openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
SF_network.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
12 #ifndef _SF_NETWORK_H
13 #define _SF_NETWORK_H
14 
15 #include <mpi.h>
16 
17 #include "SF_container.h"
18 #include "SF_globals.h"
19 #include "SF_vector.h"
20 
21 namespace SF {
22 
31 template<class T, class S>
32 inline void MPI_Exchange(commgraph<T> & grph,
33  vector<S> & send,
34  vector<S> & recv,
35  MPI_Comm comm)
36 {
37  int size, rank;
38  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
39 
40  size_t numsend = 0, numrecv = 0;
41  for(int i=0; i<size; i++) {
42  if(grph.scnt[i]) numsend++;
43  if(grph.rcnt[i]) numrecv++;
44  }
45 
46  vector<MPI_Request> sreq(numsend), rreq(numrecv);
47  vector<MPI_Status> stat(numsend > numrecv ? numsend : numrecv);
48 
49  size_t sidx = 0, ridx = 0;
50  for(int i=0; i<size; i++) {
51  if(grph.rcnt[i])
52  MPI_Irecv(recv.data() + grph.rdsp[i], grph.rcnt[i]*sizeof(S), MPI_BYTE, i, SF_MPITAG, comm, rreq.data()+ridx++);
53  if(grph.scnt[i])
54  MPI_Isend(send.data() + grph.sdsp[i], grph.scnt[i]*sizeof(S), MPI_BYTE, i, SF_MPITAG, comm, sreq.data()+sidx++);
55  }
56 
57  if( (ridx != numrecv) || (sidx != numsend) )
58  fprintf(stderr, "Rank %d: MPI_Exchange error! \n", rank);
59 
60  MPI_Waitall(ridx, rreq.data(), stat.data());
61  MPI_Waitall(sidx, sreq.data(), stat.data());
62 }
63 
64 
76 template<class T>
77 inline T parallel_fallback_value(const vector<T> & vec, MPI_Comm comm)
78 {
79  int rank, size;
80  MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &size);
81 
82  vector<size_t> vec_sizes(size);
83  size_t lsize = vec.size();
84 
85  MPI_Allgather(&lsize, sizeof(size_t), MPI_BYTE, vec_sizes.data(), sizeof(size_t), MPI_BYTE, comm);
86 
87  int fallback_rank = 0;
88  while(fallback_rank < size && vec_sizes[fallback_rank] == 0) fallback_rank++;
89 
90  assert(vec_sizes[fallback_rank]);
91 
92  T fallback_value = T();
93  if(rank == fallback_rank)
94  fallback_value = vec[0];
95 
96  MPI_Bcast(&fallback_value, sizeof(T), MPI_BYTE, fallback_rank, comm);
97 
98  return fallback_value;
99 }
100 
101 
110 template<class T>
111 inline T global_min(const vector<T> & vec, MPI_Comm comm)
112 {
113  int size;
114  MPI_Comm_size(comm, &size);
115 
116  int zero_size_err = 0;
117  if(vec.size() == 0) zero_size_err++;
118  MPI_Allreduce(MPI_IN_PLACE, &zero_size_err, 1, MPI_INT, MPI_SUM, comm);
119 
120  T fb = T();
121  if(zero_size_err)
122  fb = parallel_fallback_value(vec, comm);
123 
124  vector<T> mins(size);
125 
126  T lmin = vec.size() ? *std::min_element(vec.begin(), vec.end()) : fb;
127  MPI_Allgather(&lmin, sizeof(T), MPI_BYTE, mins.data(), sizeof(T), MPI_BYTE, comm);
128  T gmin = *std::min_element(mins.begin(), mins.end());
129 
130  return gmin;
131 }
140 template<class T>
141 inline T global_max(const vector<T> & vec, MPI_Comm comm)
142 {
143  int size;
144  MPI_Comm_size(comm, &size);
145 
146  int zero_size_err = 0;
147  if(vec.size() == 0) zero_size_err++;
148  MPI_Allreduce(MPI_IN_PLACE, &zero_size_err, 1, MPI_INT, MPI_SUM, comm);
149 
150  T fb = T();
151  if(zero_size_err)
152  fb = parallel_fallback_value(vec, comm);
153 
154  vector<T> max(size);
155 
156  T lmax = vec.size() ? *std::max_element(vec.begin(), vec.end()) : fb;
157  MPI_Allgather(&lmax, sizeof(T), MPI_BYTE, max.data(), sizeof(T), MPI_BYTE, comm);
158  T gmax = *std::max_element(max.begin(), max.end());
159 
160  return gmax;
161 }
170 template<class T>
171 inline T global_max(const T val, MPI_Comm comm)
172 {
173  int size;
174  MPI_Comm_size(comm, &size);
175  vector<T> max(size);
176 
177  MPI_Allgather(&val, sizeof(T), MPI_BYTE, max.data(), sizeof(T), MPI_BYTE, comm);
178  T gmax = *std::max_element(max.begin(), max.end());
179 
180  return gmax;
181 }
182 
185 template<class T> inline
186 void layout_from_count(const T count, vector<T> & layout, MPI_Comm comm)
187 {
188  int size;
189  MPI_Comm_size(comm, &size);
190  vector<T> cnt(size);
191 
192  MPI_Allgather(&count, sizeof(T), MPI_BYTE, cnt.data(), sizeof(T), MPI_BYTE, comm);
193  dsp_from_cnt(cnt, layout);
194 }
195 
196 template<class T> inline
197 T index_in_layout(const T idx, const vector<T> & layout)
198 {
199  T li = 0, end = layout.size() - 1;
200 
201  while(li < end && !(layout[li] <= idx && layout[li+1] > idx))
202  li++;
203 
204  return li;
205 }
206 
207 
209 template<class T> inline
210 void make_global(const vector<T> & vec, vector<T> & out, MPI_Comm comm)
211 {
212  int vecsize = vec.size()*sizeof(T);
213  vector<int> cnt, dsp;
214  layout_from_count(vecsize, dsp, comm);
215  cnt_from_dsp(dsp, cnt);
216 
217  out.resize(sum(cnt)/sizeof(T));
218  MPI_Allgatherv(vec.data(), vecsize, MPI_BYTE, out.data(), cnt.data(), dsp.data(), MPI_BYTE, comm);
219 }
220 
221 template<class T> inline
222 void make_global(vector<T> & vec, MPI_Comm comm)
223 {
224  vector<T> out;
225  make_global(vec, out, comm);
226  vec = out;
227 }
228 
229 }
230 #endif
Basic containers.
#define SF_MPITAG
the MPI tag when communicating
Definition: SF_globals.h:15
The vector class and related algorithms.
The class holds the communication graph for a MPI_Exchange() call.
Definition: SF_container.h:623
vector< T > rcnt
Number of elements received from each rank.
Definition: SF_container.h:627
vector< T > scnt
Number of elements sent to each rank.
Definition: SF_container.h:625
vector< T > sdsp
Displacements w.r.t. scnt.
Definition: SF_container.h:626
vector< T > rdsp
Displacements w.r.t. rcnt.
Definition: SF_container.h:628
size_t size() const
The current size of the vector.
Definition: SF_vector.h:89
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:194
const T * end() const
Pointer to the vector's end.
Definition: SF_vector.h:113
const T * begin() const
Pointer to the vector's start.
Definition: SF_vector.h:101
T * data()
Pointer to the vector's start.
Definition: SF_vector.h:76
Definition: dense_mat.hpp:19
void cnt_from_dsp(const vector< T > &dsp, vector< T > &cnt)
Compute counts from displacements.
Definition: SF_vector.h:304
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
Definition: SF_vector.h:295
void make_global(const vector< T > &vec, vector< T > &out, MPI_Comm comm)
make a parallel vector global
Definition: SF_network.h:210
T sum(const vector< T > &vec)
Compute sum of a vector's entries.
Definition: SF_vector.h:325
void count(const vector< T > &data, vector< S > &cnt)
Count number of occurrences of indices.
Definition: SF_vector.h:317
T parallel_fallback_value(const vector< T > &vec, MPI_Comm comm)
Get a fallback value for operations on parallel vectors if the local vector is of 0 size.
Definition: SF_network.h:77
T global_min(const vector< T > &vec, MPI_Comm comm)
Compute the global minimum of a distributed vector.
Definition: SF_network.h:111
void MPI_Exchange(commgraph< T > &grph, vector< S > &send, vector< S > &recv, MPI_Comm comm)
Exchange data in parallel over MPI.
Definition: SF_network.h:32
T index_in_layout(const T idx, const vector< T > &layout)
Definition: SF_network.h:197
void layout_from_count(const T count, vector< T > &layout, MPI_Comm comm)
Definition: SF_network.h:186
T global_max(const vector< T > &vec, MPI_Comm comm)
Compute the global maximum of a distributed vector.
Definition: SF_network.h:141
constexpr T max(T a, T b)
Definition: ion_type.h:16