NEST  2.6.0,not_revisioned_source_dir@0
communicator_impl.h
Go to the documentation of this file.
1 /*
2  * communicator_impl.h
3  *
4  * This file is part of NEST.
5  *
6  * Copyright (C) 2004 The NEST Initiative
7  *
8  * NEST is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * NEST is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with NEST. If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "communicator.h"
24 #include "network.h"
25 
26 #include "config.h"
27 
28 /* To avoid problems on BlueGene/L, mpi.h MUST be the
29  first included file after config.h.
30  */
31 #ifdef HAVE_MPI
32 #include <mpi.h>
33 #endif /* #ifdef HAVE_MPI */
34 
35 #ifdef HAVE_MPI
36 
37 // Variable to hold the MPI communicator to use.
38 #ifdef HAVE_MUSIC
39 extern MPI::Intracomm comm;
40 #else /* #ifdef HAVE_MUSIC */
41 extern MPI_Comm comm;
42 #endif /* #ifdef HAVE_MUSIC */
43 
44 
45 /* ------------------------------------------------------
46  The following datatypes are defined here in communicator_impl.h
47  file instead of as static class members, to avoid inclusion
48  of mpi.h in the .h file. This is necessary, because on
49  BlueGene/L mpi.h MUST be included FIRST. Having mpi.h in
50  the .h file would lead to requirements on include-order
51  throughout the NEST code base and is not acceptable.
52  Reported by Mikael Djurfeldt.
53  Hans Ekkehard Plesser, 2010-01-28
54  */
55 template <typename T>
56 struct MPI_Type { static MPI_Datatype type; };
57 
58 template <typename T>
59 void nest::Communicator::communicate_Allgatherv(std::vector<T>& send_buffer,
60  std::vector<T>& recv_buffer,
61  std::vector<int>& displacements,
62  std::vector<int>& recv_counts)
63 {
64  //attempt Allgather
65  MPI_Allgatherv(&send_buffer[0], send_buffer.size(), MPI_Type<T>::type,
66  &recv_buffer[0], &recv_counts[0], &displacements[0], MPI_Type<T>::type, comm);
67 }
68 
69 template <typename NodeListType>
70 void nest::Communicator::communicate(const NodeListType& local_nodes,
71  vector<NodeAddressingData>& all_nodes,
72  bool remote)
73 {
74  size_t np = Communicator::num_processes_;
75  if (np > 1 && remote)
76  {
77  vector<long_t> localnodes;
78  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
79  {
80  localnodes.push_back((*n)->get_gid());
81  localnodes.push_back(((*n)->get_parent())->get_gid());
82  localnodes.push_back((*n)->get_vp());
83  }
84  //get size of buffers
85  std::vector<nest::int_t> n_nodes(np);
86  n_nodes[Communicator::rank_] = localnodes.size();
87  communicate(n_nodes);
88  // Set up displacements vector.
89  std::vector<int> displacements(np,0);
90 
91  for ( size_t i = 1; i < np; ++i )
92  displacements.at(i) = displacements.at(i-1)+n_nodes.at(i-1);
93 
94  // Calculate total number of node data items to be gathered.
95  size_t n_globals =
96  std::accumulate(n_nodes.begin(),n_nodes.end(), 0);
97  assert(n_globals % 3 == 0);
98  vector<long_t> globalnodes;
99  if (n_globals != 0)
100  {
101  globalnodes.resize(n_globals,0L);
102  communicate_Allgatherv<nest::long_t>(localnodes, globalnodes, displacements, n_nodes);
103 
104  //Create unflattened vector
105  for ( size_t i = 0; i < n_globals -2; i +=3)
106  all_nodes.push_back(NodeAddressingData(globalnodes[i],globalnodes[i+1],globalnodes[i+2]));
107 
108  //get rid of any multiple entries
109  std::sort(all_nodes.begin(), all_nodes.end());
110  vector<NodeAddressingData>::iterator it;
111  it = std::unique(all_nodes.begin(), all_nodes.end());
112  all_nodes.resize(it - all_nodes.begin());
113  }
114  }
115  else //on one proc or not including remote nodes
116  {
117  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
118  all_nodes.push_back(NodeAddressingData((*n)->get_gid(),
119  ((*n)->get_parent())->get_gid(),
120  (*n)->get_vp()));
121  std::sort(all_nodes.begin(), all_nodes.end());
122  }
123 }
124 
125 
126 template <typename NodeListType>
127 void nest::Communicator::communicate(const NodeListType& local_nodes,
128  vector<NodeAddressingData>& all_nodes,
129  Network& net, DictionaryDatum params,
130  bool remote)
131 {
132  size_t np = Communicator::num_processes_;
133 
134  if ( np > 1 && remote)
135  {
136  vector<long_t> localnodes;
137  if (params->empty())
138  {
139  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
140  {
141  localnodes.push_back((*n)->get_gid());
142  localnodes.push_back(((*n)->get_parent())->get_gid());
143  localnodes.push_back((*n)->get_vp());
144  }
145  } else {
146  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
147  {
148  //select those nodes fulfilling the key/value pairs of the dictionary
149  bool match = true;
150  index gid = (*n)->get_gid();
151  DictionaryDatum node_status = net.get_status(gid);
152  for (Dictionary::iterator i = params->begin(); i != params->end(); ++i)
153  {
154  if (node_status->known(i->first))
155  {
156  const Token token = node_status->lookup(i->first);
157  if (not ( token == i->second || token.matches_as_string(i->second) ))
158  {
159  match = false;
160  break;
161  }
162  }
163  }
164  if (match)
165  {
166  localnodes.push_back(gid);
167  localnodes.push_back(((*n)->get_parent())->get_gid());
168  localnodes.push_back((*n)->get_vp());
169  }
170  }
171  }
172 
173  //get size of buffers
174  std::vector<nest::int_t> n_nodes(np);
175  n_nodes[Communicator::rank_] = localnodes.size();
176  communicate(n_nodes);
177 
178  // Set up displacements vector.
179  std::vector<int> displacements(np,0);
180 
181  for ( size_t i = 1; i < np; ++i )
182  displacements.at(i) = displacements.at(i-1)+n_nodes.at(i-1);
183 
184  // Calculate sum of global connections.
185  size_t n_globals =
186  std::accumulate(n_nodes.begin(),n_nodes.end(), 0);
187  assert(n_globals % 3 == 0);
188  vector<long_t> globalnodes;
189  if (n_globals != 0)
190  {
191  globalnodes.resize(n_globals,0L);
192  communicate_Allgatherv<nest::long_t>(localnodes, globalnodes, displacements, n_nodes);
193 
194  //Create unflattened vector
195  for ( size_t i = 0; i < n_globals -2; i +=3)
196  all_nodes.push_back(NodeAddressingData(globalnodes[i],globalnodes[i+1],globalnodes[i+2]));
197 
198  //get rid of any multiple entries
199  std::sort(all_nodes.begin(), all_nodes.end());
200  vector<NodeAddressingData>::iterator it;
201  it = std::unique(all_nodes.begin(), all_nodes.end());
202  all_nodes.resize(it - all_nodes.begin());
203  }
204  }
205  else //on one proc or not including remote nodes
206  {
207  if (params->empty())
208  {
209  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
210  all_nodes.push_back(NodeAddressingData((*n)->get_gid(), ((*n)->get_parent())->get_gid(), (*n)->get_vp()));
211  }
212  else {
213  //select those nodes fulfilling the key/value pairs of the dictionary
214  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
215  {
216  bool match = true;
217  index gid = (*n)->get_gid();
218  DictionaryDatum node_status = net.get_status(gid);
219  for (Dictionary::iterator i = params->begin(); i != params->end(); ++i)
220  {
221  if (node_status->known(i->first))
222  {
223  const Token token = node_status->lookup(i->first);
224  if (not ( token == i->second || token.matches_as_string(i->second) ))
225  {
226  match = false;
227  break;
228  }
229  }
230  }
231  if (match)
232  all_nodes.push_back(NodeAddressingData((*n)->get_gid(), ((*n)->get_parent())->get_gid(), (*n)->get_vp()));
233  }
234  }
235  std::sort(all_nodes.begin(),all_nodes.end());
236  }
237 }
238 
239 
240 
241 #else //HAVE_MPI
242 
243 template <typename NodeListType>
244 void nest::Communicator::communicate(const NodeListType& local_nodes, vector<NodeAddressingData>& all_nodes, bool)
245 {
246  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
247  all_nodes.push_back(NodeAddressingData((*n)->get_gid(), ((*n)->get_parent())->get_gid(), (*n)->get_vp()));
248  std::sort(all_nodes.begin(),all_nodes.end());
249 }
250 
251 template <typename NodeListType>
252 void nest::Communicator::communicate(const NodeListType& local_nodes, vector<NodeAddressingData>& all_nodes,
253  Network& net, DictionaryDatum params, bool)
254 {
255 
256  if (params->empty())
257  {
258  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
259  all_nodes.push_back(NodeAddressingData((*n)->get_gid(), ((*n)->get_parent())->get_gid(), (*n)->get_vp()));
260  }
261  else {
262  //select those nodes fulfilling the key/value pairs of the dictionary
263  for ( typename NodeListType::iterator n = local_nodes.begin(); n != local_nodes.end(); ++n )
264  {
265  bool match = true;
266  index gid = (*n)->get_gid();
267  DictionaryDatum node_status = net.get_status(gid);
268  for (Dictionary::iterator i = params->begin(); i != params->end(); ++i)
269  {
270  if (node_status->known(i->first))
271  {
272  const Token token = node_status->lookup(i->first);
273  if (not ( token == i->second || token.matches_as_string(i->second) ))
274  {
275  match = false;
276  break;
277  }
278  }
279  }
280  if (match)
281  all_nodes.push_back(NodeAddressingData((*n)->get_gid(), ((*n)->get_parent())->get_gid(), (*n)->get_vp()));
282  }
283  }
284  std::sort(all_nodes.begin(),all_nodes.end());
285 }
286 
287 #endif
size_t index
Unsigned long type for enumerations.
Definition: nest.h:109
Definition: communicator_impl.h:56
static int num_processes_
the number of mpi-processes
Definition: communicator.h:220
Definition: communicator.h:110
static MPI_Datatype type
Definition: communicator_impl.h:56
static int rank_
the rank of the machine
Definition: communicator.h:219
MPI::Intracomm comm
Definition: communicator_impl.h:41
assert(pNet!=0)
static void communicate_Allgatherv(std::vector< T > &send_buffer, std::vector< T > &recv_buffer, std::vector< int > &displacements, std::vector< int > &recv_counts)
Definition: communicator_impl.h:59
static void communicate(std::vector< uint_t > &send_buffer, std::vector< uint_t > &recv_buffer, std::vector< int > &displacements)
communicate (on-grid) if compiled without MPI
Definition: communicator.cpp:239
Declarations for class Network.
Main administrative interface to the network.
Definition: network.h:135
bool matches_as_string(const Token &rhs) const
Returns true if token equals rhs as string.
Definition: token.cc:178
const Name n("n")
Number of synaptic release sites (int >=0) (Tsodyks2_connection)
Definition: nest_names.h:202
A type-independent container for C++-types.
Definition: token.h:68
DictionaryDatum get_status(index)
Get properties of a node.
Definition: network.cpp:837