source: XIOS/trunk/src/server_distribution_description.cpp @ 887

Last change on this file since 887 was 887, checked in by mhnguyen, 5 years ago

Adding a new type of element into grid: Scalar

+) Add a new node Scalar for xml
+) Make some change on writing scalar value
+) Reorganize some codes
+) Remove some redundant codes

Test
+) On Curie
+) All tests pass

File size: 12.7 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
31/*!
32  Compute pre-defined global index distribution of server(s).
33  \param [in] doComputeGlobalIndex flag to compute global index on each server. By default, false
34
35*/
36void CServerDistributionDescription::computeServerDistribution(bool doComputeGlobalIndex,
37                                                               int positionDimensionDistributed)
38{
39  switch (serverType_) {
40    case BAND_DISTRIBUTION:
41      computeBandDistribution(nServer_, positionDimensionDistributed);
42      break;
43    default:
44      break;
45  }
46
47  if (doComputeGlobalIndex)
48  {
49    vecGlobalIndex_.resize(nServer_);
50    int dim = nGlobal_.size();
51    std::vector<int> currentIndex(dim);
52
53    for (int idxServer = 0; idxServer < nServer_; ++idxServer)
54    {
55      size_t ssize = 1, idx = 0;
56      for (int j = 0; j < dim; ++j) ssize *= dimensionSizes_[idxServer][j];
57      vecGlobalIndex_[idxServer].resize(ssize);
58
59      std::vector<int> idxLoop(dim,0);
60
61      int innerLoopSize = dimensionSizes_[idxServer][0];
62
63      while (idx<ssize)
64      {
65        for (int idxDim = 0; idxDim < dim-1; ++idxDim)
66        {
67          if (idxLoop[idxDim] == dimensionSizes_[idxServer][idxDim])
68          {
69            idxLoop[idxDim] = 0;
70            ++idxLoop[idxDim+1];
71          }
72        }
73
74        for (int idxDim = 1; idxDim < dim; ++idxDim)  currentIndex[idxDim] = idxLoop[idxDim] + indexBegin_[idxServer][idxDim];
75
76        size_t mulDim, globalIndex;
77        for (int j = 0; j < innerLoopSize; ++j)
78        {
79          mulDim = 1;
80          globalIndex = j + indexBegin_[idxServer][0];
81
82          for (int k = 1; k < dim; ++k)
83          {
84            mulDim *= nGlobal_[k-1];
85            globalIndex += currentIndex[k] * mulDim;
86          }
87          vecGlobalIndex_[idxServer](idx) = globalIndex;
88          ++idx;
89        }
90        idxLoop[0] += innerLoopSize;
91      }
92    }
93  }
94}
95
96/*!
97  Compute global index assigned to a server with a range.E.g: if a grid has 100 points and
98  there are 2 servers, the first one takes index from 0 to 49, the second has index from 50 to 99
99  \param [in] indexBeginEnd begining and ending index of range
100  \param [in] positionDimensionDistributed dimension of server on which we make the cut.
101*/
102void CServerDistributionDescription::computeServerGlobalIndexInRange(const std::pair<size_t, size_t>& indexBeginEnd,
103                                                                     int positionDimensionDistributed)
104{
105  switch (serverType_) {
106    case BAND_DISTRIBUTION:
107      computeBandDistribution(nServer_, positionDimensionDistributed);
108      break;
109    default:
110      break;
111  }
112
113  size_t indexBegin = indexBeginEnd.first;
114  size_t indexEnd   = indexBeginEnd.second;
115  if (indexBegin > indexEnd)
116     ERROR("CServerDistributionDescription::computeServerGlobalIndexInRange",
117           << "Index begin is larger than index end");
118
119  globalIndex_.rehash(std::ceil((indexEnd-indexBegin+1)/globalIndex_.max_load_factor()));
120
121  int dim = nGlobal_.size();
122  std::vector<int> currentIndex(dim);
123
124  for (int idxServer = 0; idxServer < nServer_; ++idxServer)
125  {
126    size_t ssize = 1, idx = 0;
127    for (int j = 0; j < dim; ++j) ssize *= dimensionSizes_[idxServer][j];
128
129    std::vector<int> idxLoop(dim,0);
130    int innerLoopSize = dimensionSizes_[idxServer][0];
131
132    while (idx<ssize)
133    {
134      for (int idxDim = 0; idxDim < dim-1; ++idxDim)
135      {
136        if (idxLoop[idxDim] == dimensionSizes_[idxServer][idxDim])
137        {
138          idxLoop[idxDim] = 0;
139          ++idxLoop[idxDim+1];
140        }
141      }
142
143      for (int idxDim = 1; idxDim < dim; ++idxDim)  currentIndex[idxDim] = idxLoop[idxDim] + indexBegin_[idxServer][idxDim];
144
145      size_t mulDim, globalIndex;
146      for (int j = 0; j < innerLoopSize; ++j)
147      {
148        mulDim = 1;
149        globalIndex = j + indexBegin_[idxServer][0];
150
151        for (int k = 1; k < dim; ++k)
152        {
153          mulDim *= nGlobal_[k-1];
154          globalIndex += (currentIndex[k])*mulDim;
155        }
156        if ((indexBegin <= globalIndex) && (globalIndex <= indexEnd))
157          globalIndex_[globalIndex] = idxServer;
158        ++idx;
159      }
160      idxLoop[0] += innerLoopSize;
161    }
162  }
163}
164
165/*!
166  Compute the global index of grid elements (domain, axis) and their associated server rank.
167  Each client knows the general distribution of servers and from which they can compute the pieces of information to hold
168  \param [out] indexServerOnElement global index of each element as well as the corresponding server which contains these indices
169  \param [in] clientRank rank of client
170  \param [in] clientSize number of client
171  \param [in] axisDomainOrder the order of element in grid (2 for domain, 1 for axis, 0 for scalar)
172  \param [in] positionDimensionDistributed dimension of server on which we make the cut.
173*/
174void CServerDistributionDescription::computeServerGlobalByElement(std::vector<boost::unordered_map<size_t,std::vector<int> > >& indexServerOnElement,
175                                                                  int clientRank,
176                                                                  int clientSize,
177                                                                  const CArray<int,1>& axisDomainOrder,
178                                                                  int positionDimensionDistributed)
179{
180  switch (serverType_) {
181    case BAND_DISTRIBUTION:
182      computeBandDistribution(nServer_, positionDimensionDistributed);
183      break;
184    default:
185      break;
186  }
187
188  int nbElement = axisDomainOrder.numElements();
189  indexServerOnElement.resize(nbElement);
190  int idx = 0;
191  std::vector<int> idxMap(nbElement);
192  for (int i = 0; i < nbElement; ++i)
193  {
194    idxMap[i] = idx;
195    if (2 == axisDomainOrder(i)) idx += 2;
196    else ++idx;
197  }
198
199  for (int idxServer = 0; idxServer < nServer_; ++idxServer)
200  {
201    std::vector<int> elementDimension(4);
202    for (int i = 0; i < nbElement; ++i)
203    {
204      int elementSize = 1;
205      if (2 == axisDomainOrder(i))
206      {
207        elementSize *= dimensionSizes_[idxServer][idxMap[i]] * dimensionSizes_[idxServer][idxMap[i]+1];
208        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
209        elementDimension[1] = indexBegin_[idxServer][idxMap[i]+1];
210        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
211        elementDimension[3] = dimensionSizes_[idxServer][idxMap[i]+1];
212      }
213
214      else if (1 == axisDomainOrder(i))
215      {
216        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
217        elementDimension[0] = indexBegin_[idxServer][idxMap[i]];
218        elementDimension[1] = 0;
219        elementDimension[2] = dimensionSizes_[idxServer][idxMap[i]];
220        elementDimension[3] = 1;
221      }
222      else
223      {
224        elementSize *= dimensionSizes_[idxServer][idxMap[i]];
225        elementDimension[0] = 0;
226        elementDimension[1] = 0;
227        elementDimension[2] = 1;
228        elementDimension[3] = 1;
229      }
230
231      int rangeBegin, rangeSize;
232      computeRangeProcIndex(clientRank, clientSize, elementSize, rangeBegin, rangeSize);
233
234      size_t globalIndexElement;
235      idx = 0; int idxRange = 0;
236      for (int k = 0; k < elementDimension[3]; ++k)
237        for (int l = 0; l < elementDimension[2]; ++l)
238        {
239          globalIndexElement = (l+elementDimension[0]) + (k+elementDimension[1])*elementDimension[2];
240          if ((rangeBegin <= idx) && (idxRange < rangeSize))
241          {
242            indexServerOnElement[i][globalIndexElement].push_back(idxServer);
243            ++idxRange;
244          }
245          ++idx;
246        }
247    }
248  }
249}
250
251/*!
252  Compute a range of index on server which a client holds
253  For a range of index on a specific server, each client can hold a piece of the index range
254  If the range size is smaller than the number of client, there are some clients holding the same index
255  \param [in] clientRank rank of client
256  \param [in] clientSize number of client
257  \param [in] rangeProcSize index range size
258  \param [out] rangeBegin begin of range index a client holds
259  \param [out] rangeSize size of range index a client holds
260*/
261void CServerDistributionDescription::computeRangeProcIndex(int clientRank,
262                                                           int clientSize,
263                                                           int rangeProcSize,
264                                                           int& rangeBegin,
265                                                           int& rangeSize)
266{
267  if (rangeProcSize < clientSize)
268  {
269    int rangeIndex = 0;
270    for (int idx = 0; idx < clientSize; ++idx)
271    {
272      if (idx == clientRank)
273      {
274        rangeBegin = rangeIndex;
275        rangeSize = 1;
276      }
277      ++rangeIndex;
278      if (rangeIndex == rangeProcSize) rangeIndex = 0;
279    }
280    return;
281  }
282
283  int range, indexBegin = 0;
284  for (int i = 0; i < clientSize; ++i)
285  {
286    range = rangeProcSize / clientSize;
287    if (i < (rangeProcSize%clientSize)) ++range;
288    if (i == clientRank) break;
289    indexBegin += range;
290  }
291  rangeBegin = indexBegin;
292  rangeSize = range;
293}
294
295/*!
296  Compute global index of servers with band distribution
297  \param [in] nServer number of server
298*/
299void CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)
300{
301  int dim = nGlobal_.size();
302  positionDimensionDistributed_ = positionDimensionDistributed;
303  if (1 == dim) positionDimensionDistributed_ = 0;
304  if (positionDimensionDistributed_ > dim)
305    ERROR("CServerDistributionDescription::computeBandDistribution(int nServer, int positionDimensionDistributed)",
306          << "Position of distributed dimension is invalid" << std::endl
307          << "Position of distributed dimension is " << positionDimensionDistributed_
308          << "Dimension " << dim)
309
310  indexBegin_.resize(nServer);
311  dimensionSizes_.resize(nServer);
312
313  for (int i = 0; i< nServer; ++i)
314  {
315    indexBegin_[i].resize(dim);
316    dimensionSizes_[i].resize(dim);
317  }
318
319  int njRangeSize;
320  int nGlobTemp = 0;
321  std::vector<int> njRangeBegin(nServer,0);
322  std::vector<int> njRangeEnd(nServer,0);
323
324  int positionDistributed = (1<dim) ? positionDimensionDistributed_ : 0;
325  nGlobTemp = nGlobal_[positionDistributed];
326
327  for (int i = 0; i < nServer; ++i)
328  {
329    if (0 < i) njRangeBegin[i] = njRangeEnd[i-1];
330    njRangeSize = nGlobTemp / nServer;
331    if (i < nGlobTemp%nServer) ++njRangeSize;
332    njRangeEnd[i] = njRangeSize + njRangeBegin[i];
333  }
334  njRangeEnd[nServer-1] = nGlobTemp;
335
336  for (int i = 0; i < nServer; ++i)
337  {
338    for (int j = 0; j < dim; ++j)
339    {
340      if (positionDistributed != j)
341      {
342        if (1 == dim)
343        {
344          indexBegin_[i][j] = njRangeBegin[i];
345          dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
346        }
347        else
348        {
349          indexBegin_[i][j] = 0;
350          dimensionSizes_[i][j] = nGlobal_[j];
351        }
352      }
353      else
354      {
355        indexBegin_[i][j] = njRangeBegin[i];
356        dimensionSizes_[i][j] = njRangeEnd[i] - njRangeBegin[i];
357      }
358    }
359  }
360}
361
362/*!
363  Get size of each dimension on distributed server
364  \return size of dimensions on server(s)
365*/
366std::vector<std::vector<int> > CServerDistributionDescription::getServerDimensionSizes() const
367{
368  return dimensionSizes_;
369}
370
371/*!
372  Get index begin of each dimension on distributed server
373  \return index begin of dimensions on server(s)
374*/
375std::vector<std::vector<int> > CServerDistributionDescription::getServerIndexBegin() const
376{
377  return indexBegin_;
378}
379
380/*!
381  Get global index on distributed server
382  \return global index on server(s)
383*/
384const std::vector<CArray<size_t,1> >& CServerDistributionDescription::getGlobalIndex() const
385{
386  return vecGlobalIndex_;
387}
388
389/*!
390  Get global index calculated by computeServerGlobalIndexInRange
391*/
392const boost::unordered_map<size_t,int>& CServerDistributionDescription::getGlobalIndexRange() const
393{
394  return globalIndex_;
395}
396
397int CServerDistributionDescription::getDimensionDistributed()
398{
399  return ((1<nGlobal_.size()) ? positionDimensionDistributed_ : 0);
400}
401
402} // namespace xios
Note: See TracBrowser for help on using the repository browser.