source: XIOS/trunk/src/node/distribution_client.cpp @ 583

Last change on this file since 583 was 575, checked in by rlacroix, 9 years ago

Rename axisDomainOrder attribute to axis_domain_order.

"Snake case" is used everywhere else and camel case seems to confuse PGI compilers.

File size: 19.5 KB
Line 
1/*!
2   \file distribution_client.cpp
3   \author Ha NGUYEN
4   \since 13 Jan 2015
5   \date 09 Mars 2015
6
7   \brief Index distribution on client side.
8 */
9#include "distribution_client.hpp"
10
11namespace xios {
12
13CDistributionClient::CDistributionClient(int rank, int dims, CArray<size_t,1>* globalIndex)
14   : CDistribution(rank, dims, globalIndex),
15   localDataIndex_(0), axisDomainOrder_(),
16   nLocal_(), nGlob_(), nBeginLocal_(), nBeginGlobal_(),nZoomBegin_(), nZoomEnd_(),
17   dataNIndex_(), dataDims_(), dataBegin_(), dataIndex_(), domainMasks_(), axisMasks_(),
18   gridMask_(), localDomainIndex_(), localAxisIndex_(), indexMap_(), indexDomainData_(), indexAxisData_(),
19   isDataDistributed_(true), axisNum_(0), domainNum_(0), localDataIndexSendToServer_(0)
20{
21}
22
23CDistributionClient::CDistributionClient(int rank, CGrid* grid)
24   : CDistribution(rank, 0, 0),
25   localDataIndex_(0), axisDomainOrder_(),
26   nLocal_(), nGlob_(), nBeginLocal_(), nBeginGlobal_(),nZoomBegin_(), nZoomEnd_(),
27   dataNIndex_(), dataDims_(), dataBegin_(), dataIndex_(), domainMasks_(), axisMasks_(),
28   gridMask_(), localDomainIndex_(), localAxisIndex_(), indexMap_(), indexDomainData_(), indexAxisData_(),
29   isDataDistributed_(true), axisNum_(0), domainNum_(0), localDataIndexSendToServer_(0)
30{
31  readDistributionInfo(grid);
32  createGlobalIndex();
33}
34
35CDistributionClient::~CDistributionClient()
36{
37  if (0 != localDataIndex_) delete localDataIndex_;
38  if (0 != localDataIndexSendToServer_) delete localDataIndexSendToServer_;
39}
40
41/*!
42  Read information of a grid to generate distribution.
43  Every grid is composed of several axis or/and domain(s). Their information are processed
44stored and used to calculate index distribution between client and server
45  \param [in] grid Grid to read
46*/
47void CDistributionClient::readDistributionInfo(CGrid* grid)
48{
49  std::vector<CDomain*> domList = grid->getDomains();
50  std::vector<CAxis*> axisList = grid->getAxis();
51  CArray<bool,1> axisDomainOrder = grid->axis_domain_order;
52
53  std::vector<CDomain*>::iterator itbDom, iteDom, itDom;
54  std::vector<CAxis*>::iterator itbAxis, iteAxis, itAxis;
55
56  itbDom  = itDom  = domList.begin();  iteDom  = domList.end();
57  itbAxis = itAxis = axisList.begin(); iteAxis = axisList.end();
58
59  readDistributionInfo(domList, axisList, axisDomainOrder);
60
61  // Then check mask of grid
62  int gridDim = domList.size()*2 + axisList.size();
63  grid->checkMask();
64  switch (gridDim) {
65    case 1:
66      readGridMaskInfo(grid->mask1);
67      break;
68    case 2:
69      readGridMaskInfo(grid->mask2);
70      break;
71    case 3:
72      readGridMaskInfo(grid->mask3);
73      break;
74    default:
75      break;
76  }
77}
78
79/*!
80  Read information from domain(s) and axis to generate distribution.
81  All information related to domain, e.g ibegin, jbegin, ni, nj, ni_glo, nj_glo
82as well as related to axis, e.g dataNIndex, dataIndex will be stored to compute
83the distribution between clients and servers. Till now, every data structure of domain has been kept
84like before, e.g: data_n_index to make sure a compability, however, it should be changed?
85  \param [in] domList List of domains of grid
86  \param [in] axisList List of axis of grid
87  \param [in] axisDomainOrder order of axis and domain inside a grid. True if domain, false if axis
88//  \param [in] gridMask Mask of grid, for now, keep it 3 dimension, but it needs changing
89*/
90void CDistributionClient::readDistributionInfo(const std::vector<CDomain*>& domList,
91                                               const std::vector<CAxis*>& axisList,
92                                               const CArray<bool,1>& axisDomainOrder)
93{
94  domainNum_ = domList.size();
95  axisNum_   = axisList.size();
96  numElement_ = axisDomainOrder.numElements(); // Number of element, e.x: Axis, Domain
97
98  axisDomainOrder_.resize(numElement_);
99  axisDomainOrder_ = axisDomainOrder;
100
101  // Each domain or axis has its mask, of course
102  domainMasks_.resize(domainNum_);
103  for (int i = 0; i < domainNum_;++i)
104  {
105    domainMasks_[i].resize(domList[i]->mask.extent(0), domList[i]->mask.extent(1));
106    domainMasks_[i] = domList[i]->mask;
107  }
108
109  axisMasks_.resize(axisNum_);
110  for (int i = 0; i < axisNum_; ++i)
111  {
112    axisMasks_[i].resize(axisList[i]->mask.numElements());
113    axisMasks_[i] = axisList[i]->mask;
114  }
115
116  // Because domain and axis can be in any order (axis1, domain1, axis2, axis3, )
117  // their position should be specified. In axisDomainOrder, domain == true, axis == false
118  int idx = 0;
119  indexMap_.resize(numElement_);
120  this->dims_ = numElement_;
121  for (int i = 0; i < numElement_; ++i)
122  {
123    indexMap_[i] = idx;
124    if (true == axisDomainOrder(i))
125    {
126      ++(this->dims_);
127      idx += 2;
128    }
129    else ++idx;
130  }
131
132  // Size of each dimension (local and global)
133  nLocal_.resize(this->dims_);
134  nGlob_.resize(this->dims_);
135  nBeginLocal_.resize(this->dims_,0);
136  nBeginGlobal_.resize(this->dims_,0);
137  nZoomBegin_.resize(this->dims_);
138  nZoomEnd_.resize(this->dims_);
139
140  // Data_n_index of domain or axis (For now, axis uses its size as data_n_index
141  dataNIndex_.resize(numElement_);
142  dataDims_.resize(numElement_);
143  dataBegin_.resize(this->dims_);
144
145  // Data_*_index of each dimension
146  dataIndex_.resize(this->dims_);
147
148  // A trick to determine position of each domain in domainList
149  int domIndex = 0, axisIndex = 0;
150  idx = 0;
151
152  // Update all the vectors above
153  while (idx < numElement_)
154  {
155    bool isDomain = axisDomainOrder(idx);
156
157    // If this is a domain
158    if (isDomain)
159    {
160      // On the j axis
161      nLocal_.at(indexMap_[idx]+1) = domList[domIndex]->nj.getValue();
162      nGlob_.at(indexMap_[idx]+1)  = domList[domIndex]->nj_glo.getValue();
163      nBeginLocal_.at(indexMap_[idx]+1) = 0;
164      nBeginGlobal_.at(indexMap_[idx]+1) = domList[domIndex]->jbegin;
165      nZoomBegin_.at((indexMap_[idx]+1)) = domList[domIndex]->zoom_jbegin;
166      nZoomEnd_.at((indexMap_[idx]+1))   = domList[domIndex]->zoom_jbegin + domList[domIndex]->zoom_nj-1;
167
168      dataBegin_.at(indexMap_[idx]+1) = (2 == domList[domIndex]->data_dim) ? domList[domIndex]->data_jbegin.getValue() : -1;
169      dataIndex_.at(indexMap_[idx]+1).resize(domList[domIndex]->data_j_index.numElements());
170      dataIndex_.at(indexMap_[idx]+1) = domList[domIndex]->data_j_index;
171
172      // On the i axis
173      nLocal_.at(indexMap_[idx]) = domList[domIndex]->ni.getValue();
174      nGlob_.at(indexMap_[idx]) = domList[domIndex]->ni_glo.getValue();
175      nBeginLocal_.at(indexMap_[idx]) = 0;
176      nBeginGlobal_.at(indexMap_[idx]) = domList[domIndex]->ibegin;
177      nZoomBegin_.at((indexMap_[idx])) = domList[domIndex]->zoom_ibegin;
178      nZoomEnd_.at((indexMap_[idx]))   = domList[domIndex]->zoom_ibegin + domList[domIndex]->zoom_ni-1;
179
180      dataBegin_.at(indexMap_[idx]) = domList[domIndex]->data_ibegin.getValue();
181      dataIndex_.at(indexMap_[idx]).resize(domList[domIndex]->data_i_index.numElements());
182      dataIndex_.at(indexMap_[idx]) = domList[domIndex]->data_i_index;
183
184      dataNIndex_.at(idx) = domList[domIndex]->data_n_index.getValue();
185      dataDims_.at(idx) = domList[domIndex]->data_dim.getValue();
186      ++domIndex;
187    }
188    else // So it's an axis
189    {
190      nLocal_.at(indexMap_[idx]) = axisList[axisIndex]->ni.getValue();
191      nGlob_.at(indexMap_[idx]) = axisList[axisIndex]->size.getValue();
192      nBeginLocal_.at(indexMap_[idx]) = 0;
193      nBeginGlobal_.at(indexMap_[idx]) = axisList[axisIndex]->ibegin.getValue();
194      nZoomBegin_.at((indexMap_[idx])) = axisList[axisIndex]->zoom_begin;
195      nZoomEnd_.at((indexMap_[idx])) = axisList[axisIndex]->zoom_begin + axisList[axisIndex]->zoom_size-1;
196
197      dataBegin_.at(indexMap_[idx]) = axisList[axisIndex]->data_begin.getValue();
198      dataIndex_.at(indexMap_[idx]).resize(axisList[axisIndex]->data_index.numElements());
199      dataIndex_.at(indexMap_[idx]) = axisList[axisIndex]->data_index;
200      dataNIndex_.at(idx) = axisList[axisIndex]->data_index.numElements();
201      dataDims_.at(idx) = 1;
202      ++axisIndex;
203    }
204    ++idx;
205  }
206
207  // Grid has only one axis and it is not distributed
208  bool isDataNotDistributed = true;
209  for (int i = 0; i < this->dims_; ++i)
210    isDataNotDistributed &= (nLocal_[i] == nGlob_[i]);
211  isDataDistributed_ = !isDataNotDistributed;
212}
213
214/*!
215  Create local index of domain(s).
216  A domain can have data index which even contains the "ghost" points. Very often, these
217data surround the true data. In order to send correct data to server,
218a client need to know index of the true data.
219*/
220void CDistributionClient::createLocalDomainDataIndex()
221{
222  int numDomain = 0;
223  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
224    if (axisDomainOrder_(i)) ++numDomain;
225
226  localDomainIndex_.resize(numDomain*2);
227  indexDomainData_.resize(numDomain);
228
229  int idxDomain = 0;
230  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
231  {
232    if (axisDomainOrder_(i))
233    {
234      int iIdx, jIdx = 0, count = 0;
235      indexDomainData_[idxDomain].resize(dataNIndex_[i], false);
236      for (int j = 0; j < dataNIndex_[i]; ++j)
237      {
238        iIdx = getDomainIndex(dataIndex_[indexMap_[i]](j), dataIndex_[indexMap_[i]+1](j),
239                              dataBegin_[indexMap_[i]], dataBegin_[indexMap_[i]+1],
240                              dataDims_[i], nLocal_[indexMap_[i]], jIdx);
241
242        if ((iIdx >= nBeginLocal_[indexMap_[i]]) && (iIdx < nLocal_[indexMap_[i]]) &&
243           (jIdx >= nBeginLocal_[indexMap_[i]+1]) && (jIdx < nLocal_[indexMap_[i]+1]) &&
244           (domainMasks_[idxDomain](iIdx, jIdx)))
245        {
246          (localDomainIndex_[idxDomain]).push_back(iIdx);
247          (localDomainIndex_[idxDomain*2+1]).push_back(jIdx);
248          indexDomainData_[idxDomain][j] = true;
249        }
250      }
251      ++idxDomain;
252    }
253  }
254}
255
256/*!
257  Create local index of axis.
258*/
259void CDistributionClient::createLocalAxisDataIndex()
260{
261  int numAxis = 0;
262  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
263    if (!axisDomainOrder_(i)) ++numAxis;
264
265  localAxisIndex_.resize(numAxis);
266  indexAxisData_.resize(numAxis);
267
268  int idxAxis = 0;
269  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
270  {
271    if (!axisDomainOrder_(i))
272    {
273      int iIdx = 0;
274      indexAxisData_[idxAxis].resize(dataNIndex_[i], false);
275      for (int j = 0; j < dataNIndex_[i]; ++j)
276      {
277        iIdx = getAxisIndex(dataIndex_[indexMap_[i]](j), dataBegin_[indexMap_[i]], nLocal_[indexMap_[i]]);
278        if ((iIdx >= nBeginLocal_[indexMap_[i]]) &&
279           (iIdx < nLocal_[indexMap_[i]]) && (axisMasks_[idxAxis](iIdx)))
280        {
281          localAxisIndex_[idxAxis].push_back(iIdx);
282          indexAxisData_[idxAxis][j] = true;
283        }
284      }
285      ++idxAxis;
286    }
287  }
288}
289
290/*!
291   Create global index on client
292   In order to do the mapping between client-server, each client creates its own
293global index of sending data. This global index is then used to calculate to which server
294the client needs to send it data as well as which part of data belongs to the server.
295So as to make clients and server coherent in order of index, global index is calculated by
296take into account of C-convention, the rightmost dimension varies faster.
297*/
298void CDistributionClient::createGlobalIndex()
299{
300  createLocalDomainDataIndex();
301  createLocalAxisDataIndex();
302
303  int idxDomain = 0, idxAxis = 0;
304  std::vector<int> eachElementSize(numElement_);
305
306  // Precompute size of the loop
307  for (int i = 0; i < numElement_; ++i)
308  {
309    if(axisDomainOrder_(i))
310    {
311      eachElementSize[i] = localDomainIndex_[idxDomain].size();
312      idxDomain += 2;
313    }
314    else
315    {
316      eachElementSize[i] = localAxisIndex_[idxAxis].size();
317      ++idxAxis;
318    }
319  }
320
321  //   Compute size of the global index on client
322  std::vector<int> idxLoop(numElement_,0);
323  std::vector<int> currentIndex(this->dims_);
324  int innerLoopSize = eachElementSize[0];
325  size_t idx = 0, indexLocalDataOnClientCount = 0, indexSend2ServerCount = 0;
326  size_t ssize = 1;
327  for (int i = 0; i < numElement_; ++i) ssize *= eachElementSize[i];
328  while (idx < ssize)
329  {
330    for (int i = 0; i < numElement_-1; ++i)
331    {
332      if (idxLoop[i] == eachElementSize[i])
333      {
334        idxLoop[i] = 0;
335        ++idxLoop[i+1];
336      }
337    }
338
339    // Find out outer index
340    // Depending the inner-most element is axis or domain,
341    // The outer loop index begins correspondingly at one (1) or zero (0)
342    idxDomain = idxAxis = 0;
343    if (axisDomainOrder_(0)) ++idxDomain;
344    else ++idxAxis;
345    for (int i = 1; i < numElement_; ++i)
346    {
347      if (axisDomainOrder_(i))
348      {
349        currentIndex[indexMap_[i]]   = localDomainIndex_[idxDomain][idxLoop[i]];
350        currentIndex[indexMap_[i]+1] = localDomainIndex_[idxDomain+1][idxLoop[i]];
351        idxDomain += 2;
352      }
353      else
354      {
355        currentIndex[indexMap_[i]]   = localAxisIndex_[idxAxis][idxLoop[i]];
356        ++idxAxis;
357      }
358    }
359
360    int maskIndex = currentIndex[0];
361    for (int j = 0; j < this->dims_; ++j)
362
363    // Inner most index
364    idxDomain = idxAxis = 0;
365    for (int i = 0; i < innerLoopSize; ++i)
366    {
367      if (axisDomainOrder_(0))
368      {
369        currentIndex[0] = localDomainIndex_[idxDomain][i];
370        currentIndex[1] = localDomainIndex_[idxDomain+1][i];
371      }
372      else currentIndex[0]   = localAxisIndex_[idxAxis][i];
373
374      int gridMaskIndex = currentIndex[0];
375      int mulDimMask = 1;
376      for (int k = 1; k < this->dims_; ++k)
377      {
378        mulDimMask *= nLocal_[k-1];
379        gridMaskIndex += (currentIndex[k])*mulDimMask;
380      }
381
382      if (gridMask_(gridMaskIndex)) //(gridMask_(currentIndex[0], currentIndex[1], currentIndex[2]))
383      {
384        ++indexLocalDataOnClientCount;
385        bool isIndexOnServer = true;
386        for (int j = 0; j < this->dims_; ++j)
387          isIndexOnServer = isIndexOnServer && ((currentIndex[j]+nBeginGlobal_[j]) <= nZoomEnd_[j])
388                                            && (nZoomBegin_[j] <= (currentIndex[j]+nBeginGlobal_[j]));
389        if (isIndexOnServer) ++indexSend2ServerCount;
390      }
391
392    }
393    idxLoop[0] += innerLoopSize;
394    idx += innerLoopSize;
395  }
396
397
398  // Now allocate these arrays
399  this->globalIndex_ = new CArray<size_t,1>(indexSend2ServerCount);
400  localDataIndex_ = new CArray<int,1>(indexLocalDataOnClientCount);
401  localDataIndexSendToServer_ = new CArray<int,1>(indexSend2ServerCount);
402
403  // We need to loop with data index
404  idxLoop.assign(numElement_,0);
405  idx = indexLocalDataOnClientCount = indexSend2ServerCount = 0;
406  ssize = 1; for (int i = 0; i < numElement_; ++i) ssize *= dataNIndex_[i];
407  innerLoopSize = dataNIndex_[0];
408  int countLocalData = 0;
409  std::vector<int> correctOuterIndex(numElement_,0);
410  while (idx < ssize)
411  {
412    for (int i = 0; i < numElement_-1; ++i)
413    {
414      if (idxLoop[i] == dataNIndex_[i])
415      {
416        idxLoop[i] = 0;
417        correctOuterIndex[i] = 0;
418        ++idxLoop[i+1];
419        ++correctOuterIndex[i+1];
420      }
421    }
422
423    // Depending the inner-most element axis or domain,
424    // The outer loop index begins correspondingly at one (1) or zero (0)
425    idxDomain = idxAxis = 0;
426    if (axisDomainOrder_(0)) ++idxDomain;
427    else ++idxAxis;
428    bool isIndexDomainDataCorrect = true;
429    bool isIndexAxisDataCorrect = true;
430
431    for (int i = 1; i < numElement_; ++i)
432    {
433      if (axisDomainOrder_(i))
434      {
435        if (indexDomainData_[idxDomain][idxLoop[i]])
436        {
437          currentIndex[indexMap_[i]]   = localDomainIndex_[idxDomain][correctOuterIndex[i]];
438          currentIndex[indexMap_[i]+1] = localDomainIndex_[idxDomain*2+1][correctOuterIndex[i]];
439        }
440        else isIndexDomainDataCorrect = false;
441        ++idxDomain;
442      }
443      else
444      {
445        if (indexAxisData_[idxAxis][idxLoop[i]])
446        {
447          currentIndex[indexMap_[i]]   = localAxisIndex_[idxAxis][correctOuterIndex[i]];
448        }
449        else isIndexAxisDataCorrect = false;
450        ++idxAxis;
451      }
452    }
453
454    // Inner most index
455    idxDomain = idxAxis = 0;
456    int correctIndexDomain = 0, correctIndexAxis = 0;
457    for (int i = 0; i < innerLoopSize; ++i)
458    {
459      if (axisDomainOrder_(0))
460      {
461        if (indexDomainData_[idxDomain][i])
462        {
463          currentIndex[0] = localDomainIndex_[idxDomain][correctIndexDomain];
464          currentIndex[1] = localDomainIndex_[idxDomain+1][correctIndexDomain];
465          isIndexDomainDataCorrect = true;
466          ++correctIndexDomain;
467        }
468        else isIndexDomainDataCorrect = false;
469      }
470      else
471      {
472        if (indexAxisData_[idxAxis][i])
473        {
474          currentIndex[0] = localAxisIndex_[idxAxis][correctIndexAxis];
475          isIndexAxisDataCorrect = true;
476          ++correctIndexAxis;
477        }
478        else isIndexAxisDataCorrect = false;
479      }
480
481      int gridMaskIndex = currentIndex[0];
482      int mulDimMask = 1;
483      for (int k = 1; k < this->dims_; ++k)
484      {
485        mulDimMask *= nLocal_[k-1];
486        gridMaskIndex += (currentIndex[k])*mulDimMask;
487      }
488
489      if (isIndexDomainDataCorrect &&
490          isIndexAxisDataCorrect &&
491          gridMask_(gridMaskIndex))
492      {
493        (*localDataIndex_)(indexLocalDataOnClientCount) = countLocalData;
494
495        bool isIndexOnServer = true;
496        for (int j = 0; j < this->dims_; ++j)
497          isIndexOnServer = isIndexOnServer &&
498                            ((currentIndex[j]+nBeginGlobal_[j]) <= nZoomEnd_[j]) &&
499                            (nZoomBegin_[j] <= (currentIndex[j]+nBeginGlobal_[j]));
500        if (isIndexOnServer)
501        {
502          size_t globalIndex = currentIndex[0] + nBeginGlobal_[0];
503          size_t mulDim = 1;
504          for (int k = 1; k < this->dims_; ++k)
505          {
506            mulDim *= nGlob_[k-1];
507            globalIndex += (currentIndex[k] + nBeginGlobal_[k])*mulDim;
508          }
509          (*this->globalIndex_)(indexSend2ServerCount) = globalIndex;
510          (*localDataIndexSendToServer_)(indexSend2ServerCount) = indexLocalDataOnClientCount;
511          ++indexSend2ServerCount;
512        }
513        ++indexLocalDataOnClientCount;
514      }
515      ++countLocalData;
516    }
517    idxLoop[0] += innerLoopSize;
518    idx += innerLoopSize;
519  }
520}
521
522/*!
523  Retrieve index i and index j of a domain from its data index
524  Data contains not only true data, which are sent to servers, but also ghost data, which
525very often play a role of border of each local data, so does data index. Because data of a domain
526can be one dimension, or two dimensions, there is a need to convert data index to domain index
527  \param [in] dataIIndex index of i data
528  \param [in] dataJIndex index of j data
529  \param [in] dataIBegin index begin of i data
530  \param [in] dataJBegin index begin of j data
531  \param [in] dataDim dimension of data (1 or 2)
532  \param [in] ni local size ni of domain
533  \param [out] j j index of domain
534  \return i index of domain
535*/
536int CDistributionClient::getDomainIndex(const int& dataIIndex, const int& dataJIndex,
537                                        const int& dataIBegin, const int& dataJBegin,
538                                        const int& dataDim, const int& ni, int& j)
539{
540  int tempI = dataIIndex + dataIBegin,
541      tempJ = (1 == dataDim) ? -1
542                             : (dataJIndex + dataJBegin);
543  int i = (dataDim == 1) ? (tempI - 1) % ni
544                     : (tempI - 1) ;
545  j = (dataDim == 1) ? (tempI - 1) / ni
546                     : (tempJ - 1) ;
547
548  return i;
549}
550
551/*!
552  Retrieve index of an axis from its data index
553  \param [in] dataIndex index of data
554  \param [in] dataBegin index begin of data
555  \param [in] ni local size of axis
556  \return index of domain
557*/
558int CDistributionClient::getAxisIndex(const int& dataIndex, const int& dataBegin, const int& ni)
559{
560   int tempI = dataIndex + dataBegin;
561   return ((tempI-1)%ni);
562}
563
564/*!
565  Return local data index of client
566*/
567const CArray<int,1>& CDistributionClient::getLocalDataIndexOnClient() const
568{
569  return (*localDataIndex_);
570}
571
572/*!
573  Return local data index on client which are sent to servers
574*/
575const CArray<int,1>& CDistributionClient::getLocalDataIndexSendToServerOnClient() const
576{
577  return (*localDataIndexSendToServer_);
578}
579
580} // namespace xios
Note: See TracBrowser for help on using the repository browser.