source: XIOS/dev/XIOS_DEV_CMIP6/src/server_distribution_description.cpp @ 1260

Last change on this file since 1260 was 1258, checked in by ymipsl, 7 years ago

Fix problem of axis distribution. When a grid is composed of a distributed axis and an non distributed axis on client side , on server side the first axis will be non distributed and second axis will be distributed. In this case, attributes (value, bounds, etc) was not sent in correct distribution.

YM

File size: 15.9 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 ++idx;
222  }
223
224  for (int idxServer = 0; idxServer < nBand; ++idxServer)
225  {
226    std::vector<int> elementDimension(4);
227    for (int i = 0; i < nbElement; ++i)
228    {
229      int elementSize = 1;
230      if (2 == axisDomainOrder(i))
231      {
232        elementSize *= dimensionSizes_[idxServer][idxMap[i]] * dimensionSizes_[idxServer][idxMap[i]+1];
233        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
234        elementDimension[1] = indexBegin_[idxServer][idxMap[i]+1];
235        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
236        elementDimension[3] = dimensionSizes_[idxServer][idxMap[i]+1];
237      }
238
239      else if (1 == axisDomainOrder(i))
240      {
241        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
242        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
243        elementDimension[1] = 0;
244        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
245        elementDimension[3] = 1;
246      }
247      else
248      {
249        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
250        elementDimension[0] = 0;
251        elementDimension[1] = 0;
252        elementDimension[2] = 1;
253        elementDimension[3] = 1;
254      }
255
256      int rangeBegin, rangeSize;
257      computeRangeProcIndex(clientRank, clientSize, elementSize, rangeBegin, rangeSize);
258
259      size_t globalIndexElement;
260      idx = 0; int idxRange = 0;
261      for (int k = 0; k < elementDimension[3]; ++k)
262        for (int l = 0; l < elementDimension[2]; ++l)
263        {
264          globalIndexElement = (l+elementDimension[0]) + (k+elementDimension[1])*elementDimension[2];
265          if ((rangeBegin <= idx) && (idxRange < rangeSize))
266          {
267            indexServerOnElement[i][globalIndexElement].push_back(idxServer);
268            ++idxRange;
269          }
270          ++idx;
271        }
272    }
273  }
274
275  // List of servers without distribution (cause total number of server is greater than number of bands, for example)
276  std::vector<int> zeroIndexServer(nServer_-nBand); 
277  for (int idxServer = nBand; idxServer < nServer_; ++idxServer)
278    zeroIndexServer[idxServer-nBand] = idxServer;
279
280  return zeroIndexServer;
281}
282
283/*!
284  Compute a range of index on server which a client holds
285  For a range of index on a specific server, each client can hold a piece of the index range
286  If the range size is smaller than the number of client, there are some clients holding the same index
287  \param [in] clientRank rank of client
288  \param [in] clientSize number of client
289  \param [in] rangeProcSize index range size
290  \param [out] rangeBegin begin of range index a client holds
291  \param [out] rangeSize size of range index a client holds
292*/
293void CServerDistributionDescription::computeRangeProcIndex(int clientRank,
294                                                           int clientSize,
295                                                           int rangeProcSize,
296                                                           int& rangeBegin,
297                                                           int& rangeSize)
298{
299  if (rangeProcSize < clientSize)
300  {
301    int rangeIndex = 0;
302    for (int idx = 0; idx < clientSize; ++idx)
303    {
304      if (idx == clientRank)
305      {
306        rangeBegin = rangeIndex;
307        rangeSize = 1;
308      }
309      ++rangeIndex;
310      if (rangeIndex == rangeProcSize) rangeIndex = 0;
311    }
312    return;
313  }
314
315  int range, indexBegin = 0;
316  for (int i = 0; i < clientSize; ++i)
317  {
318    range = rangeProcSize / clientSize;
319    if (i < (rangeProcSize%clientSize)) ++range;
320    if (i == clientRank) break;
321    indexBegin += range;
322  }
323  rangeBegin = indexBegin;
324  rangeSize = range;
325}
326
327/*!
328  Compute global index of servers with band distribution
329  \param [in] nServer number of server
330*/
331int CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)
332{
333  int dim = nGlobal_.size();
334  positionDimensionDistributed_ = positionDimensionDistributed;
335  if (1 == dim) positionDimensionDistributed_ = 0;
336  if (positionDimensionDistributed_ > dim)
337    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
338          << "Position of distributed dimension is invalid" << std::endl
339          << "Position of distributed dimension is " << positionDimensionDistributed_
340          << "Dimension " << dim)
341
342  indexBegin_.resize(nServer);
343  dimensionSizes_.resize(nServer);
344
345  for (int i = 0; i< nServer; ++i)
346  {
347    indexBegin_[i].resize(dim);
348    dimensionSizes_[i].resize(dim);
349  }
350
351  int njRangeSize;
352  int nGlobTemp = 0;
353  std::vector<int> njRangeBegin(nServer,0);
354  std::vector<int> njRangeEnd(nServer,0);
355
356  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
357  nGlobTemp = nGlobal_[positionDistributed];
358  int nbBand = std::min(nGlobTemp, nServer);
359
360  for (int i = 0; i < nbBand; ++i)
361  {
362    if (0 < i) njRangeBegin[i] = njRangeEnd[i-1];
363    njRangeSize = nGlobTemp / nbBand;
364    if (i < nGlobTemp%nbBand) ++njRangeSize;
365    njRangeEnd[i] = njRangeSize + njRangeBegin[i];
366  }
367  njRangeEnd[nbBand-1] = nGlobTemp;
368
369  for (int i = nbBand; i < nServer; ++i)
370  {
371    njRangeBegin[i] = njRangeEnd[i] = 0;
372  }
373
374  for (int i = 0; i < nServer; ++i)
375  {
376    for (int j = 0; j < dim; ++j)
377    {
378      if (positionDistributed != j)
379      {
380        if (1 == dim)
381        {
382          indexBegin_[i][j] = njRangeBegin[i];
383          dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
384        }
385        else
386        {
387          indexBegin_[i][j] = 0;
388          dimensionSizes_[i][j] = nGlobal_[j];
389        }
390      }
391      else
392      {
393        indexBegin_[i][j] = njRangeBegin[i];
394        dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
395      }
396    }
397  }
398
399  return nbBand;
400}
401
402
403/*!
404  Compute global index of servers with root distribution : only root server will received data
405  \param [in] nServer number of server
406*/
407int CServerDistributionDescription::computeRootDistribution(int nServer, int positionDimensionDistributed)
408{
409  int dim = nGlobal_.size();
410  positionDimensionDistributed_ = positionDimensionDistributed;
411  if (1 == dim) positionDimensionDistributed_ = 0;
412  if (positionDimensionDistributed_ > dim)
413    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
414          << "Position of distributed dimension is invalid" << std::endl
415          << "Position of distributed dimension is " << positionDimensionDistributed_
416          << "Dimension " << dim)
417
418  indexBegin_.resize(nServer);
419  dimensionSizes_.resize(nServer);
420
421  for (int i = 0; i< nServer; ++i)
422  {
423    indexBegin_[i].resize(dim);
424    dimensionSizes_[i].resize(dim);
425  }
426
427  int nGlobTemp = 0;
428
429  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
430  nGlobTemp = nGlobal_[positionDistributed];
431  int nbBand = 1 ;
432
433
434  for (int i = 0; i < nServer; ++i)
435  {
436    for (int j = 0; j < dim; ++j)
437    {
438      if (positionDistributed != j) // bad coding, need to be rewrite
439      {
440        if (1 == dim)
441        {
442          if (i==0)
443          {
444            indexBegin_[i][j] = 0;
445            dimensionSizes_[i][j] = nGlobTemp;
446          }
447          else
448          {
449            indexBegin_[i][j] = nGlobTemp-1;
450            dimensionSizes_[i][j] = 0;
451          }
452        }
453        else
454        {
455          indexBegin_[i][j] = 0;
456          dimensionSizes_[i][j] = nGlobal_[j];
457        }
458      }
459      else
460      {
461        if (i==0)
462        {
463          indexBegin_[i][j] = 0;
464          dimensionSizes_[i][j] = nGlobTemp;
465        }
466        else
467        {
468          indexBegin_[i][j] = nGlobTemp-1;
469          dimensionSizes_[i][j] = 0;
470        }
471      }
472    }
473  }
474
475  return nbBand;
476}
477
478
479
480
481/*!
482  Get size of each dimension on distributed server
483  \return size of dimensions on server(s)
484*/
485std::vector<std::vector<int> > CServerDistributionDescription::getServerDimensionSizes() const
486{
487  return dimensionSizes_;
488}
489
490/*!
491  Get index begin of each dimension on distributed server
492  \return index begin of dimensions on server(s)
493*/
494std::vector<std::vector<int> > CServerDistributionDescription::getServerIndexBegin() const
495{
496  return indexBegin_;
497}
498
499/*!
500  Get global index on distributed server
501  \return global index on server(s)
502*/
503const std::vector<CArray<size_t,1> >& CServerDistributionDescription::getGlobalIndex() const
504{
505  return vecGlobalIndex_;
506}
507
508/*!
509  Get global index calculated by computeServerGlobalIndexInRange
510*/
511const boost::unordered_map<size_t,int>& CServerDistributionDescription::getGlobalIndexRange() const
512{
513  return globalIndex_;
514}
515
516int CServerDistributionDescription::getDimensionDistributed()
517{
518  return ((1<nGlobal_.size()) ? positionDimensionDistributed_ : 0);
519}
520
521} // namespace xios
Note: See TracBrowser for help on using the repository browser.