source: XIOS/dev/branch_openmp/src/server_distribution_description.cpp @ 1460

Last change on this file since 1460 was 1460, checked in by yushan, 6 years ago

branch_openmp merged with XIOS_DEV_CMIP6@1459

File size: 16.0 KB
Line 
1/*!
2   \file server_distribution_description.hpp
3   \author Ha NGUYEN
4   \since 04 Jan 2015
5   \date 11 Jan 2016
6
7   \brief Description of index distribution on server(s).
8 */
9
10#include "server_distribution_description.hpp"
11#include "exception.hpp"
12
13namespace xios
14{
15  /*!
16  \param [in] globalDimensionSize global dimension of grid
17  \param [in] nServer number of server
18  \param [in] serType type of server distribution. For now, we can distribute server by band or plan
19  */
20CServerDistributionDescription::CServerDistributionDescription(const std::vector<int>& globalDimensionSize,
21                                                               int nServer,
22                                                               ServerDistributionType serType)
23  : nGlobal_(globalDimensionSize), indexBegin_(), dimensionSizes_(), globalIndex_(),
24    vecGlobalIndex_(), serverType_(serType), nServer_(nServer), positionDimensionDistributed_(1)
25{
26}
27
28CServerDistributionDescription::~CServerDistributionDescription()
29{ /* Nothing to do */ }
30
31int CServerDistributionDescription::defaultDistributedDimension(int gridDimension,                                   
32                                                                ServerDistributionType serType)
33{ 
34  switch (serType) 
35  {
36    case BAND_DISTRIBUTION:       
37       return ((1 == gridDimension) ? 0 : 1);
38      break;
39    default:
40      break;
41  } 
42}
43
44/*!
45  Compute pre-defined global index distribution of server(s).
46  \param [in] doComputeGlobalIndex flag to compute global index on each server. By default, false
47
48*/
49void CServerDistributionDescription::computeServerDistribution(bool doComputeGlobalIndex,
50                                                               int positionDimensionDistributed)
51{
52  switch (serverType_) {
53    case BAND_DISTRIBUTION:
54      computeBandDistribution(nServer_, positionDimensionDistributed);
55      break;
56    default:
57      break;
58  }
59
60  if (doComputeGlobalIndex)
61  {
62    vecGlobalIndex_.resize(nServer_);
63    int dim = nGlobal_.size();
64    std::vector<int> currentIndex(dim);
65
66    for (int idxServer = 0; idxServer < nServer_; ++idxServer)
67    {
68      size_t ssize = 1, idx = 0;
69      for (int j = 0; j < dim; ++j) ssize *= dimensionSizes_[idxServer][j];
70      vecGlobalIndex_[idxServer].resize(ssize);
71
72      std::vector<int> idxLoop(dim,0);
73
74      int innerLoopSize = dimensionSizes_[idxServer][0];
75
76      while (idx<ssize)
77      {
78        for (int idxDim = 0; idxDim < dim-1; ++idxDim)
79        {
80          if (idxLoop[idxDim] == dimensionSizes_[idxServer][idxDim])
81          {
82            idxLoop[idxDim] = 0;
83            ++idxLoop[idxDim+1];
84          }
85        }
86
87        for (int idxDim = 1; idxDim < dim; ++idxDim)  currentIndex[idxDim] = idxLoop[idxDim] + indexBegin_[idxServer][idxDim];
88
89        size_t mulDim, globalIndex;
90        for (int j = 0; j < innerLoopSize; ++j)
91        {
92          mulDim = 1;
93          globalIndex = j + indexBegin_[idxServer][0];
94
95          for (int k = 1; k < dim; ++k)
96          {
97            mulDim *= nGlobal_[k-1];
98            globalIndex += currentIndex[k] * mulDim;
99          }
100          vecGlobalIndex_[idxServer](idx) = globalIndex;
101          ++idx;
102        }
103        idxLoop[0] += innerLoopSize;
104      }
105    }
106  }
107}
108
109/*!
110  Compute global index assigned to a server with a range.E.g: if a grid has 100 points and
111  there are 2 servers, the first one takes index from 0 to 49, the second has index from 50 to 99
112  \param [in] indexBeginEnd begining and ending index of range
113  \param [in] positionDimensionDistributed dimension of server on which we make the cut.
114*/
115std::vector<int> CServerDistributionDescription::computeServerGlobalIndexInRange(const std::pair<size_t, size_t>& indexBeginEnd,
116                                                                     int positionDimensionDistributed)
117{
118  int nBand  = 0;
119  switch (serverType_)
120  {
121    case BAND_DISTRIBUTION:
122      nBand = computeBandDistribution(nServer_, positionDimensionDistributed);
123      break;
124    case ROOT_DISTRIBUTION:
125      nBand = computeRootDistribution(nServer_);
126    default:
127      break;
128  }
129
130  size_t indexBegin = indexBeginEnd.first;
131  size_t indexEnd   = indexBeginEnd.second;
132  if (indexBegin > indexEnd)
133     ERROR("CServerDistributionDescription::computeServerGlobalIndexInRange",
134           << "Index begin is larger than index end");
135
136  globalIndex_.rehash(std::ceil((indexEnd-indexBegin+1)/globalIndex_.max_load_factor()));
137
138  int dim = nGlobal_.size();
139  std::vector<int> currentIndex(dim);
140
141  for (int idxServer = 0; idxServer < nBand; ++idxServer)
142  {
143    size_t ssize = 1, idx = 0;
144    for (int j = 0; j < dim; ++j) ssize *= dimensionSizes_[idxServer][j];
145
146    std::vector<int> idxLoop(dim,0);
147    int innerLoopSize = dimensionSizes_[idxServer][0];
148
149    while (idx<ssize)
150    {
151      for (int idxDim = 0; idxDim < dim-1; ++idxDim)
152      {
153        if (idxLoop[idxDim] == dimensionSizes_[idxServer][idxDim])
154        {
155          idxLoop[idxDim] = 0;
156          ++idxLoop[idxDim+1];
157        }
158      }
159
160      for (int idxDim = 1; idxDim < dim; ++idxDim)  currentIndex[idxDim] = idxLoop[idxDim] + indexBegin_[idxServer][idxDim];
161
162      size_t mulDim, globalIndex;
163      for (int j = 0; j < innerLoopSize; ++j)
164      {
165        mulDim = 1;
166        globalIndex = j + indexBegin_[idxServer][0];
167
168        for (int k = 1; k < dim; ++k)
169        {
170          mulDim *= nGlobal_[k-1];
171          globalIndex += (currentIndex[k])*mulDim;
172        }
173        if ((indexBegin <= globalIndex) && (globalIndex <= indexEnd))
174          globalIndex_[globalIndex] = idxServer;
175        ++idx;
176      }
177      idxLoop[0] += innerLoopSize;
178    }
179  }
180
181    // List of servers without distribution (cause total number of server is greater than number of bands, for example)
182  std::vector<int> zeroIndexServer(nServer_-nBand); 
183  for (int idxServer = nBand; idxServer < nServer_; ++idxServer)
184    zeroIndexServer[idxServer-nBand] = idxServer;
185
186  return zeroIndexServer;
187}
188
189/*!
190  Compute the global index of grid elements (domain, axis) and their associated server rank.
191  Each client knows the general distribution of servers and from which they can compute the pieces of information to hold
192  \param [out] indexServerOnElement global index of each element as well as the corresponding server which contains these indices
193  \param [in] clientRank rank of client
194  \param [in] clientSize number of client
195  \param [in] axisDomainOrder the order of element in grid (2 for domain, 1 for axis, 0 for scalar)
196  \param [in] positionDimensionDistributed dimension of server on which we make the cut.
197*/
198std::vector<int> CServerDistributionDescription::computeServerGlobalByElement(std::vector<boost::unordered_map<size_t,std::vector<int> > >& indexServerOnElement,
199                                                                              int clientRank,
200                                                                              int clientSize,
201                                                                              const CArray<int,1>& axisDomainOrder,
202                                                                              int positionDimensionDistributed)
203{
204  int nBand  = 0;
205  switch (serverType_) {
206    case BAND_DISTRIBUTION:
207      nBand = computeBandDistribution(nServer_, positionDimensionDistributed);
208      break;
209    default:
210      break;
211  }
212
213  int nbElement = axisDomainOrder.numElements();
214  indexServerOnElement.resize(nbElement);
215  int idx = 0;
216  std::vector<int> idxMap(nbElement);
217  for (int i = 0; i < nbElement; ++i)
218  {
219    idxMap[i] = idx;
220    if (2 == axisDomainOrder(i)) idx += 2;
221    else if (1 == axisDomainOrder(i)) idx += 1;
222    // nothing for scalar
223  }
224
225  for (int idxServer = 0; idxServer < nBand; ++idxServer)
226  {
227    std::vector<int> elementDimension(4);
228    for (int i = 0; i < nbElement; ++i)
229    {
230      int elementSize = 1;
231      if (2 == axisDomainOrder(i))
232      {
233        elementSize *= dimensionSizes_[idxServer][idxMap[i]] * dimensionSizes_[idxServer][idxMap[i]+1];
234        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
235        elementDimension[1] = indexBegin_[idxServer][idxMap[i]+1];
236        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
237        elementDimension[3] = dimensionSizes_[idxServer][idxMap[i]+1];
238      }
239
240      else if (1 == axisDomainOrder(i))
241      {
242        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
243        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
244        elementDimension[1] = 0;
245        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
246        elementDimension[3] = 1;
247      }
248      else
249      {
250        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
251        elementDimension[0] = 0;
252        elementDimension[1] = 0;
253        elementDimension[2] = 1;
254        elementDimension[3] = 1;
255      }
256
257      int rangeBegin, rangeSize;
258      computeRangeProcIndex(clientRank, clientSize, elementSize, rangeBegin, rangeSize);
259
260      size_t globalIndexElement;
261      idx = 0; int idxRange = 0;
262      for (int k = 0; k < elementDimension[3]; ++k)
263        for (int l = 0; l < elementDimension[2]; ++l)
264        {
265          globalIndexElement = (l+elementDimension[0]) + (k+elementDimension[1])*elementDimension[2];
266          if ((rangeBegin <= idx) && (idxRange < rangeSize))
267          {
268            indexServerOnElement[i][globalIndexElement].push_back(idxServer);
269            ++idxRange;
270          }
271          ++idx;
272        }
273    }
274  }
275
276  // List of servers without distribution (cause total number of server is greater than number of bands, for example)
277  std::vector<int> zeroIndexServer(nServer_-nBand); 
278  for (int idxServer = nBand; idxServer < nServer_; ++idxServer)
279    zeroIndexServer[idxServer-nBand] = idxServer;
280
281  return zeroIndexServer;
282}
283
284/*!
285  Compute a range of index on server which a client holds
286  For a range of index on a specific server, each client can hold a piece of the index range
287  If the range size is smaller than the number of client, there are some clients holding the same index
288  \param [in] clientRank rank of client
289  \param [in] clientSize number of client
290  \param [in] rangeProcSize index range size
291  \param [out] rangeBegin begin of range index a client holds
292  \param [out] rangeSize size of range index a client holds
293*/
294void CServerDistributionDescription::computeRangeProcIndex(int clientRank,
295                                                           int clientSize,
296                                                           int rangeProcSize,
297                                                           int& rangeBegin,
298                                                           int& rangeSize)
299{
300  if (rangeProcSize < clientSize)
301  {
302    int rangeIndex = 0;
303    for (int idx = 0; idx < clientSize; ++idx)
304    {
305      if (idx == clientRank)
306      {
307        rangeBegin = rangeIndex;
308        rangeSize = 1;
309      }
310      ++rangeIndex;
311      if (rangeIndex == rangeProcSize) rangeIndex = 0;
312    }
313    return;
314  }
315
316  int range, indexBegin = 0;
317  for (int i = 0; i < clientSize; ++i)
318  {
319    range = rangeProcSize / clientSize;
320    if (i < (rangeProcSize%clientSize)) ++range;
321    if (i == clientRank) break;
322    indexBegin += range;
323  }
324  rangeBegin = indexBegin;
325  rangeSize = range;
326}
327
328/*!
329  Compute global index of servers with band distribution
330  \param [in] nServer number of server
331*/
332int CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)
333{
334  int dim = nGlobal_.size();
335  positionDimensionDistributed_ = positionDimensionDistributed;
336  if (1 == dim) positionDimensionDistributed_ = 0;
337  if (positionDimensionDistributed_ > dim)
338    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
339          << "Position of distributed dimension is invalid" << std::endl
340          << "Position of distributed dimension is " << positionDimensionDistributed_
341          << "Dimension " << dim)
342
343  indexBegin_.resize(nServer);
344  dimensionSizes_.resize(nServer);
345
346  for (int i = 0; i< nServer; ++i)
347  {
348    indexBegin_[i].resize(dim);
349    dimensionSizes_[i].resize(dim);
350  }
351
352  int njRangeSize;
353  int nGlobTemp = 0;
354  std::vector<int> njRangeBegin(nServer,0);
355  std::vector<int> njRangeEnd(nServer,0);
356
357  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
358  nGlobTemp = nGlobal_[positionDistributed];
359  int nbBand = std::min(nGlobTemp, nServer);
360
361  for (int i = 0; i < nbBand; ++i)
362  {
363    if (0 < i) njRangeBegin[i] = njRangeEnd[i-1];
364    njRangeSize = nGlobTemp / nbBand;
365    if (i < nGlobTemp%nbBand) ++njRangeSize;
366    njRangeEnd[i] = njRangeSize + njRangeBegin[i];
367  }
368  njRangeEnd[nbBand-1] = nGlobTemp;
369
370  for (int i = nbBand; i < nServer; ++i)
371  {
372    njRangeBegin[i] = njRangeEnd[i] = 0;
373  }
374
375  for (int i = 0; i < nServer; ++i)
376  {
377    for (int j = 0; j < dim; ++j)
378    {
379      if (positionDistributed != j)
380      {
381        if (1 == dim)
382        {
383          indexBegin_[i][j] = njRangeBegin[i];
384          dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
385        }
386        else
387        {
388          indexBegin_[i][j] = 0;
389          dimensionSizes_[i][j] = nGlobal_[j];
390        }
391      }
392      else
393      {
394        indexBegin_[i][j] = njRangeBegin[i];
395        dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
396      }
397    }
398  }
399
400  return nbBand;
401}
402
403
404/*!
405  Compute global index of servers with root distribution : only root server will received data
406  \param [in] nServer number of server
407*/
408int CServerDistributionDescription::computeRootDistribution(int nServer, int positionDimensionDistributed)
409{
410  int dim = nGlobal_.size();
411  positionDimensionDistributed_ = positionDimensionDistributed;
412  if (1 == dim) positionDimensionDistributed_ = 0;
413  if (positionDimensionDistributed_ > dim)
414    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
415          << "Position of distributed dimension is invalid" << std::endl
416          << "Position of distributed dimension is " << positionDimensionDistributed_
417          << "Dimension " << dim)
418
419  indexBegin_.resize(nServer);
420  dimensionSizes_.resize(nServer);
421
422  for (int i = 0; i< nServer; ++i)
423  {
424    indexBegin_[i].resize(dim);
425    dimensionSizes_[i].resize(dim);
426  }
427
428  int nGlobTemp = 0;
429
430  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
431  nGlobTemp = nGlobal_[positionDistributed];
432  int nbBand = 1 ;
433
434
435  for (int i = 0; i < nServer; ++i)
436  {
437    for (int j = 0; j < dim; ++j)
438    {
439      if (positionDistributed != j) // bad coding, need to be rewrite
440      {
441        if (1 == dim)
442        {
443          if (i==0)
444          {
445            indexBegin_[i][j] = 0;
446            dimensionSizes_[i][j] = nGlobTemp;
447          }
448          else
449          {
450            indexBegin_[i][j] = nGlobTemp-1;
451            dimensionSizes_[i][j] = 0;
452          }
453        }
454        else
455        {
456          indexBegin_[i][j] = 0;
457          dimensionSizes_[i][j] = nGlobal_[j];
458        }
459      }
460      else
461      {
462        if (i==0)
463        {
464          indexBegin_[i][j] = 0;
465          dimensionSizes_[i][j] = nGlobTemp;
466        }
467        else
468        {
469          indexBegin_[i][j] = nGlobTemp-1;
470          dimensionSizes_[i][j] = 0;
471        }
472      }
473    }
474  }
475
476  return nbBand;
477}
478
479
480
481
482/*!
483  Get size of each dimension on distributed server
484  \return size of dimensions on server(s)
485*/
486std::vector<std::vector<int> > CServerDistributionDescription::getServerDimensionSizes() const
487{
488  return dimensionSizes_;
489}
490
491/*!
492  Get index begin of each dimension on distributed server
493  \return index begin of dimensions on server(s)
494*/
495std::vector<std::vector<int> > CServerDistributionDescription::getServerIndexBegin() const
496{
497  return indexBegin_;
498}
499
500/*!
501  Get global index on distributed server
502  \return global index on server(s)
503*/
504const std::vector<CArray<size_t,1> >& CServerDistributionDescription::getGlobalIndex() const
505{
506  return vecGlobalIndex_;
507}
508
509/*!
510  Get global index calculated by computeServerGlobalIndexInRange
511*/
512const boost::unordered_map<size_t,int>& CServerDistributionDescription::getGlobalIndexRange() const
513{
514  return globalIndex_;
515}
516
517int CServerDistributionDescription::getDimensionDistributed()
518{
519  return ((1<nGlobal_.size()) ? positionDimensionDistributed_ : 0);
520}
521
522} // namespace xios
Note: See TracBrowser for help on using the repository browser.