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

Last change on this file since 562 was 553, checked in by mhnguyen, 9 years ago

Seperating global index computation on client and server side

+) Create a class which do mapping in general manner, between client and server index global
+) Remove some redundant functions and variables
+) Add some comments to code

Test
+) On Curie. Only test_new_features.f90
+) Test passes and results are correct.
+) Need to change index from 1 to 0

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