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

Last change on this file since 1251 was 1235, checked in by mhnguyen, 7 years ago

Fixing a bug on writting axis label

+) Axis label is correctly processed before being written
+) Do some code cleaning and add some comments

Test
+) On Curie
+) OK

File size: 13.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    case BAND_DISTRIBUTION:
121      nBand = computeBandDistribution(nServer_, positionDimensionDistributed);
122      break;
123    default:
124      break;
125  }
126
127  size_t indexBegin = indexBeginEnd.first;
128  size_t indexEnd   = indexBeginEnd.second;
129  if (indexBegin > indexEnd)
130     ERROR("CServerDistributionDescription::computeServerGlobalIndexInRange",
131           << "Index begin is larger than index end");
132
133  globalIndex_.rehash(std::ceil((indexEnd-indexBegin+1)/globalIndex_.max_load_factor()));
134
135  int dim = nGlobal_.size();
136  std::vector<int> currentIndex(dim);
137
138  for (int idxServer = 0; idxServer < nBand; ++idxServer)
139  {
140    size_t ssize = 1, idx = 0;
141    for (int j = 0; j < dim; ++j) ssize *= dimensionSizes_[idxServer][j];
142
143    std::vector<int> idxLoop(dim,0);
144    int innerLoopSize = dimensionSizes_[idxServer][0];
145
146    while (idx<ssize)
147    {
148      for (int idxDim = 0; idxDim < dim-1; ++idxDim)
149      {
150        if (idxLoop[idxDim] == dimensionSizes_[idxServer][idxDim])
151        {
152          idxLoop[idxDim] = 0;
153          ++idxLoop[idxDim+1];
154        }
155      }
156
157      for (int idxDim = 1; idxDim < dim; ++idxDim)  currentIndex[idxDim] = idxLoop[idxDim] + indexBegin_[idxServer][idxDim];
158
159      size_t mulDim, globalIndex;
160      for (int j = 0; j < innerLoopSize; ++j)
161      {
162        mulDim = 1;
163        globalIndex = j + indexBegin_[idxServer][0];
164
165        for (int k = 1; k < dim; ++k)
166        {
167          mulDim *= nGlobal_[k-1];
168          globalIndex += (currentIndex[k])*mulDim;
169        }
170        if ((indexBegin <= globalIndex) && (globalIndex <= indexEnd))
171          globalIndex_[globalIndex] = idxServer;
172        ++idx;
173      }
174      idxLoop[0] += innerLoopSize;
175    }
176  }
177
178    // List of servers without distribution (cause total number of server is greater than number of bands, for example)
179  std::vector<int> zeroIndexServer(nServer_-nBand); 
180  for (int idxServer = nBand; idxServer < nServer_; ++idxServer)
181    zeroIndexServer[idxServer-nBand] = idxServer;
182
183  return zeroIndexServer;
184}
185
186/*!
187  Compute the global index of grid elements (domain, axis) and their associated server rank.
188  Each client knows the general distribution of servers and from which they can compute the pieces of information to hold
189  \param [out] indexServerOnElement global index of each element as well as the corresponding server which contains these indices
190  \param [in] clientRank rank of client
191  \param [in] clientSize number of client
192  \param [in] axisDomainOrder the order of element in grid (2 for domain, 1 for axis, 0 for scalar)
193  \param [in] positionDimensionDistributed dimension of server on which we make the cut.
194*/
195std::vector<int> CServerDistributionDescription::computeServerGlobalByElement(std::vector<boost::unordered_map<size_t,std::vector<int> > >& indexServerOnElement,
196                                                                              int clientRank,
197                                                                              int clientSize,
198                                                                              const CArray<int,1>& axisDomainOrder,
199                                                                              int positionDimensionDistributed)
200{
201  int nBand  = 0;
202  switch (serverType_) {
203    case BAND_DISTRIBUTION:
204      nBand = computeBandDistribution(nServer_, positionDimensionDistributed);
205      break;
206    default:
207      break;
208  }
209
210  int nbElement = axisDomainOrder.numElements();
211  indexServerOnElement.resize(nbElement);
212  int idx = 0;
213  std::vector<int> idxMap(nbElement);
214  for (int i = 0; i < nbElement; ++i)
215  {
216    idxMap[i] = idx;
217    if (2 == axisDomainOrder(i)) idx += 2;
218    else ++idx;
219  }
220
221  for (int idxServer = 0; idxServer < nBand; ++idxServer)
222  {
223    std::vector<int> elementDimension(4);
224    for (int i = 0; i < nbElement; ++i)
225    {
226      int elementSize = 1;
227      if (2 == axisDomainOrder(i))
228      {
229        elementSize *= dimensionSizes_[idxServer][idxMap[i]] * dimensionSizes_[idxServer][idxMap[i]+1];
230        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
231        elementDimension[1] = indexBegin_[idxServer][idxMap[i]+1];
232        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
233        elementDimension[3] = dimensionSizes_[idxServer][idxMap[i]+1];
234      }
235
236      else if (1 == axisDomainOrder(i))
237      {
238        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
239        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
240        elementDimension[1] = 0;
241        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
242        elementDimension[3] = 1;
243      }
244      else
245      {
246        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
247        elementDimension[0] = 0;
248        elementDimension[1] = 0;
249        elementDimension[2] = 1;
250        elementDimension[3] = 1;
251      }
252
253      int rangeBegin, rangeSize;
254      computeRangeProcIndex(clientRank, clientSize, elementSize, rangeBegin, rangeSize);
255
256      size_t globalIndexElement;
257      idx = 0; int idxRange = 0;
258      for (int k = 0; k < elementDimension[3]; ++k)
259        for (int l = 0; l < elementDimension[2]; ++l)
260        {
261          globalIndexElement = (l+elementDimension[0]) + (k+elementDimension[1])*elementDimension[2];
262          if ((rangeBegin <= idx) && (idxRange < rangeSize))
263          {
264            indexServerOnElement[i][globalIndexElement].push_back(idxServer);
265            ++idxRange;
266          }
267          ++idx;
268        }
269    }
270  }
271
272  // List of servers without distribution (cause total number of server is greater than number of bands, for example)
273  std::vector<int> zeroIndexServer(nServer_-nBand); 
274  for (int idxServer = nBand; idxServer < nServer_; ++idxServer)
275    zeroIndexServer[idxServer-nBand] = idxServer;
276
277  return zeroIndexServer;
278}
279
280/*!
281  Compute a range of index on server which a client holds
282  For a range of index on a specific server, each client can hold a piece of the index range
283  If the range size is smaller than the number of client, there are some clients holding the same index
284  \param [in] clientRank rank of client
285  \param [in] clientSize number of client
286  \param [in] rangeProcSize index range size
287  \param [out] rangeBegin begin of range index a client holds
288  \param [out] rangeSize size of range index a client holds
289*/
290void CServerDistributionDescription::computeRangeProcIndex(int clientRank,
291                                                           int clientSize,
292                                                           int rangeProcSize,
293                                                           int& rangeBegin,
294                                                           int& rangeSize)
295{
296  if (rangeProcSize < clientSize)
297  {
298    int rangeIndex = 0;
299    for (int idx = 0; idx < clientSize; ++idx)
300    {
301      if (idx == clientRank)
302      {
303        rangeBegin = rangeIndex;
304        rangeSize = 1;
305      }
306      ++rangeIndex;
307      if (rangeIndex == rangeProcSize) rangeIndex = 0;
308    }
309    return;
310  }
311
312  int range, indexBegin = 0;
313  for (int i = 0; i < clientSize; ++i)
314  {
315    range = rangeProcSize / clientSize;
316    if (i < (rangeProcSize%clientSize)) ++range;
317    if (i == clientRank) break;
318    indexBegin += range;
319  }
320  rangeBegin = indexBegin;
321  rangeSize = range;
322}
323
324/*!
325  Compute global index of servers with band distribution
326  \param [in] nServer number of server
327*/
328int CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)
329{
330  int dim = nGlobal_.size();
331  positionDimensionDistributed_ = positionDimensionDistributed;
332  if (1 == dim) positionDimensionDistributed_ = 0;
333  if (positionDimensionDistributed_ > dim)
334    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
335          << "Position of distributed dimension is invalid" << std::endl
336          << "Position of distributed dimension is " << positionDimensionDistributed_
337          << "Dimension " << dim)
338
339  indexBegin_.resize(nServer);
340  dimensionSizes_.resize(nServer);
341
342  for (int i = 0; i< nServer; ++i)
343  {
344    indexBegin_[i].resize(dim);
345    dimensionSizes_[i].resize(dim);
346  }
347
348  int njRangeSize;
349  int nGlobTemp = 0;
350  std::vector<int> njRangeBegin(nServer,0);
351  std::vector<int> njRangeEnd(nServer,0);
352
353  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
354  nGlobTemp = nGlobal_[positionDistributed];
355  int nbBand = std::min(nGlobTemp, nServer);
356
357  for (int i = 0; i < nbBand; ++i)
358  {
359    if (0 < i) njRangeBegin[i] = njRangeEnd[i-1];
360    njRangeSize = nGlobTemp / nbBand;
361    if (i < nGlobTemp%nbBand) ++njRangeSize;
362    njRangeEnd[i] = njRangeSize + njRangeBegin[i];
363  }
364  njRangeEnd[nbBand-1] = nGlobTemp;
365
366  for (int i = nbBand; i < nServer; ++i)
367  {
368    njRangeBegin[i] = njRangeEnd[i] = 0;
369  }
370
371  for (int i = 0; i < nServer; ++i)
372  {
373    for (int j = 0; j < dim; ++j)
374    {
375      if (positionDistributed != j)
376      {
377        if (1 == dim)
378        {
379          indexBegin_[i][j] = njRangeBegin[i];
380          dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
381        }
382        else
383        {
384          indexBegin_[i][j] = 0;
385          dimensionSizes_[i][j] = nGlobal_[j];
386        }
387      }
388      else
389      {
390        indexBegin_[i][j] = njRangeBegin[i];
391        dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
392      }
393    }
394  }
395
396  return nbBand;
397}
398
399/*!
400  Get size of each dimension on distributed server
401  \return size of dimensions on server(s)
402*/
403std::vector<std::vector<int> > CServerDistributionDescription::getServerDimensionSizes() const
404{
405  return dimensionSizes_;
406}
407
408/*!
409  Get index begin of each dimension on distributed server
410  \return index begin of dimensions on server(s)
411*/
412std::vector<std::vector<int> > CServerDistributionDescription::getServerIndexBegin() const
413{
414  return indexBegin_;
415}
416
417/*!
418  Get global index on distributed server
419  \return global index on server(s)
420*/
421const std::vector<CArray<size_t,1> >& CServerDistributionDescription::getGlobalIndex() const
422{
423  return vecGlobalIndex_;
424}
425
426/*!
427  Get global index calculated by computeServerGlobalIndexInRange
428*/
429const boost::unordered_map<size_t,int>& CServerDistributionDescription::getGlobalIndexRange() const
430{
431  return globalIndex_;
432}
433
434int CServerDistributionDescription::getDimensionDistributed()
435{
436  return ((1<nGlobal_.size()) ? positionDimensionDistributed_ : 0);
437}
438
439} // namespace xios
Note: See TracBrowser for help on using the repository browser.