double_multi_vector.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//====================================================================
26#include "double_multi_vector.h"
27#include "matrices.h"
28
29namespace oomph
30{
31 /// The contents of the vector are redistributed to match the new
32 /// distribution. In a non-MPI rebuild this method works, but does nothing.
33 /// \b NOTE 1: The current distribution and the new distribution must have
34 /// the same number of global rows.
35 /// \b NOTE 2: The current distribution and the new distribution must have
36 /// the same Communicator.
39 {
40#ifdef OOMPH_HAS_MPI
41#ifdef PARANOID
42 if (!Internal_values)
43 {
44 // if this vector does not own the double* values then it cannot be
45 // distributed.
46 // note: this is not stictly necessary - would just need to be careful
47 // with delete[] below.
48 std::ostringstream error_message;
49 error_message
50 << "This multi vector does not own its data (i.e. data has been "
51 << "passed in via set_external_values() and therefore "
52 << "cannot be redistributed";
53 throw OomphLibError(
55 }
56 // paranoid check that the nrows for both distributions is the
57 // same
58 if (dist_pt->nrow() != this->nrow())
59 {
60 std::ostringstream error_message;
61 error_message << "The number of global rows in the new distribution ("
62 << dist_pt->nrow() << ") is not equal to the number"
63 << " of global rows in the current distribution ("
64 << this->nrow() << ").\n";
65 throw OomphLibError(
67 }
68 // paranoid check that the current distribution and the new distribution
69 // have the same Communicator
70 OomphCommunicator temp_comm(*dist_pt->communicator_pt());
71 if (!(temp_comm == *this->distribution_pt()->communicator_pt()))
72 {
73 std::ostringstream error_message;
74 error_message << "The new distribution and the current distribution must "
75 << "have the same communicator.";
76 throw OomphLibError(
78 }
79#endif
80
81 // check the distributions are not the same
82 if (!((*this->distribution_pt()) == *dist_pt))
83 {
84 // Cache the number of vectors
85 const unsigned n_vector = this->Nvector;
86
87 // get the rank and the number of processors
88 int my_rank = this->distribution_pt()->communicator_pt()->my_rank();
89 int nproc = this->distribution_pt()->communicator_pt()->nproc();
90
91 // if both vectors are distributed
92 if (this->distributed() && dist_pt->distributed())
93 {
94 // new nrow_local and first_row data
99 for (int i = 0; i < nproc; i++)
100 {
101 new_first_row_data[i] = dist_pt->first_row(i);
102 new_nrow_local_data[i] = dist_pt->nrow_local(i);
104 current_nrow_local_data[i] = this->nrow_local(i);
105 }
106
107 // compute which local rows are expected to be received from each
108 // processor / sent to each processor
113
114 // for every processor compute first_row and nrow_local that will
115 // will sent and received by this processor
116 for (int p = 0; p < nproc; p++)
117 {
118 // start with data to be sent
123 {
131 }
132
133 // and data to be received
138 {
142 std::min(
146 }
147 }
148
149 // Storage for the new data
150 double** temp_data = new double*[n_vector];
151 double* contiguous_temp_data =
152 new double[n_vector * new_nrow_local_data[my_rank]];
153 for (unsigned v = 0; v < n_vector; ++v)
154 {
155 temp_data[v] =
157 }
158
159 // "send to self" or copy Data that does not need to be sent else where
160 // to temp_data
162 {
163 unsigned j =
165 unsigned k =
167 for (unsigned i = 0; i < new_nrow_local_for_proc[my_rank]; i++)
168 {
169 for (unsigned v = 0; v < n_vector; ++v)
170 {
171 temp_data[v][k + i] = Values[v][j + i];
172 }
173 }
174 }
175
176 // send and receive circularly
177 for (int p = 1; p < nproc; p++)
178 {
179 // next processor to send to
180 unsigned dest_p = (my_rank + p) % nproc;
181
182 // next processor to receive from
183 unsigned source_p = (nproc + my_rank - p) % nproc;
184
185 // send and receive the value
187 for (unsigned v = 0; v < n_vector; v++)
188 {
193 dest_p,
194 1,
199 source_p,
200 1,
201 this->distribution_pt()->communicator_pt()->mpi_comm(),
202 &status);
203 }
204 }
205
206 // copy from temp data to Values_pt
207 delete[] Values[0];
208 delete[] Values;
210 }
211 // if this vector is distributed but the new distributed is global
212 else if (this->distributed() && !dist_pt->distributed())
213 {
214 // copy existing Values_pt to temp_data
215 unsigned n_local_data = this->nrow_local();
216 double** temp_data = new double*[n_vector];
217 // New continguous data
218 double* contiguous_temp_data = new double[n_vector * n_local_data];
219 for (unsigned v = 0; v < n_vector; ++v)
220 {
222 for (unsigned i = 0; i < n_local_data; i++)
223 {
224 temp_data[v][i] = Values[v][i];
225 }
226 }
227
228 // clear and resize Values_pt
229 delete[] Values[0];
230 double* values = new double[this->nrow() * n_vector];
231 for (unsigned v = 0; v < n_vector; v++)
232 {
233 Values[v] = &values[v * this->nrow()];
234 }
235
236 // create a int vector of first rows
237 int* dist_first_row = new int[nproc];
238 int* dist_nrow_local = new int[nproc];
239 for (int p = 0; p < nproc; p++)
240 {
241 dist_first_row[p] = this->first_row(p);
242 dist_nrow_local[p] = this->nrow_local(p);
243 }
244
245 // gather the local vectors from all processors on all processors
246 int my_local_data(this->nrow_local());
247
248 // Loop over all vectors
249 for (unsigned v = 0; v < n_vector; v++)
250 {
252 temp_data[v],
255 Values[v],
259 this->distribution_pt()->communicator_pt()->mpi_comm());
260 }
261
262 // update the distribution
263 this->build_distribution(dist_pt);
264
265 // delete the temp_data
266 delete[] temp_data[0];
267 delete[] temp_data;
268
269 // clean up
270 delete[] dist_first_row;
271 delete[] dist_nrow_local;
272 }
273
274 // if this vector is not distrubted but the target vector is
275 else if (!this->distributed() && dist_pt->distributed())
276 {
277 // cache the new nrow_local
278 unsigned nrow_local = dist_pt->nrow_local();
279
280 // and first_row
281 unsigned first_row = dist_pt->first_row();
282
283 const unsigned n_local_data = nrow_local;
284 double** temp_data = new double*[n_vector];
285 double* contiguous_temp_data = new double[n_vector * n_local_data];
286
287 // copy the data
288 for (unsigned v = 0; v < n_vector; v++)
289 {
291 for (unsigned i = 0; i < n_local_data; i++)
292 {
293 temp_data[v][i] = Values[v][first_row + i];
294 }
295 }
296
297 // copy to Values_pt
298 delete[] Values[0];
299 delete[] Values;
301
302 // update the distribution
303 this->build_distribution(dist_pt);
304 }
305
306 // copy the Distribution
307 this->build_distribution(dist_pt);
308 }
309#endif
310
311 // Update the doublevector representation
313 }
314
315
316} // namespace oomph
cstr elem_len * i
Definition cfortran.h:603
bool distributed() const
distribution is serial or distributed
unsigned nrow() const
access function to the number of global rows.
unsigned nrow_local() const
access function for the num of local rows on this processor.
unsigned first_row() const
access function for the first row on this processor
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
setup the distribution of this distributable linear algebra object
void setup_doublevector_representation()
compute the A-norm using the matrix at matrix_pt
void redistribute(const LinearAlgebraDistribution *const &dist_pt)
Allows are external data to be used by this vector. WARNING: The size of the external data must corre...
unsigned Nvector
The number of vectors.
double ** values()
access function to the underlying values
double ** Values
the local data, need a pointer to a pointer so that the individual vectors can be extracted
bool Internal_values
Boolean flag to indicate whether the vector's data (values_pt) is owned by this vector.
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
bool distributed() const
access function to the distributed - indicates whether the distribution is serial or distributed
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
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...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).