source: XIOS/dev/branch_openmp/src/transformation/domain_algorithm_interpolate.cpp @ 1520

Last change on this file since 1520 was 1520, checked in by yushan, 6 years ago

save dev. TO DO : test with xios

File size: 34.7 KB
Line 
1/*!
2   \file domain_algorithm_interpolate_from_file.cpp
3   \author Ha NGUYEN
4   \since 09 Jul 2015
5   \date 15 Sep 2015
6
7   \brief Algorithm for interpolation on a domain.
8 */
9#include "domain_algorithm_interpolate.hpp"
10#include <boost/unordered_map.hpp>
11#include "context.hpp"
12#include "context_client.hpp"
13#include "distribution_client.hpp"
14#include "client_server_mapping_distributed.hpp"
15#include "netcdf.hpp"
16#include "mapper.hpp"
17#include "mpi_tag.hpp"
18#include "domain.hpp"
19#include "grid_transformation_factory_impl.hpp"
20#include "interpolate_domain.hpp"
21#include "grid.hpp"
22using namespace ep_lib;
23
24namespace xios {
25CGenericAlgorithmTransformation* CDomainAlgorithmInterpolate::create(CGrid* gridDst, CGrid* gridSrc,
26                                                                     CTransformation<CDomain>* transformation,
27                                                                     int elementPositionInGrid,
28                                                                     std::map<int, int>& elementPositionInGridSrc2ScalarPosition,
29                                                                     std::map<int, int>& elementPositionInGridSrc2AxisPosition,
30                                                                     std::map<int, int>& elementPositionInGridSrc2DomainPosition,
31                                                                     std::map<int, int>& elementPositionInGridDst2ScalarPosition,
32                                                                     std::map<int, int>& elementPositionInGridDst2AxisPosition,
33                                                                     std::map<int, int>& elementPositionInGridDst2DomainPosition)
34{
35  std::vector<CDomain*> domainListDestP = gridDst->getDomains();
36  std::vector<CDomain*> domainListSrcP  = gridSrc->getDomains();
37
38  CInterpolateDomain* interpolateDomain = dynamic_cast<CInterpolateDomain*> (transformation);
39  int domainDstIndex = elementPositionInGridDst2DomainPosition[elementPositionInGrid];
40  int domainSrcIndex = elementPositionInGridSrc2DomainPosition[elementPositionInGrid];
41
42  return (new CDomainAlgorithmInterpolate(domainListDestP[domainDstIndex], domainListSrcP[domainSrcIndex], interpolateDomain));
43}
44
45bool CDomainAlgorithmInterpolate::registerTrans()
46{
47  CGridTransformationFactory<CDomain>::registerTransformation(TRANS_INTERPOLATE_DOMAIN, create);
48}
49
50CDomainAlgorithmInterpolate::CDomainAlgorithmInterpolate(CDomain* domainDestination, CDomain* domainSource, CInterpolateDomain* interpDomain)
51: CDomainAlgorithmTransformation(domainDestination, domainSource), interpDomain_(interpDomain), writeToFile_(false), readFromFile_(false)
52{
53  CContext* context = CContext::getCurrent();
54  interpDomain_->checkValid(domainSource);
55
56  detectMissingValue = interpDomain_->detect_missing_value ;
57  renormalize = interpDomain_->renormalize ;
58  quantity = interpDomain_->quantity ;
59
60  if (interpDomain_->read_write_convention == CInterpolateDomain::read_write_convention_attr::fortran) fortranConvention=true ;
61  else fortranConvention=false ;
62 
63  fileToReadWrite_ = "xios_interpolation_weights_";
64
65  if (interpDomain_->weight_filename.isEmpty())
66  {
67    fileToReadWrite_ += context->getId() + "_" + 
68                    domainSource->getDomainOutputName() + "_" + 
69                    domainDestination->getDomainOutputName() + ".nc";   
70  }
71  else 
72    fileToReadWrite_ = interpDomain_->weight_filename;
73
74  ifstream f(fileToReadWrite_.c_str()); 
75  switch (interpDomain_->mode)
76  {
77    case CInterpolateDomain::mode_attr::read:
78      readFromFile_ = true;     
79      break;
80    case CInterpolateDomain::mode_attr::compute:
81      readFromFile_ = false;
82      break;
83    case CInterpolateDomain::mode_attr::read_or_compute:     
84      if (!f.good())
85        readFromFile_ = false;
86      else
87        readFromFile_ = true;
88      break;
89    default:
90      break;
91  } 
92
93  writeToFile_ = interpDomain_->write_weight; 
94   
95}
96
97/*!
98  Compute remap with integrated remap calculation module
99*/
100void CDomainAlgorithmInterpolate::computeRemap()
101{
102  using namespace sphereRemap;
103
104  CContext* context = CContext::getCurrent();
105  CContextClient* client=context->client;
106  int clientRank = client->clientRank;
107  int i, j, k, idx;
108  std::vector<double> srcPole(3,0), dstPole(3,0);
109  int orderInterp = interpDomain_->order.getValue();
110
111
112  const double poleValue = 90.0;
113  const int constNVertex = 4; // Value by default number of vertex for rectangular domain
114  int nVertexSrc, nVertexDest;
115  nVertexSrc = nVertexDest = constNVertex;
116
117  // First of all, try to retrieve the boundary values of domain source and domain destination
118  int localDomainSrcSize = domainSrc_->i_index.numElements();
119  int niSrc = domainSrc_->ni.getValue(), njSrc = domainSrc_->nj.getValue();
120  bool hasBoundSrc = domainSrc_->hasBounds;
121  if (hasBoundSrc) nVertexSrc = domainSrc_->nvertex.getValue();
122  CArray<double,2> boundsLonSrc(nVertexSrc,localDomainSrcSize);
123  CArray<double,2> boundsLatSrc(nVertexSrc,localDomainSrcSize);
124
125  if (domainSrc_->hasPole) srcPole[2] = 1;
126  if (hasBoundSrc)  // Suppose that domain source is curvilinear or unstructured
127  {
128    if (!domainSrc_->bounds_lon_2d.isEmpty())
129    {
130      for (j = 0; j < njSrc; ++j)
131        for (i = 0; i < niSrc; ++i)
132        {
133          k=j*niSrc+i;
134          for(int n=0;n<nVertexSrc;++n)
135          {
136            boundsLonSrc(n,k) = domainSrc_->bounds_lon_2d(n,i,j);
137            boundsLatSrc(n,k) = domainSrc_->bounds_lat_2d(n,i,j);
138          }
139        }
140    }
141    else
142    {
143      boundsLonSrc = domainSrc_->bounds_lon_1d;
144      boundsLatSrc = domainSrc_->bounds_lat_1d;
145    }
146  }
147  else // if domain source is rectilinear, not do anything now
148  {
149    CArray<double,1> lon_g ;
150    CArray<double,1> lat_g ;
151
152    if (!domainSrc_->lonvalue_1d.isEmpty() && !domainSrc_->latvalue_1d.isEmpty())
153    {
154      domainSrc_->AllgatherRectilinearLonLat(domainSrc_->lonvalue_1d,domainSrc_->latvalue_1d, lon_g,lat_g) ;
155    }
156    else if (! domainSrc_->latvalue_rectilinear_read_from_file.isEmpty() && ! domainSrc_->lonvalue_rectilinear_read_from_file.isEmpty() )
157    {
158      lat_g=domainSrc_->latvalue_rectilinear_read_from_file ;
159      lon_g=domainSrc_->lonvalue_rectilinear_read_from_file ;
160    }
161    else if (!domainSrc_->lon_start.isEmpty() && !domainSrc_->lon_end.isEmpty() &&
162             !domainSrc_->lat_start.isEmpty() && !domainSrc_->lat_end.isEmpty())
163    {
164      double step=(domainSrc_->lon_end-domainSrc_->lon_start)/domainSrc_->ni_glo ;
165      for (int i=0; i<domainSrc_->ni_glo; ++i) lon_g(i)=domainSrc_->lon_start+i*step ;
166      step=(domainSrc_->lat_end-domainSrc_->lat_start)/domainSrc_->nj_glo ;
167      for (int i=0; i<domainSrc_->ni_glo; ++i) lat_g(i)=domainSrc_->lat_start+i*step ;
168    }
169    else ERROR("void CDomainAlgorithmInterpolate::computeRemap()",<<"Cannot compute bounds for rectilinear domain") ;
170
171    nVertexSrc = constNVertex;
172    domainSrc_->fillInRectilinearBoundLonLat(lon_g,lat_g, boundsLonSrc, boundsLatSrc);
173  }
174
175  std::map<int,std::vector<std::pair<int,double> > > interpMapValueNorthPole;
176  std::map<int,std::vector<std::pair<int,double> > > interpMapValueSouthPole;
177
178  int localDomainDestSize = domainDest_->i_index.numElements();
179  int niDest = domainDest_->ni.getValue(), njDest = domainDest_->nj.getValue();
180  bool hasBoundDest = domainDest_->hasBounds;
181  if (hasBoundDest) nVertexDest = domainDest_->nvertex.getValue();
182  CArray<double,2> boundsLonDest(nVertexDest,localDomainDestSize);
183  CArray<double,2> boundsLatDest(nVertexDest,localDomainDestSize);
184
185  if (domainDest_->hasPole) dstPole[2] = 1;
186  if (hasBoundDest)
187  {
188    if (!domainDest_->bounds_lon_2d.isEmpty())
189    {
190      for (j = 0; j < njDest; ++j)
191        for (i = 0; i < niDest; ++i)
192        {
193          k=j*niDest+i;
194          for(int n=0;n<nVertexDest;++n)
195          {
196            boundsLonDest(n,k) = domainDest_->bounds_lon_2d(n,i,j);
197            boundsLatDest(n,k) = domainDest_->bounds_lat_2d(n,i,j);
198          }
199        }
200    }
201    else
202    {
203      boundsLonDest = domainDest_->bounds_lon_1d;
204      boundsLatDest = domainDest_->bounds_lat_1d;
205    }
206  }
207  else
208  {
209    bool isNorthPole = false;
210    bool isSouthPole = false;
211
212    CArray<double,1> lon_g ;
213    CArray<double,1> lat_g ;
214
215    if (!domainDest_->lonvalue_1d.isEmpty() && !domainDest_->latvalue_1d.isEmpty())
216    {
217      domainDest_->AllgatherRectilinearLonLat(domainDest_->lonvalue_1d,domainDest_->latvalue_1d, lon_g,lat_g) ;
218    }
219    else if (! domainDest_->latvalue_rectilinear_read_from_file.isEmpty() && ! domainDest_->lonvalue_rectilinear_read_from_file.isEmpty() )
220    {
221      lat_g=domainDest_->latvalue_rectilinear_read_from_file ;
222      lon_g=domainDest_->lonvalue_rectilinear_read_from_file ;
223    }
224    else if (!domainDest_->lon_start.isEmpty() && !domainDest_->lon_end.isEmpty() &&
225             !domainDest_->lat_start.isEmpty() && !domainDest_->lat_end.isEmpty())
226    {
227      double step=(domainDest_->lon_end-domainDest_->lon_start)/domainDest_->ni_glo ;
228      for(int i=0; i<domainDest_->ni_glo; ++i) lon_g(i)=domainDest_->lon_start+i*step ;
229      step=(domainDest_->lat_end-domainDest_->lat_start)/domainDest_->nj_glo ;
230      for(int i=0; i<domainDest_->ni_glo; ++i) lat_g(i)=domainDest_->lat_start+i*step ;
231    }
232    else ERROR("void CDomainAlgorithmInterpolate::computeRemap()",<<"Cannot compute bounds for rectilinear domain") ;
233   
234    if (std::abs(poleValue - std::abs(lat_g(0))) < NumTraits<double>::epsilon()) isNorthPole = true;
235    if (std::abs(poleValue - std::abs(lat_g(domainDest_->nj_glo-1))) < NumTraits<double>::epsilon()) isSouthPole = true;
236
237
238
239
240    if (isNorthPole && (0 == domainDest_->jbegin.getValue()))
241    {
242      int ibegin = domainDest_->ibegin.getValue();
243      for (i = 0; i < niDest; ++i)
244      {
245        interpMapValueNorthPole[i+ibegin];
246      }
247    }
248
249    if (isSouthPole && (domainDest_->nj_glo.getValue() == (domainDest_->jbegin.getValue() + njDest)))
250    {
251      int ibegin = domainDest_->ibegin.getValue();
252      int njGlo = domainDest_->nj_glo.getValue();
253      int niGlo = domainDest_->ni_glo.getValue();
254      for (i = 0; i < niDest; ++i)
255      {
256        k = (njGlo - 1)*niGlo + i + ibegin;
257        interpMapValueSouthPole[k];
258      }
259    }
260
261    // Ok, fill in boundary values for rectangular domain
262    nVertexDest = constNVertex;
263    domainDest_->fillInRectilinearBoundLonLat(lon_g,lat_g, boundsLonDest, boundsLatDest);
264  }
265
266
267
268  // Ok, now use mapper to calculate
269  int nSrcLocal = domainSrc_->i_index.numElements();
270  int nDstLocal = domainDest_->i_index.numElements();
271  long int * globalSrc = new long int [nSrcLocal];
272  long int * globalDst = new long int [nDstLocal];
273
274  long int globalIndex;
275  int i_ind, j_ind;
276  for (int idx = 0; idx < nSrcLocal; ++idx)
277  {
278    i_ind=domainSrc_->i_index(idx) ;
279    j_ind=domainSrc_->j_index(idx) ;
280
281    globalIndex = i_ind + j_ind * domainSrc_->ni_glo;
282    globalSrc[idx] = globalIndex;
283  }
284
285  for (int idx = 0; idx < nDstLocal; ++idx)
286  {
287    i_ind=domainDest_->i_index(idx) ;
288    j_ind=domainDest_->j_index(idx) ;
289
290    globalIndex = i_ind + j_ind * domainDest_->ni_glo;
291    globalDst[idx] = globalIndex;
292  }
293
294
295  // Calculate weight index
296  Mapper mapper(client->intraComm);
297  mapper.setVerbosity(PROGRESS) ;
298
299     
300  // supress masked data for the source
301  int nSrcLocalUnmasked = 0 ;
302  for (int idx=0 ; idx < nSrcLocal; idx++) if (domainSrc_->localMask(idx)) ++nSrcLocalUnmasked ;
303
304
305  CArray<double,2> boundsLonSrcUnmasked(nVertexSrc,nSrcLocalUnmasked);
306  CArray<double,2> boundsLatSrcUnmasked(nVertexSrc,nSrcLocalUnmasked);
307  long int * globalSrcUnmasked = new long int [nSrcLocalUnmasked];
308
309  nSrcLocalUnmasked=0 ;
310  for (int idx=0 ; idx < nSrcLocal; idx++)
311  {
312    if (domainSrc_->localMask(idx))
313    {
314      for(int n=0;n<nVertexSrc;++n)
315      {
316        boundsLonSrcUnmasked(n,nSrcLocalUnmasked) = boundsLonSrc(n,idx) ;
317        boundsLatSrcUnmasked(n,nSrcLocalUnmasked) = boundsLatSrc(n,idx) ;
318      }
319      globalSrcUnmasked[nSrcLocalUnmasked]=globalSrc[idx] ;
320      ++nSrcLocalUnmasked ;
321    }
322  }
323
324
325  int nDstLocalUnmasked = 0 ;
326  for (int idx=0 ; idx < nDstLocal; idx++) if (domainDest_->localMask(idx)) ++nDstLocalUnmasked ;
327
328  CArray<double,2> boundsLonDestUnmasked(nVertexDest,nDstLocalUnmasked);
329  CArray<double,2> boundsLatDestUnmasked(nVertexDest,nDstLocalUnmasked);
330  long int * globalDstUnmasked = new long int [nDstLocalUnmasked];
331
332  nDstLocalUnmasked=0 ;
333  for (int idx=0 ; idx < nDstLocal; idx++)
334  {
335    if (domainDest_->localMask(idx))
336    {
337      for(int n=0;n<nVertexDest;++n)
338      {
339        boundsLonDestUnmasked(n,nDstLocalUnmasked) = boundsLonDest(n,idx) ;
340        boundsLatDestUnmasked(n,nDstLocalUnmasked) = boundsLatDest(n,idx) ;
341      }
342      globalDstUnmasked[nDstLocalUnmasked]=globalDst[idx] ;
343      ++nDstLocalUnmasked ;
344    }
345  }
346
347  mapper.setSourceMesh(boundsLonSrcUnmasked.dataFirst(), boundsLatSrcUnmasked.dataFirst(), nVertexSrc, nSrcLocalUnmasked, &srcPole[0], globalSrcUnmasked);
348  mapper.setTargetMesh(boundsLonDestUnmasked.dataFirst(), boundsLatDestUnmasked.dataFirst(), nVertexDest, nDstLocalUnmasked, &dstPole[0], globalDstUnmasked);
349
350  std::vector<double> timings = mapper.computeWeights(orderInterp,renormalize,quantity);
351
352  std::map<int,std::vector<std::pair<int,double> > > interpMapValue;
353  std::map<int,std::vector<std::pair<int,double> > >::const_iterator iteNorthPole = interpMapValueNorthPole.end(),
354                                                                     iteSouthPole = interpMapValueSouthPole.end();
355  for (int idx = 0;  idx < mapper.nWeights; ++idx)
356  {
357    interpMapValue[mapper.targetWeightId[idx]].push_back(make_pair(mapper.sourceWeightId[idx],mapper.remapMatrix[idx]));
358    if (iteNorthPole != interpMapValueNorthPole.find(mapper.targetWeightId[idx]))
359    {
360      interpMapValueNorthPole[mapper.targetWeightId[idx]].push_back(make_pair(mapper.sourceWeightId[idx],mapper.remapMatrix[idx]));
361    }
362
363    if (iteSouthPole != interpMapValueSouthPole.find(mapper.targetWeightId[idx]))
364    {
365      interpMapValueSouthPole[mapper.targetWeightId[idx]].push_back(make_pair(mapper.sourceWeightId[idx],mapper.remapMatrix[idx]));
366    }
367  }
368  int niGloDst = domainDest_->ni_glo.getValue();
369  processPole(interpMapValueNorthPole, niGloDst);
370  processPole(interpMapValueSouthPole, niGloDst);
371
372  if (!interpMapValueNorthPole.empty())
373  {
374     std::map<int,std::vector<std::pair<int,double> > >::iterator itNorthPole = interpMapValueNorthPole.begin();
375     for (; itNorthPole != iteNorthPole; ++itNorthPole)
376     {
377       if (!(itNorthPole->second.empty()))
378        itNorthPole->second.swap(interpMapValue[itNorthPole->first]);
379     }
380  }
381
382  if (!interpMapValueSouthPole.empty())
383  {
384     std::map<int,std::vector<std::pair<int,double> > >::iterator itSouthPole = interpMapValueSouthPole.begin();
385     for (; itSouthPole != iteSouthPole; ++itSouthPole)
386     {
387       if (!(itSouthPole->second.empty()))
388        itSouthPole->second.swap(interpMapValue[itSouthPole->first]);
389     }
390  }
391
392  if (writeToFile_ && !readFromFile_) writeRemapInfo(interpMapValue);
393//  exchangeRemapInfo(interpMapValue);
394  convertRemapInfo(interpMapValue) ;
395
396  delete [] globalSrc;
397  delete [] globalSrcUnmasked;
398  delete [] globalDst;
399  delete [] globalDstUnmasked;
400
401}
402
403void CDomainAlgorithmInterpolate::processPole(std::map<int,std::vector<std::pair<int,double> > >& interMapValuePole,
404                                              int nbGlobalPointOnPole)
405{
406  CContext* context = CContext::getCurrent();
407  CContextClient* client=context->client;
408  //int mykey;
409  //ep_lib::MPI_Comm_rank(client->intraComm, &mykey);
410
411  ep_lib::MPI_Comm poleComme = MPI_COMM_NULL;
412  ep_lib::MPI_Comm_split(client->intraComm, interMapValuePole.empty() ? 0 : 1, 0, &poleComme);
413  //ep_lib::MPI_Comm_split(client->intraComm, interMapValuePole.empty() ? 0 : 1, mykey, &poleComme);
414  //if (!poleComme.is_null())
415  if (poleComme!=MPI_COMM_NULL)
416  {
417    int nbClientPole;
418    ep_lib::MPI_Comm_size(poleComme, &nbClientPole);
419
420    std::map<int,std::vector<std::pair<int,double> > >::iterator itePole = interMapValuePole.end(), itPole,
421                                                                 itbPole = interMapValuePole.begin();
422
423    int nbWeight = 0;
424    for (itPole = itbPole; itPole != itePole; ++itPole)
425       nbWeight += itPole->second.size();
426
427    std::vector<int> recvCount(nbClientPole,0);
428    std::vector<int> displ(nbClientPole,0);
429    ep_lib::MPI_Allgather(&nbWeight,1,MPI_INT,&recvCount[0],1,MPI_INT,poleComme) ;
430    displ[0]=0;
431    for(int n=1;n<nbClientPole;++n) displ[n]=displ[n-1]+recvCount[n-1] ;
432    int recvSize=displ[nbClientPole-1]+recvCount[nbClientPole-1] ;
433
434    std::vector<int> sendSourceIndexBuff(nbWeight);
435    std::vector<double> sendSourceWeightBuff(nbWeight);
436    int k = 0;
437    for (itPole = itbPole; itPole != itePole; ++itPole)
438    {
439      for (int idx = 0; idx < itPole->second.size(); ++idx)
440      {
441        sendSourceIndexBuff[k] = (itPole->second)[idx].first;
442        sendSourceWeightBuff[k] = (itPole->second)[idx].second;
443        ++k;
444      }
445    }
446
447    std::vector<int> recvSourceIndexBuff(recvSize);
448    std::vector<double> recvSourceWeightBuff(recvSize);
449
450    // Gather all index and weight for pole
451    ep_lib::MPI_Allgatherv(&sendSourceIndexBuff[0],nbWeight,MPI_INT,&recvSourceIndexBuff[0],&recvCount[0],&displ[0],MPI_INT,poleComme);
452    ep_lib::MPI_Allgatherv(&sendSourceWeightBuff[0],nbWeight,MPI_DOUBLE,&recvSourceWeightBuff[0],&recvCount[0],&displ[0],MPI_DOUBLE,poleComme);
453
454    std::map<int,double> recvTemp;
455    for (int idx = 0; idx < recvSize; ++idx)
456    {
457      if (recvTemp.end() != recvTemp.find(recvSourceIndexBuff[idx]))
458        recvTemp[recvSourceIndexBuff[idx]] += recvSourceWeightBuff[idx]/nbGlobalPointOnPole;
459      else
460        recvTemp[recvSourceIndexBuff[idx]] = recvSourceWeightBuff[idx]/nbGlobalPointOnPole;
461    }
462
463    std::map<int,double>::const_iterator itRecvTemp, itbRecvTemp = recvTemp.begin(), iteRecvTemp = recvTemp.end();
464
465    for (itPole = itbPole; itPole != itePole; ++itPole)
466    {
467      itPole->second.clear();
468      for (itRecvTemp = itbRecvTemp; itRecvTemp != iteRecvTemp; ++itRecvTemp)
469          itPole->second.push_back(make_pair(itRecvTemp->first, itRecvTemp->second));
470    }
471  }
472
473}
474
475/*!
476  Compute the index mapping between domain on grid source and one on grid destination
477*/
478void CDomainAlgorithmInterpolate::computeIndexSourceMapping_(const std::vector<CArray<double,1>* >& dataAuxInputs)
479{
480  if (readFromFile_) 
481    readRemapInfo();
482  else
483  {
484    computeRemap(); 
485  }
486}
487
488void CDomainAlgorithmInterpolate::writeRemapInfo(std::map<int,std::vector<std::pair<int,double> > >& interpMapValue)
489{ 
490  writeInterpolationInfo(fileToReadWrite_, interpMapValue);
491}
492
493void CDomainAlgorithmInterpolate::readRemapInfo()
494{ 
495  std::map<int,std::vector<std::pair<int,double> > > interpMapValue;
496  readInterpolationInfo(fileToReadWrite_, interpMapValue);
497
498  exchangeRemapInfo(interpMapValue);
499}
500
501void CDomainAlgorithmInterpolate::convertRemapInfo(std::map<int,std::vector<std::pair<int,double> > >& interpMapValue)
502{
503  CContext* context = CContext::getCurrent();
504  CContextClient* client=context->client;
505  int clientRank = client->clientRank;
506
507  this->transformationMapping_.resize(1);
508  this->transformationWeight_.resize(1);
509
510  TransformationIndexMap& transMap = this->transformationMapping_[0];
511  TransformationWeightMap& transWeight = this->transformationWeight_[0];
512
513  std::map<int,std::vector<std::pair<int,double> > >::const_iterator itb = interpMapValue.begin(), it,
514                                                                     ite = interpMapValue.end();
515 
516  for (it = itb; it != ite; ++it)
517  {   
518    const std::vector<std::pair<int,double> >& tmp = it->second;
519    for (int i = 0; i < tmp.size(); ++i)
520    {
521      transMap[it->first].push_back(tmp[i].first);
522      transWeight[it->first].push_back(tmp[i].second);
523    }     
524  }     
525}
526
527/*!
528  Read remap information from file then distribute it among clients
529*/
530void CDomainAlgorithmInterpolate::exchangeRemapInfo(std::map<int,std::vector<std::pair<int,double> > >& interpMapValue)
531{
532  CContext* context = CContext::getCurrent();
533  CContextClient* client=context->client;
534  int clientRank = client->clientRank;
535
536  this->transformationMapping_.resize(1);
537  this->transformationWeight_.resize(1);
538
539  TransformationIndexMap& transMap = this->transformationMapping_[0];
540  TransformationWeightMap& transWeight = this->transformationWeight_[0];
541
542  boost::unordered_map<size_t,int> globalIndexOfDomainDest;
543  int ni = domainDest_->ni.getValue();
544  int nj = domainDest_->nj.getValue();
545  int ni_glo = domainDest_->ni_glo.getValue();
546  size_t globalIndex;
547  int nIndexSize = domainDest_->i_index.numElements(), i_ind, j_ind;
548  for (int idx = 0; idx < nIndexSize; ++idx)
549  {
550    i_ind=domainDest_->i_index(idx) ;
551    j_ind=domainDest_->j_index(idx) ;
552
553    globalIndex = i_ind + j_ind * ni_glo;
554    globalIndexOfDomainDest[globalIndex] = clientRank;
555  }
556
557  CClientServerMappingDistributed domainIndexClientClientMapping(globalIndexOfDomainDest,
558                                                                 client->intraComm,
559                                                                 true);
560  CArray<size_t,1> globalIndexInterp(interpMapValue.size());
561  std::map<int,std::vector<std::pair<int,double> > >::const_iterator itb = interpMapValue.begin(), it,
562                                                                     ite = interpMapValue.end();
563  size_t globalIndexCount = 0;
564  for (it = itb; it != ite; ++it)
565  {
566    globalIndexInterp(globalIndexCount) = it->first;
567    ++globalIndexCount;
568  }
569
570  domainIndexClientClientMapping.computeServerIndexMapping(globalIndexInterp, client->serverSize);
571  const CClientServerMapping::GlobalIndexMap& globalIndexInterpSendToClient = domainIndexClientClientMapping.getGlobalIndexOnServer();
572
573  //Inform each client number of index they will receive
574  int nbClient = client->clientSize;
575  int* sendBuff = new int[nbClient];
576  int* recvBuff = new int[nbClient];
577  for (int i = 0; i < nbClient; ++i)
578  {
579    sendBuff[i] = 0;
580    recvBuff[i] = 0;
581  }
582  int sendBuffSize = 0;
583  CClientServerMapping::GlobalIndexMap::const_iterator itbMap = globalIndexInterpSendToClient.begin(), itMap,
584                                                       iteMap = globalIndexInterpSendToClient.end();
585  for (itMap = itbMap; itMap != iteMap; ++itMap)
586  {
587    const std::vector<size_t>& tmp = itMap->second;
588    int sizeIndex = 0, mapSize = (itMap->second).size();
589    for (int idx = 0; idx < mapSize; ++idx)
590    {
591//      sizeIndex += interpMapValue.at((itMap->second)[idx]).size();
592      sizeIndex += (interpMapValue[(int)(itMap->second)[idx]]).size();
593    }
594    sendBuff[itMap->first] = sizeIndex;
595    sendBuffSize += sizeIndex;
596  }
597
598
599  ep_lib::MPI_Allreduce(sendBuff, recvBuff, nbClient, MPI_INT, MPI_SUM, client->intraComm);
600
601  int* sendIndexDestBuff = new int [sendBuffSize];
602  int* sendIndexSrcBuff  = new int [sendBuffSize];
603  double* sendWeightBuff = new double [sendBuffSize];
604
605  std::vector<ep_lib::MPI_Request> sendRequest(3*globalIndexInterpSendToClient.size());
606
607  int sendOffSet = 0, l = 0;
608  int position = 0;
609  for (itMap = itbMap; itMap != iteMap; ++itMap)
610  {
611    const std::vector<size_t>& indexToSend = itMap->second;
612    int mapSize = indexToSend.size();
613    int k = 0;
614    for (int idx = 0; idx < mapSize; ++idx)
615    {
616      std::vector<std::pair<int,double> >& interpMap = interpMapValue[(int)indexToSend[idx]]; //interpMapValue.at(indexToSend[idx]);
617      for (int i = 0; i < interpMap.size(); ++i)
618      {
619        sendIndexDestBuff[l] = indexToSend[idx];
620        sendIndexSrcBuff[l]  = interpMap[i].first;
621        sendWeightBuff[l]    = interpMap[i].second;
622        ++k;
623        ++l;
624      }
625    }
626
627    ep_lib::MPI_Isend(sendIndexDestBuff + sendOffSet,
628             k,
629             MPI_INT,
630             itMap->first,
631             MPI_DOMAIN_INTERPOLATION_DEST_INDEX,
632             client->intraComm,
633             &sendRequest[position++]);
634    ep_lib::MPI_Isend(sendIndexSrcBuff + sendOffSet,
635             k,
636             MPI_INT,
637             itMap->first,
638             MPI_DOMAIN_INTERPOLATION_SRC_INDEX,
639             client->intraComm,
640             &sendRequest[position++]);
641    ep_lib::MPI_Isend(sendWeightBuff + sendOffSet,
642             k,
643             MPI_DOUBLE,
644             itMap->first,
645             MPI_DOMAIN_INTERPOLATION_WEIGHT,
646             client->intraComm,
647             &sendRequest[position++]);
648    sendOffSet += k;
649  }
650
651  int recvBuffSize = recvBuff[clientRank];
652  int* recvIndexDestBuff = new int [recvBuffSize];
653  int* recvIndexSrcBuff  = new int [recvBuffSize];
654  double* recvWeightBuff = new double [recvBuffSize];
655  int receivedSize = 0;
656  int clientSrcRank;
657  while (receivedSize < recvBuffSize)
658  {
659    ep_lib::MPI_Status recvStatus;
660    ep_lib::MPI_Recv((recvIndexDestBuff + receivedSize),
661             recvBuffSize,
662             MPI_INT,
663             -2,
664             MPI_DOMAIN_INTERPOLATION_DEST_INDEX,
665             client->intraComm,
666             &recvStatus);
667
668    int countBuff = 0;
669    ep_lib::MPI_Get_count(&recvStatus, MPI_INT, &countBuff);
670    #ifdef _usingMPI
671    clientSrcRank = recvStatus.MPI_SOURCE;
672    #elif _usingEP
673    clientSrcRank = recvStatus.ep_src;
674    #endif
675
676    ep_lib::MPI_Recv((recvIndexSrcBuff + receivedSize),
677             recvBuffSize,
678             MPI_INT,
679             clientSrcRank,
680             MPI_DOMAIN_INTERPOLATION_SRC_INDEX,
681             client->intraComm,
682             &recvStatus);
683
684    ep_lib::MPI_Recv((recvWeightBuff + receivedSize),
685             recvBuffSize,
686             MPI_DOUBLE,
687             clientSrcRank,
688             MPI_DOMAIN_INTERPOLATION_WEIGHT,
689             client->intraComm,
690             &recvStatus);
691
692    for (int idx = 0; idx < countBuff; ++idx)
693    {
694      transMap[*(recvIndexDestBuff + receivedSize + idx)].push_back(*(recvIndexSrcBuff + receivedSize + idx));
695      transWeight[*(recvIndexDestBuff + receivedSize + idx)].push_back(*(recvWeightBuff + receivedSize + idx));
696    }
697    receivedSize += countBuff;
698  }
699
700  std::vector<ep_lib::MPI_Status> requestStatus(sendRequest.size());
701  ep_lib::MPI_Waitall(sendRequest.size(), &sendRequest[0], &requestStatus[0]);
702
703  delete [] sendIndexDestBuff;
704  delete [] sendIndexSrcBuff;
705  delete [] sendWeightBuff;
706  delete [] recvIndexDestBuff;
707  delete [] recvIndexSrcBuff;
708  delete [] recvWeightBuff;
709  delete [] sendBuff;
710  delete [] recvBuff;
711}
712 
713/*! Redefined some functions of CONetCDF4 to make use of them */
714CDomainAlgorithmInterpolate::WriteNetCdf::WriteNetCdf(const StdString& filename, const ep_lib::MPI_Comm comm)
715  : CNc4DataOutput(NULL, filename, false, false, true, comm, false, true) {}
716int CDomainAlgorithmInterpolate::WriteNetCdf::addDimensionWrite(const StdString& name, 
717                                                                const StdSize size)
718{
719  return CONetCDF4::addDimension(name, size); 
720}
721
722int CDomainAlgorithmInterpolate::WriteNetCdf::addVariableWrite(const StdString& name, nc_type type,
723                                                               const std::vector<StdString>& dim)
724{
725  return CONetCDF4::addVariable(name, type, dim);
726}
727
728void CDomainAlgorithmInterpolate::WriteNetCdf::endDefinition()
729{
730  CONetCDF4::definition_end();
731}
732
733void CDomainAlgorithmInterpolate::WriteNetCdf::writeDataIndex(const CArray<int,1>& data, const StdString& name,
734                                                              bool collective, StdSize record,
735                                                              const std::vector<StdSize>* start,
736                                                              const std::vector<StdSize>* count)
737{
738  CONetCDF4::writeData<int,1>(data, name, collective, record, start, count);
739}
740
741void CDomainAlgorithmInterpolate::WriteNetCdf::writeDataIndex(const CArray<double,1>& data, const StdString& name,
742                                                              bool collective, StdSize record,
743                                                              const std::vector<StdSize>* start,
744                                                              const std::vector<StdSize>* count)
745{
746  CONetCDF4::writeData<double,1>(data, name, collective, record, start, count);
747}
748
749/*
750   Write interpolation weights into a file
751   \param [in] filename name of output file
752   \param interpMapValue mapping of global index of domain destination and domain source as well as the corresponding weight
753*/
754void CDomainAlgorithmInterpolate::writeInterpolationInfo(std::string& filename,
755                                                         std::map<int,std::vector<std::pair<int,double> > >& interpMapValue)
756{
757  CContext* context = CContext::getCurrent();
758  CContextClient* client=context->client;
759
760  size_t n_src = domainSrc_->ni_glo * domainSrc_->nj_glo;
761  size_t n_dst = domainDest_->ni_glo * domainDest_->nj_glo;
762
763  long localNbWeight = 0;
764  long globalNbWeight;
765  long startIndex;
766  typedef std::map<int,std::vector<std::pair<int,double> > > IndexRemap;
767  IndexRemap::iterator itb = interpMapValue.begin(), it,
768                       ite = interpMapValue.end();
769  for (it = itb; it!=ite; ++it)
770  {
771    localNbWeight += (it->second).size();
772  }
773
774  CArray<int,1> src_idx(localNbWeight);
775  CArray<int,1> dst_idx(localNbWeight);
776  CArray<double,1> weights(localNbWeight);
777
778  int index = 0;
779  int indexOffset=0 ;
780  if (fortranConvention) indexOffset=1 ;
781  for (it = itb; it !=ite; ++it)
782  {
783    std::vector<std::pair<int,double> >& tmp = it->second;
784    for (int idx = 0; idx < tmp.size(); ++idx)
785    {
786      dst_idx(index) = it->first + indexOffset;
787      src_idx(index) = tmp[idx].first + indexOffset;
788      weights(index) = tmp[idx].second;
789      ++index;
790    }   
791  }
792
793  ep_lib::MPI_Allreduce(&localNbWeight, &globalNbWeight, 1, MPI_LONG, MPI_SUM, client->intraComm);
794  ep_lib::MPI_Scan(&localNbWeight, &startIndex, 1, MPI_LONG, MPI_SUM, client->intraComm);
795 
796  if (0 == globalNbWeight)
797  {
798    info << "There is no interpolation weights calculated between "
799         << "domain source: " << domainSrc_->getDomainOutputName()
800         << " and domain destination: " << domainDest_->getDomainOutputName()
801         << std::endl;
802    return;
803  }
804
805  std::vector<StdSize> start(1, startIndex - localNbWeight);
806  std::vector<StdSize> count(1, localNbWeight);
807 
808  WriteNetCdf netCdfWriter(filename, client->intraComm); 
809
810  // Define some dimensions
811  netCdfWriter.addDimensionWrite("n_src", n_src);
812  netCdfWriter.addDimensionWrite("n_dst", n_dst);
813  netCdfWriter.addDimensionWrite("n_weight", globalNbWeight);
814 
815  std::vector<StdString> dims(1,"n_weight");
816
817  // Add some variables
818  netCdfWriter.addVariableWrite("src_idx", NC_INT, dims);
819  netCdfWriter.addVariableWrite("dst_idx", NC_INT, dims);
820  netCdfWriter.addVariableWrite("weight", NC_DOUBLE, dims);
821
822  // End of definition
823  netCdfWriter.endDefinition();
824
825  // // Write variables
826  if (0 != localNbWeight)
827  {
828    netCdfWriter.writeDataIndex(src_idx, "src_idx", false, 0, &start, &count);
829    netCdfWriter.writeDataIndex(dst_idx, "dst_idx", false, 0, &start, &count);
830    netCdfWriter.writeDataIndex(weights, "weight", false, 0, &start, &count);
831  }
832
833  netCdfWriter.closeFile();
834}
835
836/*!
837  Read interpolation information from a file
838  \param [in] filename interpolation file
839  \param [in/out] interpMapValue Mapping between (global) index of domain on grid destination and
840         corresponding global index of domain and associated weight value on grid source
841*/
842void CDomainAlgorithmInterpolate::readInterpolationInfo(std::string& filename,
843                                                        std::map<int,std::vector<std::pair<int,double> > >& interpMapValue)
844{
845  int ncid ;
846  int weightDimId ;
847  size_t nbWeightGlo ;
848
849
850  CContext* context = CContext::getCurrent();
851  CContextClient* client=context->client;
852  int clientRank = client->clientRank;
853  int clientSize = client->clientSize;
854
855
856  {
857    ifstream f(filename.c_str());
858    if (!f.good()) ERROR("void CDomainAlgorithmInterpolate::readInterpolationInfo",
859                      << "Attempt to read file weight :"  << filename << " which doesn't seem to exist." << std::endl
860                      << "Please check this file ");
861  }
862                 
863  nc_open(filename.c_str(),NC_NOWRITE, &ncid) ;
864  nc_inq_dimid(ncid,"n_weight",&weightDimId) ;
865  nc_inq_dimlen(ncid,weightDimId,&nbWeightGlo) ;
866
867  size_t nbWeight ;
868  size_t start ;
869  size_t div = nbWeightGlo/clientSize ;
870  size_t mod = nbWeightGlo%clientSize ;
871  if (clientRank < mod)
872  {
873    nbWeight=div+1 ;
874    start=clientRank*(div+1) ;
875  }
876  else
877  {
878    nbWeight=div ;
879    start= mod * (div+1) + (clientRank-mod) * div ;
880  }
881
882  double* weight=new double[nbWeight] ;
883  int weightId ;
884  nc_inq_varid (ncid, "weight", &weightId) ;
885  nc_get_vara_double(ncid, weightId, &start, &nbWeight, weight) ;
886
887  long* srcIndex=new long[nbWeight] ;
888  int srcIndexId ;
889  nc_inq_varid (ncid, "src_idx", &srcIndexId) ;
890  nc_get_vara_long(ncid, srcIndexId, &start, &nbWeight, srcIndex) ;
891
892  long* dstIndex=new long[nbWeight] ;
893  int dstIndexId ;
894  nc_inq_varid (ncid, "dst_idx", &dstIndexId) ;
895  nc_get_vara_long(ncid, dstIndexId, &start, &nbWeight, dstIndex) ;
896
897  int indexOffset=0 ;
898  if (fortranConvention) indexOffset=1 ;
899    for(size_t ind=0; ind<nbWeight;++ind)
900      interpMapValue[dstIndex[ind]-indexOffset].push_back(make_pair(srcIndex[ind]-indexOffset,weight[ind]));
901 }
902
903void CDomainAlgorithmInterpolate::apply(const std::vector<std::pair<int,double> >& localIndex,
904                                            const double* dataInput,
905                                            CArray<double,1>& dataOut,
906                                            std::vector<bool>& flagInitial,
907                                            bool ignoreMissingValue, bool firstPass  )
908{
909  int nbLocalIndex = localIndex.size();   
910  double defaultValue = std::numeric_limits<double>::quiet_NaN();
911   
912  if (detectMissingValue)
913  {
914     if (firstPass && renormalize)
915     {
916       renormalizationFactor.resize(dataOut.numElements()) ;
917       renormalizationFactor=1 ;
918     }
919     
920    if (firstPass)
921    {
922      allMissing.resize(dataOut.numElements()) ;
923      allMissing=true ;
924    }
925
926    for (int idx = 0; idx < nbLocalIndex; ++idx)
927    {
928      if (NumTraits<double>::isNan(*(dataInput + idx)))
929      {
930        allMissing(localIndex[idx].first) = allMissing(localIndex[idx].first) && true;
931        if (renormalize) renormalizationFactor(localIndex[idx].first)-=localIndex[idx].second ;
932      }
933      else
934      {
935        dataOut(localIndex[idx].first) += *(dataInput + idx) * localIndex[idx].second;   
936      }
937    }
938
939  }
940  else
941  {
942    for (int idx = 0; idx < nbLocalIndex; ++idx)
943    {
944      dataOut(localIndex[idx].first) += *(dataInput + idx) * localIndex[idx].second;
945    }
946  }
947}
948
949void CDomainAlgorithmInterpolate::updateData(CArray<double,1>& dataOut)
950{
951  if (detectMissingValue)
952  {
953    double defaultValue = std::numeric_limits<double>::quiet_NaN();
954    size_t nbIndex=dataOut.numElements() ; 
955
956    for (int idx = 0; idx < nbIndex; ++idx)
957    {
958      if (allMissing(idx)) dataOut(idx) = defaultValue; // If all data source are nan then data destination must be nan
959    }
960   
961    if (renormalize)
962    {
963      if (renormalizationFactor.numElements()>0) dataOut/=renormalizationFactor ; // In some case, process doesn't received any data for interpolation (mask)
964                                                                                 // so renormalizationFactor is not initialized
965    }   
966  }
967}
968
969}
Note: See TracBrowser for help on using the repository browser.