openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
SF_network.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
27 #ifndef _SF_NETWORK_H
28 #define _SF_NETWORK_H
29 
30 #include <mpi.h>
31 
32 #include "SF_container.h"
33 #include "SF_globals.h"
34 #include "SF_vector.h"
35 
36 namespace SF {
37 
46 template<class T, class S>
47 inline void MPI_Exchange(commgraph<T> & grph,
48  vector<S> & send,
49  vector<S> & recv,
50  MPI_Comm comm)
51 {
52  int size, rank;
53  MPI_Comm_size(comm, &size); MPI_Comm_rank(comm, &rank);
54 
55  size_t numsend = 0, numrecv = 0;
56  for(int i=0; i<size; i++) {
57  if(grph.scnt[i]) numsend++;
58  if(grph.rcnt[i]) numrecv++;
59  }
60 
61  vector<MPI_Request> sreq(numsend), rreq(numrecv);
62  vector<MPI_Status> stat(numsend > numrecv ? numsend : numrecv);
63 
64  size_t sidx = 0, ridx = 0;
65  for(int i=0; i<size; i++) {
66  if(grph.rcnt[i])
67  MPI_Irecv(recv.data() + grph.rdsp[i], grph.rcnt[i]*sizeof(S), MPI_BYTE, i, SF_MPITAG, comm, rreq.data()+ridx++);
68  if(grph.scnt[i])
69  MPI_Isend(send.data() + grph.sdsp[i], grph.scnt[i]*sizeof(S), MPI_BYTE, i, SF_MPITAG, comm, sreq.data()+sidx++);
70  }
71 
72  if( (ridx != numrecv) || (sidx != numsend) )
73  fprintf(stderr, "Rank %d: MPI_Exchange error! \n", rank);
74 
75  MPI_Waitall(ridx, rreq.data(), stat.data());
76  MPI_Waitall(sidx, sreq.data(), stat.data());
77 }
78 
79 
91 template<class T>
92 inline T parallel_fallback_value(const vector<T> & vec, MPI_Comm comm)
93 {
94  int rank, size;
95  MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &size);
96 
97  vector<size_t> vec_sizes(size);
98  size_t lsize = vec.size();
99 
100  MPI_Allgather(&lsize, sizeof(size_t), MPI_BYTE, vec_sizes.data(), sizeof(size_t), MPI_BYTE, comm);
101 
102  int fallback_rank = 0;
103  while(fallback_rank < size && vec_sizes[fallback_rank] == 0) fallback_rank++;
104 
105  assert(vec_sizes[fallback_rank]);
106 
107  T fallback_value = T();
108  if(rank == fallback_rank)
109  fallback_value = vec[0];
110 
111  MPI_Bcast(&fallback_value, sizeof(T), MPI_BYTE, fallback_rank, comm);
112 
113  return fallback_value;
114 }
115 
116 
125 template<class T>
126 inline T global_min(const vector<T> & vec, MPI_Comm comm)
127 {
128  int size;
129  MPI_Comm_size(comm, &size);
130 
131  int zero_size_err = 0;
132  if(vec.size() == 0) zero_size_err++;
133  MPI_Allreduce(MPI_IN_PLACE, &zero_size_err, 1, MPI_INT, MPI_SUM, comm);
134 
135  T fb = T();
136  if(zero_size_err)
137  fb = parallel_fallback_value(vec, comm);
138 
139  vector<T> mins(size);
140 
141  T lmin = vec.size() ? *std::min_element(vec.begin(), vec.end()) : fb;
142  MPI_Allgather(&lmin, sizeof(T), MPI_BYTE, mins.data(), sizeof(T), MPI_BYTE, comm);
143  T gmin = *std::min_element(mins.begin(), mins.end());
144 
145  return gmin;
146 }
155 template<class T>
156 inline T global_max(const vector<T> & vec, MPI_Comm comm)
157 {
158  int size;
159  MPI_Comm_size(comm, &size);
160 
161  int zero_size_err = 0;
162  if(vec.size() == 0) zero_size_err++;
163  MPI_Allreduce(MPI_IN_PLACE, &zero_size_err, 1, MPI_INT, MPI_SUM, comm);
164 
165  T fb = T();
166  if(zero_size_err)
167  fb = parallel_fallback_value(vec, comm);
168 
169  vector<T> max(size);
170 
171  T lmax = vec.size() ? *std::max_element(vec.begin(), vec.end()) : fb;
172  MPI_Allgather(&lmax, sizeof(T), MPI_BYTE, max.data(), sizeof(T), MPI_BYTE, comm);
173  T gmax = *std::max_element(max.begin(), max.end());
174 
175  return gmax;
176 }
185 template<class T>
186 inline T global_max(const T val, MPI_Comm comm)
187 {
188  int size;
189  MPI_Comm_size(comm, &size);
190  vector<T> max(size);
191 
192  MPI_Allgather(&val, sizeof(T), MPI_BYTE, max.data(), sizeof(T), MPI_BYTE, comm);
193  T gmax = *std::max_element(max.begin(), max.end());
194 
195  return gmax;
196 }
197 
200 template<class T> inline
201 void layout_from_count(const T count, vector<T> & layout, MPI_Comm comm)
202 {
203  int size;
204  MPI_Comm_size(comm, &size);
205  vector<T> cnt(size);
206 
207  MPI_Allgather(&count, sizeof(T), MPI_BYTE, cnt.data(), sizeof(T), MPI_BYTE, comm);
208  dsp_from_cnt(cnt, layout);
209 }
210 
211 template<class T> inline
212 T index_in_layout(const T idx, const vector<T> & layout)
213 {
214  T li = 0, end = layout.size() - 1;
215 
216  while(li < end && !(layout[li] <= idx && layout[li+1] > idx))
217  li++;
218 
219  return li;
220 }
221 
222 
224 template<class T> inline
225 void make_global(const vector<T> & vec, vector<T> & out, MPI_Comm comm)
226 {
227  int vecsize = vec.size()*sizeof(T);
228  vector<int> cnt, dsp;
229  layout_from_count(vecsize, dsp, comm);
230  cnt_from_dsp(dsp, cnt);
231 
232  out.resize(sum(cnt)/sizeof(T));
233  MPI_Allgatherv(vec.data(), vecsize, MPI_BYTE, out.data(), cnt.data(), dsp.data(), MPI_BYTE, comm);
234 }
235 
236 template<class T> inline
237 void make_global(vector<T> & vec, MPI_Comm comm)
238 {
239  vector<T> out;
240  make_global(vec, out, comm);
241  vec = out;
242 }
243 
244 }
245 #endif
Definition: dense_mat.hpp:34
T global_min(const vector< T > &vec, MPI_Comm comm)
Compute the global minimum of a distributed vector.
Definition: SF_network.h:126
The vector class and related algorithms.
T index_in_layout(const T idx, const vector< T > &layout)
Definition: SF_network.h:212
void layout_from_count(const T count, vector< T > &layout, MPI_Comm comm)
Definition: SF_network.h:201
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:47
constexpr T max(T a, T b)
Definition: ion_type.h:31
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:92
Basic containers.
#define SF_MPITAG
the MPI tag when communicating
Definition: SF_globals.h:29
void count(const vector< T > &data, vector< S > &cnt)
Count number of occurrences of indices.
Definition: SF_vector.h:332
vector< T > rdsp
Displacements w.r.t. rcnt.
Definition: SF_container.h:631
T * data()
Pointer to the vector&#39;s start.
Definition: SF_vector.h:91
const T * end() const
Pointer to the vector&#39;s end.
Definition: SF_vector.h:128
The class holds the communication graph for a MPI_Exchange() call.
Definition: SF_container.h:625
void cnt_from_dsp(const vector< T > &dsp, vector< T > &cnt)
Compute counts from displacements.
Definition: SF_vector.h:319
void make_global(const vector< T > &vec, vector< T > &out, MPI_Comm comm)
make a parallel vector global
Definition: SF_network.h:225
T sum(const vector< T > &vec)
Compute sum of a vector&#39;s entries.
Definition: SF_vector.h:340
T global_max(const vector< T > &vec, MPI_Comm comm)
Compute the global maximum of a distributed vector.
Definition: SF_network.h:156
size_t size() const
The current size of the vector.
Definition: SF_vector.h:104
vector< T > scnt
Number of elements sent to each rank.
Definition: SF_container.h:628
vector< T > sdsp
Displacements w.r.t. scnt.
Definition: SF_container.h:629
const T * begin() const
Pointer to the vector&#39;s start.
Definition: SF_vector.h:116
vector< T > rcnt
Number of elements received from each rank.
Definition: SF_container.h:630
void resize(size_t n)
Resize a vector.
Definition: SF_vector.h:209
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
Definition: SF_vector.h:310