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

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

Doing some cleans and improving a little bit performance of creating local index on server

+) Add some comments, add some initialization
+) Change the way to calculate local index on server

Test
+) On Curie

File size: 25.2 KB
Line 
1#include "distribution_client.hpp"
2
3namespace xios {
4
5CDistributionClient::CDistributionClient(int rank, int dims, CArray<size_t,1>* globalIndex)
6   : CDistribution(rank, dims, globalIndex),
7   localDataIndex_(0), indexGlobalOnServer_(), localIndexSend2Server_(), axisDomainOrder_(),
8   nLocal_(), nGlob_(), nBeginLocal_(), nBeginGlobal_(),nZoomBegin_(), nZoomEnd_(),
9   dataNIndex_(), dataDims_(), dataBegin_(), dataIndex_(), domainMasks_(), axisMasks_(),
10   gridMask_(), localDomainIndex_(), localAxisIndex_(), indexMap_(), connectedClients_(),
11   isConnectedServerComputed_(false), indexDomainData_()
12{
13}
14
15CDistributionClient::CDistributionClient(int rank, CGrid* grid)
16   : CDistribution(rank, 0, 0),
17   localDataIndex_(0), indexGlobalOnServer_(), localIndexSend2Server_(), axisDomainOrder_(),
18   nLocal_(), nGlob_(), nBeginLocal_(), nBeginGlobal_(),nZoomBegin_(), nZoomEnd_(),
19   dataNIndex_(), dataDims_(), dataBegin_(), dataIndex_(), domainMasks_(), axisMasks_(),
20   gridMask_(), localDomainIndex_(), localAxisIndex_(), indexMap_(), connectedClients_(),
21   isConnectedServerComputed_(false), indexDomainData_()
22{
23  readDistributionInfo(grid);
24  createGlobalIndex();
25}
26
27CDistributionClient::~CDistributionClient()
28{
29  if (0 != localDataIndex_) delete localDataIndex_;
30}
31
32/*!
33  Read information of a grid to generate distribution.
34  Every grid is composed of several axis or/and domain(s). Their information are processed
35stored and used to calculate index distribution between client and server
36  \param [in] grid Grid to read
37*/
38void CDistributionClient::readDistributionInfo(CGrid* grid)
39{
40  std::vector<CDomain*> domList = grid->getDomains();
41  std::vector<CAxis*> axisList = grid->getAxis();
42  CArray<bool,1>& axisDomainOrder = grid->axisDomainOrder;
43
44  std::vector<CDomain*>::iterator itbDom, iteDom, itDom;
45  std::vector<CAxis*>::iterator itbAxis, iteAxis, itAxis;
46
47  itbDom  = itDom  = domList.begin();  iteDom  = domList.end();
48  itbAxis = itAxis = axisList.begin(); iteAxis = axisList.end();
49
50  // First of all, every attribute of domain and axis should be checked
51  for (;itDom != iteDom; ++itDom) (*itDom)->checkAttributesOnClient();
52  for (;itAxis != iteAxis; ++itAxis) (*itAxis)->checkAttributes();
53
54  // Then check mask of grid
55  grid->checkMask();
56  CArray<bool,3>& gridMask = grid->mask;
57
58  ////////////////////////////////////////////////////////
59
60  int gridDim = domList.size()*2 + axisList.size();
61
62  // For now, just suppose that gridMask is all true, but we need to cope with this problem
63  //  std::vector<std::vector<bool> > gridMask(gridDim);
64//  int idxDomain = 0, idxAxis = 0;
65//  for (int i = 0; i < axisDomainOrder.size(); ++i)
66//  {
67//    if (axisDomainOrder(i))
68//    {
69//      gridMask[idxDomain*2+i].resize(domList[idxDomain]->ni);
70//      gridMask[idxDomain*2+i+1].resize(domList[idxDomain]->nj);
71//      ++idxDomain;
72//    }
73//    else
74//    {
75//      gridMask[i].resize(axisList[idxAxis]->ni);
76//      ++idxAxis;
77//    }
78//  }
79
80  readDistributionInfo(domList, axisList, axisDomainOrder, gridMask);
81}
82
83/*!
84  Read information from domain(s) and axis to generate distribution.
85  All information related to domain, e.g ibegin, jbegin, ni, nj, ni_glo, nj_glo
86as well as related to axis, e.g dataNIndex, dataIndex will be stored to compute
87the distribution between clients and servers. Till now, every data structure of domain has been kept
88like before, e.g: data_n_index to make sure a compability, however, it should be changed?
89  \param [in] domList List of domains of grid
90  \param [in] axisList List of axis of grid
91  \param [in] axisDomainOrder order of axis and domain inside a grid. True if domain, false if axis
92  \param [in] gridMask Mask of grid, for now, keep it 3 dimension, but it needs changing
93*/
94void CDistributionClient::readDistributionInfo(const std::vector<CDomain*>& domList,
95                                               const std::vector<CAxis*>& axisList,
96                                               const CArray<bool,1>& axisDomainOrder,
97                                               const CArray<bool,3>& gridMask)
98{
99  numElement_ = axisDomainOrder.numElements(); // Number of element, e.x: Axis, Domain
100
101  axisDomainOrder_.resize(numElement_);
102  axisDomainOrder_ = axisDomainOrder;
103
104  // Each domain or axis has its mask, of course
105  domainMasks_.resize(domList.size());
106  for (int i = 0; i < domainMasks_.size();++i)
107  {
108    domainMasks_[i].resize(domList[i]->mask.extent(0), domList[i]->mask.extent(1));
109    domainMasks_[i] = domList[i]->mask;
110  }
111
112  axisMasks_.resize(axisList.size());
113  for (int i = 0; i < axisMasks_.size(); ++i)
114  {
115    axisMasks_[i].resize(axisList[i]->mask.numElements());
116    axisMasks_[i] = axisList[i]->mask;
117  }
118
119  gridMask_.resize(gridMask.extent(0), gridMask.extent(1), gridMask.extent(2));
120  gridMask_ = gridMask;
121
122  // Because domain and axis can be in any order (axis1, domain1, axis2, axis3, )
123  // their position should be specified. In axisDomainOrder, domain == true, axis == false
124  int idx = 0;
125  indexMap_.resize(numElement_);
126  this->dims_ = numElement_;
127  for (int i = 0; i < numElement_; ++i)
128  {
129    indexMap_[i] = idx;
130    if (true == axisDomainOrder(i))
131    {
132      ++(this->dims_);
133      idx += 2;
134    }
135  }
136
137  // Size of each dimension (local and global)
138  nLocal_.resize(this->dims_);
139  nGlob_.resize(this->dims_);
140  nBeginLocal_.resize(this->dims_,0);
141  nBeginGlobal_.resize(this->dims_,0);
142  nZoomBegin_.resize(this->dims_);
143  nZoomEnd_.resize(this->dims_);
144
145  // Data_n_index of domain or axis (For now, axis uses its size as data_n_index
146  dataNIndex_.resize(numElement_);
147  dataDims_.resize(numElement_);
148  dataBegin_.resize(this->dims_);
149
150  // Data_*_index of each dimension
151  dataIndex_.resize(this->dims_);
152
153  // A trick to determine position of each domain in domainList
154  int domIndex = 0, axisIndex = 0;
155  idx = 0;
156
157  // Update all the vectors above
158  while (idx < numElement_)
159  {
160    bool isDomain = axisDomainOrder(idx);
161
162    // If this is a domain
163    if (isDomain)
164    {
165      // On the j axis
166      nLocal_.at(indexMap_[idx]+1) = domList[domIndex]->nj.getValue();
167      nGlob_.at(indexMap_[idx]+1)  = domList[domIndex]->nj_glo.getValue();
168      nBeginLocal_.at(indexMap_[idx]+1) = 0;
169      nBeginGlobal_.at(indexMap_[idx]+1) = domList[domIndex]->jbegin;
170      nZoomBegin_.at((indexMap_[idx]+1)) = domList[domIndex]->zoom_jbegin;
171      nZoomEnd_.at((indexMap_[idx]+1))   = domList[domIndex]->zoom_jbegin + domList[domIndex]->zoom_nj-1;
172
173      dataBegin_.at(indexMap_[idx]+1) = (2 == domList[domIndex]->data_dim) ? domList[domIndex]->data_jbegin.getValue() : -1;
174      dataIndex_.at(indexMap_[idx]+1).resize(domList[domIndex]->data_j_index.numElements());
175      dataIndex_.at(indexMap_[idx]+1) = domList[domIndex]->data_j_index;
176
177      // On the i axis
178      nLocal_.at(indexMap_[idx]) = domList[domIndex]->ni.getValue();
179      nGlob_.at(indexMap_[idx]) = domList[domIndex]->ni_glo.getValue();
180      nBeginLocal_.at(indexMap_[idx]) = 0;
181      nBeginGlobal_.at(indexMap_[idx]) = domList[domIndex]->ibegin;
182      nZoomBegin_.at((indexMap_[idx])) = domList[domIndex]->zoom_ibegin;
183      nZoomEnd_.at((indexMap_[idx]))   = domList[domIndex]->zoom_ibegin + domList[domIndex]->zoom_ni-1;
184
185      dataBegin_.at(indexMap_[idx]) = domList[domIndex]->data_ibegin.getValue();
186      dataIndex_.at(indexMap_[idx]).resize(domList[domIndex]->data_i_index.numElements());
187      dataIndex_.at(indexMap_[idx]) = domList[domIndex]->data_i_index;
188
189      dataNIndex_.at(idx) = domList[domIndex]->data_n_index.getValue();
190      dataDims_.at(idx) = domList[domIndex]->data_dim.getValue();
191      ++domIndex;
192    }
193    else // So it's an axis
194    {
195      nLocal_.at(indexMap_[idx]) = axisList[axisIndex]->zoom_size.getValue();
196      nGlob_.at(indexMap_[idx]) = axisList[axisIndex]->size.getValue();
197      nBeginLocal_.at(indexMap_[idx]) = axisList[axisIndex]->zoom_begin.getValue(); //ibegin.getValue();
198      nBeginGlobal_.at(indexMap_[idx]) = axisList[axisIndex]->ibegin.getValue();
199      nZoomBegin_.at((indexMap_[idx])) = axisList[axisIndex]->zoom_begin;
200      nZoomEnd_.at((indexMap_[idx])) = axisList[axisIndex]->zoom_begin + axisList[axisIndex]->zoom_size-1;
201
202      dataBegin_.at(indexMap_[idx]) = axisList[axisIndex]->data_begin.getValue();
203      dataIndex_.at(indexMap_[idx]).resize(axisList[axisIndex]->data_index.numElements());
204      dataIndex_.at(indexMap_[idx]) = axisList[axisIndex]->data_index;
205      dataNIndex_.at(idx) = axisList[axisIndex]->data_index.numElements();
206      dataDims_.at(idx) = 1;
207      ++axisIndex;
208    }
209    ++idx;
210  }
211}
212
213/*!
214  Create local index of domain(s).
215  A domain can have data index which even contains the "ghost" points. Very often, these
216data surround the true data. In order to send correct data to server,
217a client need to know index of the true data.
218*/
219void CDistributionClient::createLocalDomainDataIndex()
220{
221  int numDomain = 0;
222  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
223    if (axisDomainOrder_(i)) ++numDomain;
224
225  localDomainIndex_.resize(numDomain*2);
226  indexDomainData_.resize(numDomain);
227
228  int idxDomain = 0;
229  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
230  {
231    if (axisDomainOrder_(i))
232    {
233      int iIdx, jIdx = 0, count = 0;
234      indexDomainData_[idxDomain].resize(dataNIndex_[i], false);
235      for (int j = 0; j < dataNIndex_[i]; ++j)
236      {
237        iIdx = getDomainIndex(dataIndex_[indexMap_[i]](j), dataIndex_[indexMap_[i]+1](j),
238                              dataBegin_[indexMap_[i]], dataBegin_[indexMap_[i]+1],
239                              dataDims_[i], nLocal_[indexMap_[i]], jIdx);
240
241        if ((iIdx >= nBeginLocal_[indexMap_[i]]) && (iIdx < nLocal_[indexMap_[i]]) &&
242           (jIdx >= nBeginLocal_[indexMap_[i]+1]) && (jIdx < nLocal_[indexMap_[i]+1]) &&
243           (domainMasks_[idxDomain](iIdx, jIdx)))
244        {
245          (localDomainIndex_[idxDomain]).push_back(iIdx);
246          (localDomainIndex_[idxDomain*2+1]).push_back(jIdx);
247          indexDomainData_[idxDomain][j] = true;
248        }
249      }
250      ++idxDomain;
251    }
252  }
253}
254
255/*!
256  Create local index of axis.
257*/
258void CDistributionClient::createLocalAxisDataIndex()
259{
260  int numAxis = 0;
261  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
262    if (!axisDomainOrder_(i)) ++numAxis;
263
264  localAxisIndex_.resize(numAxis);
265
266  int idxAxis = 0;
267  for (int i = 0; i < axisDomainOrder_.numElements(); ++i)
268  {
269    if (!axisDomainOrder_(i))
270    {
271      int iIdx = 0;
272      for (int j = 0; j < dataNIndex_[i]; ++j)
273      {
274        iIdx = getAxisIndex(dataIndex_[indexMap_[i]](j), dataBegin_[indexMap_[i]], nLocal_[indexMap_[i]]);
275        if ((iIdx >= nBeginLocal_[indexMap_[i]]) &&
276           (iIdx < nLocal_[indexMap_[i]]) && (axisMasks_[idxAxis](iIdx)))
277        {
278          localAxisIndex_[idxAxis].push_back(iIdx);
279        }
280      }
281      ++idxAxis;
282    }
283  }
284}
285
286/*!
287   Create global index on client
288   In order to do the mapping between client-server, each client creates its own
289global index of sending data. This global index is then used to calculate to which server
290the client needs to send it data as well as which part of data belongs to the server.
291So as to make clients and server coherent in order of index, global index is calculated by
292take into account of C-convention, the rightmost dimension varies faster.
293*/
294void CDistributionClient::createGlobalIndex()
295{
296  createLocalDomainDataIndex();
297  createLocalAxisDataIndex();
298
299  int idxDomain = 0, idxAxis = 0;
300  std::vector<int> eachElementSize(numElement_);
301
302  // Precompute size of the loop
303  for (int i = 0; i < numElement_; ++i)
304  {
305    if(axisDomainOrder_(i))
306    {
307      eachElementSize[i] = localDomainIndex_[idxDomain].size();
308      idxDomain += 2;
309    }
310    else
311    {
312      eachElementSize[i] = localAxisIndex_[idxAxis].size();
313      ++idxAxis;
314    }
315  }
316
317  //   Compute size of the global index on client
318  std::vector<int> idxLoop(numElement_,0);
319  std::vector<int> currentIndex(this->dims_);
320  int innerLoopSize = eachElementSize[0];
321  size_t idx = 0, indexLocalDataOnClientCount = 0, indexSend2ServerCount = 0;
322  size_t ssize = 1;
323  for (int i = 0; i < numElement_; ++i) ssize *= eachElementSize[i];
324  while (idx < ssize)
325  {
326    for (int i = 0; i < numElement_-1; ++i)
327    {
328      if (idxLoop[i] == eachElementSize[i])
329      {
330        idxLoop[i] = 0;
331        ++idxLoop[i+1];
332      }
333    }
334
335    // Outer index
336    idxDomain = idxAxis = 0;
337    for (int i = 1; i < numElement_; ++i)
338    {
339      if (axisDomainOrder_(i))
340      {
341        currentIndex[indexMap_[i]]   = localDomainIndex_[idxDomain][idxLoop[i]];
342        currentIndex[indexMap_[i]+1] = localDomainIndex_[idxDomain+1][idxLoop[i]];
343        idxDomain += 2;
344      }
345      else
346      {
347        currentIndex[indexMap_[i]]   = localAxisIndex_[idxAxis][idxLoop[i]];
348        ++idxAxis;
349      }
350    }
351
352    // Inner most index
353    idxDomain = idxAxis = 0;
354    for (int i = 0; i < innerLoopSize; ++i)
355    {
356      if (axisDomainOrder_(0))
357      {
358        currentIndex[0] = localDomainIndex_[idxDomain][i];
359        currentIndex[1] = localDomainIndex_[idxDomain+1][i];
360      }
361      else currentIndex[0]   = localAxisIndex_[idxAxis][i];
362
363      if (gridMask_(currentIndex[0], currentIndex[1], currentIndex[2]))
364      {
365        ++indexLocalDataOnClientCount;
366        bool isIndexOnServer = true;
367        for (int j = 0; j < this->dims_; ++j)
368          isIndexOnServer = isIndexOnServer && ((currentIndex[j]+nBeginGlobal_[j]) <= nZoomEnd_[j])
369                                            && (nZoomBegin_[j] <= (currentIndex[j]+nBeginGlobal_[j]));
370        if (isIndexOnServer) ++indexSend2ServerCount;
371      }
372
373    }
374    idxLoop[0] += innerLoopSize;
375    idx += innerLoopSize;
376  }
377
378  // Fill in the global index
379  this->globalIndex_ = new CArray<size_t,1>(indexSend2ServerCount);
380  localDataIndex_ = new CArray<int,1>(indexLocalDataOnClientCount);
381
382  eachElementSize = dataNIndex_;
383  innerLoopSize = eachElementSize[0];
384  ssize = 1; for (int i = 0; i < numElement_; ++i) ssize *= eachElementSize[i];
385  idxLoop.assign(numElement_,0);
386  idx = indexLocalDataOnClientCount = indexSend2ServerCount = 0;
387  int count = 0;
388  while (idx < ssize)
389  {
390    for (int i = 0; i < numElement_-1; ++i)
391    {
392      if (idxLoop[i] == eachElementSize[i])
393      {
394        idxLoop[i] = 0;
395        ++idxLoop[i+1];
396      }
397    }
398
399    // Outer index
400    idxDomain = idxAxis = 0;
401    bool isIndexDataCorrect = false;
402    for (int i = 1; i < numElement_; ++i)
403    {
404      if (axisDomainOrder_(i))
405      {
406        if (indexDomainData_[idxDomain][idxLoop[i]])
407        {
408          currentIndex[indexMap_[i]]   = localDomainIndex_[idxDomain][idxLoop[i]];
409          currentIndex[indexMap_[i]+1] = localDomainIndex_[idxDomain*2+1][idxLoop[i]];
410          isIndexDataCorrect = true;
411        }
412        ++idxDomain;
413      }
414      else
415      {
416        currentIndex[indexMap_[i]]   = localAxisIndex_[idxAxis][idxLoop[i]];
417        ++idxAxis;
418      }
419    }
420
421    // Inner most index
422    idxDomain = idxAxis = 0;
423    int correctIndexDomain = 0;
424    for (int i = 0; i < innerLoopSize; ++i)
425    {
426      if (axisDomainOrder_(0))
427      {
428        if (indexDomainData_[idxDomain][i])
429        {
430          currentIndex[0] = localDomainIndex_[idxDomain][correctIndexDomain];
431          currentIndex[1] = localDomainIndex_[idxDomain+1][correctIndexDomain];
432          isIndexDataCorrect = true;
433          ++correctIndexDomain;
434        } else isIndexDataCorrect = false;
435      }
436      else
437      {
438        currentIndex[0]   = localAxisIndex_[idxAxis][i];
439      }
440
441      if (isIndexDataCorrect && gridMask_(currentIndex[0], currentIndex[1], currentIndex[2]))
442      {
443        (*localDataIndex_)(indexLocalDataOnClientCount) = count;
444        ++indexLocalDataOnClientCount;
445
446        bool isIndexOnServer = true;
447        for (int j = 0; j < this->dims_; ++j)
448          isIndexOnServer = isIndexOnServer && ((currentIndex[j]+nBeginGlobal_[j]) <= nZoomEnd_[j])
449                                            && (nZoomBegin_[j] <= (currentIndex[j]+nBeginGlobal_[j]));
450        if (isIndexOnServer)
451        {
452          size_t mulDim = 1;
453          size_t globalIndex = currentIndex[0] + nBeginGlobal_[0];
454          for (int k = 1; k < this->dims_; ++k)
455          {
456            mulDim *= nGlob_[k-1];
457            globalIndex += (currentIndex[k] + nBeginGlobal_[k])*mulDim;
458          }
459          (*this->globalIndex_)(indexSend2ServerCount) = globalIndex;
460          ++indexSend2ServerCount;
461        }
462      }
463      ++count;
464    }
465    idxLoop[0] += innerLoopSize;
466    idx += innerLoopSize;
467  }
468
469//  std::cout << "global index " << *this->globalIndex_ << std::endl;
470//  std::cout << "local index " << *localDataIndex_ << std::endl;
471}
472
473/*!
474  Retrieve index i and index j of a domain from its data index
475  Data contains not only true data, which are sent to servers, but also ghost data, which
476very often play a role of border of each local data, so does data index. Because data of a domain
477can be one dimension, or two dimensions, there is a need to convert data index to domain index
478  \param [in] dataIIndex index of i data
479  \param [in] dataJIndex index of j data
480  \param [in] dataIBegin index begin of i data
481  \param [in] dataJBegin index begin of j data
482  \param [in] dataDim dimension of data (1 or 2)
483  \param [in] ni local size ni of domain
484  \param [out] j j index of domain
485  \return i index of domain
486*/
487int CDistributionClient::getDomainIndex(const int& dataIIndex, const int& dataJIndex,
488                                        const int& dataIBegin, const int& dataJBegin,
489                                        const int& dataDim, const int& ni, int& j)
490{
491  int tempI = dataIIndex + dataIBegin,
492      tempJ = (1 == dataDim) ? -1
493                             : (dataJIndex + dataJBegin);
494  int i = (dataDim == 1) ? (tempI - 1) % ni
495                     : (tempI - 1) ;
496  j = (dataDim == 1) ? (tempI - 1) / ni
497                     : (tempJ - 1) ;
498
499  return i;
500}
501
502/*!
503  Retrieve index of an axis from its data index
504  \param [in] dataIndex index of data
505  \param [in] dataBegin index begin of data
506  \param [in] ni local size of axis
507  \return index of domain
508*/
509int CDistributionClient::getAxisIndex(const int& dataIndex, const int& dataBegin, const int& ni)
510{
511   int tempI = dataIndex + dataBegin;
512   return ((tempI-1)%ni);
513//   return ((tempI)%ni);
514}
515
516/*!
517  Compute global index of each server distributed by band
518  The classic distribution of servers: each server takes charges of writing data divided
519into blocks on the second dimension of grid. If the grid contain a domain, this second dimension is nj.
520  \param [in] nServer number of server
521  \return vector of pointer to array of global index of servers
522*/
523std::vector<CArray<size_t,1>* > CDistributionClient::computeServerBandDistribution(int nServer)
524{
525  // It's not intelligent to allocate dynamic memory inside one function and dellocate in another
526  // but it's a way to free a large amount of unnecessary memory
527  // This function must NEVER made into public.
528  size_t ssize = 1, idx = 0;
529  for (int i = 0; i < nGlob_.size(); ++i) ssize *= nGlob_[i];
530  std::vector<int> idxLoop(this->dims_,0);
531  std::vector<int> indexServer(nServer,0);
532  int njRangeSize;
533  std::vector<int> njRangeBegin(nServer,0);
534  std::vector<int> njRangeEnd(nServer,0);
535  std::vector<CArray<size_t,1>* > globalIndexServer(nServer);
536
537  int innerLoopSize = nGlob_[0], idxServer;
538  if (1<nGlob_.size())
539  {
540    for (int i = 0; i < nServer; ++i)
541    {
542      if (0 < i) njRangeBegin[i] = njRangeEnd[i-1];
543      njRangeSize = nGlob_[1] / nServer;
544      if (i < nGlob_[1]%nServer) ++njRangeSize;
545      njRangeEnd[i] = njRangeSize + njRangeBegin[i];
546    }
547    njRangeEnd[nServer-1] = nGlob_[1];
548
549    // Compute size of each global index server array
550    while (idx < ssize)
551    {
552      for (int i = 0; i < this->dims_-1; ++i)
553      {
554        if (idxLoop[i] == nGlob_[i])
555        {
556          idxLoop[i] = 0;
557          ++idxLoop[i+1];
558        }
559      }
560
561      for (int i = 0; i < nServer; ++i)
562        if ((njRangeBegin[i]<=idxLoop[1]) && (idxLoop[1] < njRangeEnd[i]))
563        {
564          idxServer = i;
565          break;
566        }
567
568      indexServer[idxServer] += innerLoopSize;
569      idxLoop[0] += innerLoopSize;
570      idx += innerLoopSize;
571    }
572
573
574    for (int i = 0; i < nServer; ++i) globalIndexServer[i] = new CArray<size_t,1>(indexServer[i]);
575
576    // Fill in each global index server array
577    idx = 0;
578    idxLoop.assign(this->dims_,0);
579    indexServer.assign(nServer,0);
580    size_t globalIndex = 0;
581    while (idx < ssize)
582    {
583      for (int i = 0; i < this->dims_-1; ++i)
584      {
585        if (idxLoop[i] == nGlob_[i])
586        {
587          idxLoop[i] = 0;
588          ++idxLoop[i+1];
589        }
590      }
591
592      for (int i = 0; i < nServer; ++i)
593        if ((njRangeBegin[i]<=idxLoop[1]) && (idxLoop[1] < njRangeEnd[i]))
594        {
595          idxServer = i;
596          break;
597        }
598
599      for (int i = 0; i < innerLoopSize; ++i)
600      {
601        (*globalIndexServer[idxServer])(indexServer[idxServer]) = globalIndex;
602        ++indexServer[idxServer];
603        ++globalIndex;
604      }
605      idxLoop[0] += innerLoopSize;
606      idx += innerLoopSize;
607    }
608  }
609
610  return globalIndexServer;
611}
612
613/*!
614  Compute index mapping between cliens and servers
615  On using global index of data on clients and servers, each client calculates which part
616of data will be sent to the corresponding server. After the functions is called, client can use
617all computed information to send correct data to server
618  \param [in] nServer number of server
619  \param [in] distributionType type of distribution, like band or plan
620*/
621void CDistributionClient::computeServerIndexMapping(int nServer, ServerDistributionType distributionType)
622{
623  std::vector<CArray<size_t,1>* > globalIndexServer;
624
625  switch (distributionType)
626  {
627    case BAND_DISTRIBUTION:
628      globalIndexServer = computeServerBandDistribution(nServer);
629      break;
630    default:
631      break;
632  }
633
634  std::vector<CArray<size_t,1>::const_iterator> itBegin(nServer), itEnd(nServer), it(nServer);
635  for (int i = 0; i < nServer; ++i)
636  {
637    itBegin[i] = it[i] = globalIndexServer[i]->begin();
638    itEnd[i]   = globalIndexServer[i]->end();
639  }
640
641  size_t ssize = (this->globalIndex_)->numElements();
642  for (int i = 0; i < ssize; ++i)
643  {
644    for (int j = 0; j < nServer; ++j)
645    {
646      // Just temporarily, it's bad.
647
648      if (std::binary_search(itBegin[j], itEnd[j], (*this->globalIndex_)(i)))
649      {
650        // Just try to calculate local index server on client side
651        (indexGlobalOnServer_[j]).push_back((*this->globalIndex_)(i));
652        (localIndexSend2Server_[j]).push_back(i);
653        continue;
654      }
655    }
656  }
657
658  for (int i = 0; i < nServer; ++i)
659    if (0 != globalIndexServer[i]) delete globalIndexServer[i];
660}
661
662/*!
663  Compute how many clients each server will receive data from
664  On client can send data to several servers as well as one server can receive data originated from
665some clients. In order to write data correctly, each server must know from how many clients it receives data
666  \param [in] nbServer number of servers
667  \param [in] nClient number of clients
668  \param [in] clientIntraComm MPI communication of clients
669  \return mapping of server rank and the number of connected clients
670*/
671std::map<int,int> CDistributionClient::computeConnectedClients(int nbServer, int nbClient, MPI_Comm& clientIntraComm)
672{
673  if (isConnectedServerComputed_) return connectedClients_;
674  std::map<int, std::vector<size_t> >::const_iterator itbMap, iteMap, it;
675  itbMap = it = indexGlobalOnServer_.begin();
676  iteMap = indexGlobalOnServer_.end();
677
678  std::vector<int> connectedServer;
679  std::vector<bool> isConnected(nbServer,false);
680
681  for (it = itbMap; it != iteMap; ++it)
682  {
683    for (int serverNum = 0; serverNum < nbServer; ++serverNum)
684      if (it->first == serverNum) isConnected[serverNum] = true;
685  }
686
687  for(int serverNum = 0; serverNum<nbServer; ++serverNum)
688    if (isConnected[serverNum])
689      connectedServer.push_back(serverNum);
690
691
692  int nbConnectedServer=connectedServer.size();
693  int* recvCount=new int[nbClient];
694  int* displ=new int[nbClient];
695  int* sendBuff=new int[nbConnectedServer];
696  valarray<int> clientRes(0,nbServer);
697
698  for(int n=0;n<nbConnectedServer;n++) sendBuff[n]=connectedServer[n] ;
699
700  // get connected server for everybody
701  MPI_Allgather(&nbConnectedServer,1,MPI_INT,recvCount,1,MPI_INT,clientIntraComm) ;
702
703  displ[0]=0 ;
704  for(int n=1;n<nbClient;n++) displ[n]=displ[n-1]+recvCount[n-1] ;
705  int recvSize=displ[nbClient-1]+recvCount[nbClient-1] ;
706  int* recvBuff=new int[recvSize] ;
707
708
709  MPI_Allgatherv(sendBuff,nbConnectedServer,MPI_INT,recvBuff,recvCount,displ,MPI_INT,clientIntraComm) ;
710  for(int n=0;n<recvSize;n++) clientRes[recvBuff[n]]++ ;
711
712//  std::map<int,int> nbSenders;
713  for(int n=0;n<nbConnectedServer;n++)
714  {
715    connectedClients_[connectedServer[n]] = clientRes[connectedServer[n]];
716  }
717
718  isConnectedServerComputed_ = true;
719
720  delete [] recvCount ;
721  delete [] displ ;
722  delete [] sendBuff ;
723  delete [] recvBuff ;
724
725  return connectedClients_;
726}
727
728/*!
729  Return local index of data that is send to server
730  \return mapping of server rank and local index of sending data on the client
731*/
732const std::map<int, std::vector<int> >& CDistributionClient::getLocalIndexSendToServer() const
733{
734  return localIndexSend2Server_;
735}
736
737/*!
738  Return local data index of client
739*/
740const CArray<int,1>& CDistributionClient::getLocalDataIndexOnClient() const
741{
742  return (*localDataIndex_);
743}
744
745/*!
746  Return global index of data on each connected server.
747  On receiving data sent from client(s), each server with this global index, is able to
748know where the data should be written.
749  \return mapping of server rank and its global index.
750*/
751const std::map<int, std::vector<size_t> >& CDistributionClient::getGlobalIndexOnServer() const
752{
753  return indexGlobalOnServer_;
754}
755
756} // namespace xios
Note: See TracBrowser for help on using the repository browser.