double_vector_with_halo.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
27
28namespace oomph
29{
30 //============================================================================
31 /// Constructor that sets up the required information communicating
32 /// between all processors. Requires two "all to all" communications.
33 /// Arguments are the distribution of the DoubleVector and a
34 /// Vector of global unknowns required on this processor.
35 //===========================================================================
39 : Distribution_pt(dist_pt)
40 {
41#ifdef OOMPH_HAS_MPI
42 // Only bother to do anything if the vector is distributed
43 if (dist_pt->distributed())
44 {
45 // First create temporary maps for halo requests.
46 // Using the map structure ensures that the data will be sorted
47 // into processor order: the order of the unsigned integer key
48
49 // These are the halo requests indexed by master processor and the
50 // local equation number that is to be haloed on that processor
51 std::map<unsigned, Vector<unsigned>> to_be_haloed;
52 // These are the halo requests indexed by master processor and the
53 // index in the additional storage
54 // that corresponds to the halo data on this processor
55 std::map<unsigned, Vector<unsigned>> halo_entries;
56
57 // Find rank of current processor
58 const unsigned my_rank =
59 static_cast<int>(dist_pt->communicator_pt()->my_rank());
60 // Loop over the desired equations (on this processor)
61 // and work out whether we need to halo them according to the
62 // given distribution
63 const unsigned n_global_eqn = required_global_eqn.size();
64 // Index for the locally stored halo values
65 unsigned index = 0;
66 for (unsigned n = 0; n < n_global_eqn; n++)
67 {
68 // Cache the required GLOBAL equation number
69 const unsigned i_global = required_global_eqn[n];
70 // Where is it stored?
71 unsigned rank_of_global = dist_pt->rank_of_global_row(i_global);
72 // If the equation is not stored locally then
73 // populate the two maps
75 {
76 // Work out the local entry on the appropriate processor
77 unsigned i_local = i_global - dist_pt->first_row(rank_of_global);
78 // Mark the local storage index as halo with rank_of_global as master
79 halo_entries[rank_of_global].push_back(index);
80 // Mark the local equation of the rank_of_global as to be
81 // haloed
83 // Store the local index corresponding to the global equation
84 Local_index[i_global] = index;
85 // Increment the index
86 ++index;
87 }
88 }
89
90 // We now need to tell the other processors which of their data are
91 // haloed on this processor
92
93 // First find out how many processors there are!
94 const int n_proc = dist_pt->communicator_pt()->nproc();
95
96 // Setup storage for number of data to be sent to each processor
99 int send_data_count = 0;
100
101 // Iterate over the entries in the map
102 // This will be in rank order because of the ordering of the map
103 for (std::map<unsigned, Vector<unsigned>>::iterator it =
104 to_be_haloed.begin();
105 it != to_be_haloed.end();
106 ++it)
107 {
108 const unsigned rank = it->first;
109 const unsigned size_ = it->second.size();
110 // The displacement is the current number of data
112 // The number to send is just the size of the array
113 send_n[rank] = static_cast<int>(size_);
115 }
116
117 // Now send the number of haloed entries from every processor
118 // to every processor
119
120 // Receive the data directly into the storage for haloed daa
121 Haloed_n.resize(n_proc, 0);
123 1,
124 MPI_INT,
125 &Haloed_n[0],
126 1,
127 MPI_INT,
128 dist_pt->communicator_pt()->mpi_comm());
129
130 // Prepare the data to be sent
131 // Always resize to at least one
132 if (send_data_count == 0)
133 {
135 }
137 // Iterate over the entries in the map
138 unsigned count = 0;
139 for (std::map<unsigned, Vector<unsigned>>::iterator it =
140 to_be_haloed.begin();
141 it != to_be_haloed.end();
142 ++it)
143 {
144 // Iterate over the vector
145 for (Vector<unsigned>::iterator it2 = it->second.begin();
146 it2 != it->second.end();
147 ++it2)
148 {
149 send_data[count] = (*it2);
150 ++count;
151 }
152 }
153
154 // Prepare the data to be received,
155 // Again this can go directly into Haloed storage
156 int receive_data_count = 0;
158 for (int d = 0; d < n_proc; d++)
159 {
160 // The displacement is the amount of data received so far
163 }
164
165 // Now resize the receive buffer
166 // Always make sure that it has size of at least one
167 if (receive_data_count == 0)
168 {
170 }
172 // Send the data between all the processors
174 &send_n[0],
177 &Haloed_eqns[0],
178 &Haloed_n[0],
181 dist_pt->communicator_pt()->mpi_comm());
182
183 // Finally, we translate the map of halo entries into the permanent
184 // storage
185 Halo_n.resize(n_proc, 0);
186 Halo_displacement.resize(n_proc, 0);
187
188 // Loop over all the entries in the map
189 unsigned receive_haloed_count = 0;
190 for (int d = 0; d < n_proc; d++)
191 {
192 // Pointer to the map entry
193 std::map<unsigned, Vector<unsigned>>::iterator it =
194 halo_entries.find(d);
195 // If we don't have it in the map, skip
196 if (it == halo_entries.end())
197 {
199 Halo_n[d] = 0;
200 }
201 else
202 {
204 const int size_ = it->second.size();
205 Halo_n[d] = size_;
206 // Resize the equations to be sent
208 for (int i = 0; i < size_; i++)
209 {
210 Halo_eqns[receive_haloed_count + i] = it->second[i];
211 }
213 }
214 }
215 }
216#endif
217 }
218
219 //=====================================================================
220 /// Function that sets up a vector of pointers to halo
221 /// data, index using the scheme in Local_index. The first arguement
222 /// is a map of pointers to all halo data index by the global equation
223 /// number
224 //====================================================================
226 const std::map<unsigned, double*>& halo_data_pt,
228 {
229 // How many entries are there in the map
230 unsigned n_halo = Local_index.size();
231 // Resize the vector
232 halo_dof_pt.resize(n_halo);
233
234 // Loop over all the entries in the map
235 for (std::map<unsigned, unsigned>::iterator it = Local_index.begin();
236 it != Local_index.end();
237 ++it)
238 {
239 // Find the pointer in the halo_data_pt map
240 std::map<unsigned, double*>::const_iterator it2 =
241 halo_data_pt.find(it->first);
242 // Did we find it
243 if (it2 != halo_data_pt.end())
244 {
245 // Now set the entry
246 halo_dof_pt[it->second] = it2->second;
247 }
248 else
249 {
250 std::ostringstream error_stream;
251 error_stream << "Global equation " << it->first
252 << " reqired as halo is not stored in halo_data_pt\n";
253
254 throw OomphLibError(
256 }
257 }
258 }
259
260 //------------------------------------------------------------------
261 // Member functions for the DoubleVectorWithHaloEntries
262 //-------------------------------------------------------------------
263
264
265 //=========================================================================
266 /// Synchronise the halo data within the vector. This requires one
267 /// "all to all" communnication.
268 //====================================================================
270 {
271#ifdef OOMPH_HAS_MPI
272 // Only need to do anything if the DoubleVector is distributed
273 if (this->distributed())
274 {
275 // Read out the number of entries to send
276 const unsigned n_send = Halo_scheme_pt->Haloed_eqns.size();
278 // Read out the data values
279 for (unsigned i = 0; i < n_send; i++)
280 {
281 send_data[i] = (*this)[Halo_scheme_pt->Haloed_eqns[i]];
282 }
283
284 // Read out the number of entries to receive
285 const unsigned n_receive = Halo_scheme_pt->Halo_eqns.size();
287
288 // Make sure that the send and receive data have size at least one
289 if (n_send == 0)
290 {
291 send_data.resize(1);
292 }
293 if (n_receive == 0)
294 {
295 receive_data.resize(1);
296 }
297 // Communicate
302 &receive_data[0],
306 this->distribution_pt()->communicator_pt()->mpi_comm());
307
308
309 // Now I need simply to update my local values
310 for (unsigned i = 0; i < n_receive; i++)
311 {
313 }
314 }
315#endif
316 }
317
318 //=========================================================================
319 /// Gather all ther data from multiple processors and sum the result
320 /// which will be stored in the master copy and then synchronised to
321 /// all copies. This requires two "all to all" communications
322 //====================================================================
324 {
325#ifdef OOMPH_HAS_MPI
326 // Only need to do anything if the DoubleVector is distributed
327 if (this->distributed())
328 {
329 // Send the Halo entries to the master processor
330 const unsigned n_send = Halo_scheme_pt->Halo_eqns.size();
332 // Read out the data values
333 for (unsigned i = 0; i < n_send; i++)
334 {
336 }
337
338 // Read out the number of entries to receive
339 const unsigned n_receive = Halo_scheme_pt->Haloed_eqns.size();
341
342 // Make sure that the send and receive data have size at least one
343 if (n_send == 0)
344 {
345 send_data.resize(1);
346 }
347 if (n_receive == 0)
348 {
349 receive_data.resize(1);
350 }
351 // Communicate
356 &receive_data[0],
360 this->distribution_pt()->communicator_pt()->mpi_comm());
361
362
363 // Now I need simply to update and sum my local values
364 for (unsigned i = 0; i < n_receive; i++)
365 {
367 }
368
369 // Then synchronise
370 this->synchronise();
371 }
372#endif
373 }
374
375
376 //===================================================================
377 /// Construct the halo scheme and storage for the halo data
378 //=====================================================================
380 DoubleVectorHaloScheme* const& halo_scheme_pt)
381 {
383
384 if (Halo_scheme_pt != 0)
385 {
386 // Need to set up the halo data
387 unsigned n_halo_data = halo_scheme_pt->Local_index.size();
388
389 // Resize the halo storage
390 Halo_value.resize(n_halo_data);
391
392 // Now let's get the initial values from the other processors
393 this->synchronise();
394 }
395 }
396
397
398} // namespace oomph
cstr elem_len * i
Definition cfortran.h:603
bool distributed() const
distribution is serial or distributed
A class that stores the halo/haloed entries required when using a DoubleVectorWithHaloEntries....
Vector< int > Haloed_n
Storage for the number of haloed entries to be sent to each processor.
Vector< int > Halo_displacement
Storage for the offsets of the processor data in the receive buffer.
Vector< int > Halo_n
Storage for the number of entries to be received from each other processor.
std::map< unsigned, unsigned > Local_index
Storage for the translation scheme from global unknown to local index in the additional storage vecto...
Vector< int > Haloed_displacement
Storage for the offsets of the haloed entries for each processor in the packed Haloed_eqns array.
void setup_halo_dofs(const std::map< unsigned, double * > &halo_data_pt, Vector< double * > &halo_dof_pt)
Function that sets up a vector of pointers to halo data, index using the scheme in Local_index.
Vector< unsigned > Haloed_eqns
The haloed entries that will be sent in a format compatible with MPI_Alltoallv i.e....
DoubleVectorHaloScheme(LinearAlgebraDistribution *const &dist_pt, const Vector< unsigned > &required_global_eqn)
Constructor that sets up the required information communicating between all processors....
Vector< unsigned > Halo_eqns
Storage for all the entries that are to be received from other processors (received_from_proc0,...
void build_halo_scheme(DoubleVectorHaloScheme *const &halo_scheme_pt)
Construct the halo scheme and storage for the halo data.
DoubleVectorHaloScheme * Halo_scheme_pt
Pointer to the lookup scheme that stores information about on which processor the required informatio...
void synchronise()
Synchronise the halo data.
void sum_all_halo_and_haloed_values()
Sum all the data, store in the master (haloed) data and then synchronise.
DoubleVectorHaloScheme *& halo_scheme_pt()
Access function for halo scheme.
Vector< double > Halo_value
Vector of the halo values.
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
An OomphLibError object which should be thrown when an run-time error is encountered....
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition Vector.h:58
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).