source: XIOS2/trunk/extern/remap/src/mapper.cpp @ 2506

Last change on this file since 2506 was 2506, checked in by ymipsl, 13 months ago

Supress limitation of number of vertex max in remaper.
YM

File size: 33.5 KB
RevLine 
[694]1#include "mpi.hpp"
[688]2#include <map>
3#include "cputime.hpp"       /* time */
4#include "meshutil.hpp"
5#include "polyg.hpp"
6#include "circle.hpp"
7#include "intersect.hpp"
8#include "intersection_ym.hpp"
9#include "errhandle.hpp"
10#include "mpi_routing.hpp"
11#include "gridRemap.hpp"
12
13#include "mapper.hpp"
14
15namespace sphereRemap {
16
17/* A subdivition of an array into N sub-arays
18   can be represented by the length of the N arrays
19   or by the offsets when each of the N arrays starts.
20   This function convertes from the former to the latter. */
21void cptOffsetsFromLengths(const int *lengths, int *offsets, int sz)
22{
[1614]23  offsets[0] = 0;
24  for (int i = 1; i < sz; i++)
25    offsets[i] = offsets[i-1] + lengths[i-1];
[688]26}
27
28
[1614]29void Mapper::setSourceMesh(const double* boundsLon, const double* boundsLat, const double* area, int nVertex, int nbCells, const double* pole, const long int* globalId)
[688]30{
31  srcGrid.pole = Coord(pole[0], pole[1], pole[2]);
32
[1614]33  int mpiRank, mpiSize;
[1639]34  MPI_Comm_rank(communicator, &mpiRank);
35  MPI_Comm_size(communicator, &mpiSize);
[688]36
[1614]37  sourceElements.reserve(nbCells);
38  sourceMesh.reserve(nbCells);
[688]39  sourceGlobalId.resize(nbCells) ;
40
41  if (globalId==NULL)
42  {
43    long int offset ;
44    long int nb=nbCells ;
[1639]45    MPI_Scan(&nb,&offset,1,MPI_LONG,MPI_SUM,communicator) ;
[688]46    offset=offset-nb ;
47    for(int i=0;i<nbCells;i++) sourceGlobalId[i]=offset+i ;
48  }
49  else sourceGlobalId.assign(globalId,globalId+nbCells);
50
[1614]51  for (int i = 0; i < nbCells; i++)
52  {
53    int offs = i*nVertex;
54    Elt elt(boundsLon + offs, boundsLat + offs, nVertex);
55    elt.src_id.rank = mpiRank;
56    elt.src_id.ind = i;
[688]57    elt.src_id.globalId = sourceGlobalId[i];
[1614]58    sourceElements.push_back(elt);
59    sourceMesh.push_back(Node(elt.x, cptRadius(elt), &sourceElements.back()));
60    cptEltGeom(sourceElements[i], Coord(pole[0], pole[1], pole[2]));
61    if (area!=NULL) sourceElements[i].given_area=area[i] ;
62    else sourceElements[i].given_area=sourceElements[i].area ;
63  }
[688]64
65}
66
[1614]67void Mapper::setTargetMesh(const double* boundsLon, const double* boundsLat, const double* area, int nVertex, int nbCells, const double* pole, const long int* globalId)
[688]68{
69  tgtGrid.pole = Coord(pole[0], pole[1], pole[2]);
70
[1614]71  int mpiRank, mpiSize;
[1639]72  MPI_Comm_rank(communicator, &mpiRank);
73  MPI_Comm_size(communicator, &mpiSize);
[688]74
[1614]75  targetElements.reserve(nbCells);
76  targetMesh.reserve(nbCells);
[688]77
78  targetGlobalId.resize(nbCells) ;
79  if (globalId==NULL)
80  {
81    long int offset ;
82    long int nb=nbCells ;
[1639]83    MPI_Scan(&nb,&offset,1,MPI_LONG,MPI_SUM,communicator) ;
[688]84    offset=offset-nb ;
85    for(int i=0;i<nbCells;i++) targetGlobalId[i]=offset+i ;
86  }
87  else targetGlobalId.assign(globalId,globalId+nbCells);
88
[1614]89  for (int i = 0; i < nbCells; i++)
90  {
91    int offs = i*nVertex;
92    Elt elt(boundsLon + offs, boundsLat + offs, nVertex);
93    targetElements.push_back(elt);
94    targetMesh.push_back(Node(elt.x, cptRadius(elt), &sourceElements.back()));
95    cptEltGeom(targetElements[i], Coord(pole[0], pole[1], pole[2]));
96    if (area!=NULL) targetElements[i].given_area=area[i] ;
97    else targetElements[i].given_area=targetElements[i].area ;
98  }
[688]99
100
101}
102
103void Mapper::setSourceValue(const double* val)
104{
105  int size=sourceElements.size() ;
106  for(int i=0;i<size;++i) sourceElements[i].val=val[i] ;
107}
108
109void Mapper::getTargetValue(double* val)
110{
111  int size=targetElements.size() ;
112  for(int i=0;i<size;++i) val[i]=targetElements[i].val ;
113}
114
[1158]115vector<double> Mapper::computeWeights(int interpOrder, bool renormalize, bool quantity)
[688]116{
[1614]117  vector<double> timings;
118  int mpiSize, mpiRank;
[1639]119  MPI_Comm_size(communicator, &mpiSize);
120  MPI_Comm_rank(communicator, &mpiRank);
[688]121
122  this->buildSSTree(sourceMesh, targetMesh);
123
[1614]124  if (mpiRank == 0 && verbose) cout << "Computing intersections ..." << endl;
125  double tic = cputime();
126  computeIntersection(&targetElements[0], targetElements.size());
127  timings.push_back(cputime() - tic);
[688]128
[1614]129  tic = cputime();
130  if (interpOrder == 2) {
131    if (mpiRank == 0 && verbose) cout << "Computing grads ..." << endl;
132    buildMeshTopology();
133    computeGrads();
134  }
135  timings.push_back(cputime() - tic);
[688]136
[1614]137  /* Prepare computation of weights */
138  /* compute number of intersections which for the first order case
[688]139           corresponds to the number of edges in the remap matrix */
[1614]140  int nIntersections = 0;
141  for (int j = 0; j < targetElements.size(); j++)
142  {
143    Elt &elt = targetElements[j];
144    for (list<Polyg*>::iterator it = elt.is.begin(); it != elt.is.end(); it++)
145      nIntersections++;
146  }
[2506]147
[1614]148  /* overallocate for NMAX neighbours for each elements */
[2506]149/*
[1614]150  remapMatrix = new double[nIntersections*NMAX];
151  srcAddress = new int[nIntersections*NMAX];
152  srcRank = new int[nIntersections*NMAX];
153  dstAddress = new int[nIntersections*NMAX];
[688]154  sourceWeightId =new long[nIntersections*NMAX];
155  targetWeightId =new long[nIntersections*NMAX];
[2506]156*/
[688]157
[1614]158  if (mpiRank == 0 && verbose) cout << "Remapping..." << endl;
159  tic = cputime();
160  nWeights = remap(&targetElements[0], targetElements.size(), interpOrder, renormalize, quantity);
161  timings.push_back(cputime() - tic);
[688]162
163  for (int i = 0; i < targetElements.size(); i++) targetElements[i].delete_intersections();
164
[1614]165  return timings;
[688]166}
167
168/**
169   @param elements are cells of the target grid that are distributed over CPUs
170          indepentently of the distribution of the SS-tree.
171   @param nbElements is the size of the elements array.
172   @param order is the order of interpolaton (must be 1 or 2).
173*/
[1158]174int Mapper::remap(Elt *elements, int nbElements, int order, bool renormalize, bool quantity)
[688]175{
[1614]176  int mpiSize, mpiRank;
[1639]177  MPI_Comm_size(communicator, &mpiSize);
178  MPI_Comm_rank(communicator, &mpiRank);
[688]179
[1614]180  /* create list of intersections (super mesh elements) for each rank */
181  multimap<int, Polyg *> *elementList = new multimap<int, Polyg *>[mpiSize];
182  for (int j = 0; j < nbElements; j++)
183  {
184    Elt& e = elements[j];
185    for (list<Polyg *>::iterator it = e.is.begin(); it != e.is.end(); it++)
186      elementList[(*it)->id.rank].insert(pair<int, Polyg *>((*it)->id.ind, *it));
187  }
[688]188
[1614]189  int *nbSendElement = new int[mpiSize];
[2506]190  int *nbSendVertex = new int[mpiSize];
[1614]191  int **sendElement = new int*[mpiSize]; /* indices of elements required from other rank */
192  double **recvValue = new double*[mpiSize];
193  double **recvArea = new double*[mpiSize];
194  double **recvGivenArea = new double*[mpiSize];
[2506]195  int **recvVertexOffset = new int*[mpiSize];
[1614]196  Coord **recvGrad = new Coord*[mpiSize];
197  GloId **recvNeighIds = new GloId*[mpiSize]; /* ids of the of the source neighbours which also contribute through gradient */
198  for (int rank = 0; rank < mpiSize; rank++)
199  {
200    /* get size for allocation */
201    int last = -1; /* compares unequal to any index */
202    int index = -1; /* increased to starting index 0 in first iteration */
203    for (multimap<int, Polyg *>::iterator it = elementList[rank].begin(); it != elementList[rank].end(); ++it)
204    {
205      if (last != it->first)
206        index++;
207      (it->second)->id.ind = index;
208      last = it->first;
209    }
210    nbSendElement[rank] = index + 1;
[688]211
[1614]212    /* if size is non-zero allocate and collect indices of elements on other ranks that we intersect */
213    if (nbSendElement[rank] > 0)
214    {
215      sendElement[rank] = new int[nbSendElement[rank]];
216      last = -1;
217      index = -1;
218      for (multimap<int, Polyg *>::iterator it = elementList[rank].begin(); it != elementList[rank].end(); ++it)
219      {
220        if (last != it->first)
221          index++;
222        sendElement[rank][index] = it->first;
223        last = it->first;
224      }
225    }
226  }
[688]227
[1614]228  /* communicate sizes of source elements to be sent (index lists and later values and gradients) */
229  int *nbRecvElement = new int[mpiSize];
[2506]230  int *nbRecvVertex = new int[mpiSize];
[1639]231  MPI_Alltoall(nbSendElement, 1, MPI_INT, nbRecvElement, 1, MPI_INT, communicator);
[688]232
[1614]233  /* communicate indices of source elements on other ranks whoes value and gradient we need (since intersection) */
234  int nbSendRequest = 0;
235  int nbRecvRequest = 0;
236  int **recvElement = new int*[mpiSize];
237  double **sendValue = new double*[mpiSize];
238  double **sendArea = new double*[mpiSize];
239  double **sendGivenArea = new double*[mpiSize];
[2506]240  int    **sendVertexOffset = new int*[mpiSize];
[1614]241  Coord **sendGrad = new Coord*[mpiSize];
242  GloId **sendNeighIds = new GloId*[mpiSize];
[2506]243  MPI_Request *sendRequest = new MPI_Request[6*mpiSize];
244  MPI_Request *recvRequest = new MPI_Request[6*mpiSize];
[1614]245  for (int rank = 0; rank < mpiSize; rank++)
246  {
247    if (nbSendElement[rank] > 0)
248    {
[1639]249      MPI_Issend(sendElement[rank], nbSendElement[rank], MPI_INT, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]250      nbSendRequest++;
251    }
[688]252
[1614]253    if (nbRecvElement[rank] > 0)
254    {
255      recvElement[rank] = new int[nbRecvElement[rank]];
[1639]256      MPI_Irecv(recvElement[rank], nbRecvElement[rank], MPI_INT, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]257      nbRecvRequest++;
258    }
259  }
[2506]260  MPI_Status *status = new MPI_Status[6*mpiSize];
[1614]261 
[1639]262  MPI_Waitall(nbSendRequest, sendRequest, status);
[2506]263  MPI_Waitall(nbRecvRequest, recvRequest, status);
[688]264
[2506]265  nbSendRequest = 0;
266  nbRecvRequest = 0;
267
268  for (int rank = 0; rank < mpiSize; rank++)
269  {
270    if (nbRecvElement[rank] > 0)
271    {
272      nbRecvVertex[rank]=0 ;
273      for (int j = 0; j < nbRecvElement[rank]; j++) nbRecvVertex[rank]+=sstree.localElements[recvElement[rank][j]].n+1;
274      MPI_Issend(&nbRecvVertex[rank], 1, MPI_INT, rank, 0, communicator, &sendRequest[nbSendRequest]);
275      nbSendRequest++;
276    }
277 
278    if (nbSendElement[rank] > 0)
279    {
280      MPI_Irecv(&nbSendVertex[rank], 1, MPI_INT, rank, 0, communicator, &recvRequest[nbRecvRequest]);
281      nbRecvRequest++;
282    }
283  }
284 
285  MPI_Waitall(nbSendRequest, sendRequest, status);
286  MPI_Waitall(nbRecvRequest, recvRequest, status);
287
288
[1614]289  /* for all indices that have been received from requesting ranks: pack values and gradients, then send */
290  nbSendRequest = 0;
291  nbRecvRequest = 0;
292  for (int rank = 0; rank < mpiSize; rank++)
293  {
294    if (nbRecvElement[rank] > 0)
295    {
[2506]296      sendValue[rank]   = new double[nbRecvElement[rank]];
297      sendArea[rank]   = new double[nbRecvElement[rank]];
298      sendGivenArea[rank] = new double[nbRecvElement[rank]];
299      sendVertexOffset[rank] = new int[nbRecvElement[rank]];
300
301      if (order == 2)
302      {
303        sendNeighIds[rank] = new GloId[nbRecvVertex[rank]];
304        sendGrad[rank]    = new Coord[nbRecvVertex[rank]];
305      }
306      else sendNeighIds[rank] = new GloId[nbRecvElement[rank]];
307
[1614]308      int jj = 0; // jj == j if no weight writing
[2506]309      sendVertexOffset[rank][0]=0 ;
[1614]310      for (int j = 0; j < nbRecvElement[rank]; j++)
311      {
312        sendValue[rank][j] = sstree.localElements[recvElement[rank][j]].val;
313        sendArea[rank][j] = sstree.localElements[recvElement[rank][j]].area;
314        sendGivenArea[rank][j] = sstree.localElements[recvElement[rank][j]].given_area;
[2506]315       
316        if (j==0) 
317        {
318          if (order==2) sendVertexOffset[rank][j]=sstree.localElements[recvElement[rank][j]].n+1 ;
319          else sendVertexOffset[rank][j]=1 ;
320        }
321        else 
322        {
323          if (order == 2) sendVertexOffset[rank][j] = sendVertexOffset[rank][j-1]+sstree.localElements[recvElement[rank][j]].n+1 ;
324          else sendVertexOffset[rank][j] = sendVertexOffset[rank][j-1]+1 ;
325        }
326
[1614]327        if (order == 2)
328        {
329          sendGrad[rank][jj] = sstree.localElements[recvElement[rank][j]].grad;
[844]330//          cout<<"grad  "<<jj<<"  "<<recvElement[rank][j]<<"  "<<sendGrad[rank][jj]<<" "<<sstree.localElements[recvElement[rank][j]].grad<<endl ;
[1614]331          sendNeighIds[rank][jj] = sstree.localElements[recvElement[rank][j]].src_id;
332          jj++;
[2506]333          for (int i = 0; i <  sstree.localElements[recvElement[rank][j]].n ; i++)
[1614]334          {
335            sendGrad[rank][jj] = sstree.localElements[recvElement[rank][j]].gradNeigh[i];
[844]336//            cout<<"grad  "<<jj<<"  "<<sendGrad[rank][jj]<<" "<<sstree.localElements[recvElement[rank][j]].grad<<endl ;
337            sendNeighIds[rank][jj] = sstree.localElements[recvElement[rank][j]].neighId[i];
[1614]338            jj++;
339          }
340        }
341        else
342          sendNeighIds[rank][j] = sstree.localElements[recvElement[rank][j]].src_id;
343      }
[1639]344      MPI_Issend(sendValue[rank],  nbRecvElement[rank], MPI_DOUBLE, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]345      nbSendRequest++;
[1639]346      MPI_Issend(sendArea[rank],  nbRecvElement[rank], MPI_DOUBLE, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]347      nbSendRequest++;
[1639]348      MPI_Issend(sendGivenArea[rank],  nbRecvElement[rank], MPI_DOUBLE, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]349      nbSendRequest++;
[2506]350      MPI_Issend(sendVertexOffset[rank],  nbRecvElement[rank], MPI_INT, rank, 0, communicator, &sendRequest[nbSendRequest]);
351      nbSendRequest++;
352
[1614]353      if (order == 2)
354      {
[2506]355        MPI_Issend(sendGrad[rank], 3*nbRecvVertex[rank], MPI_DOUBLE, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]356        nbSendRequest++;
[2506]357        MPI_Issend(sendNeighIds[rank], 4*nbRecvVertex[rank], MPI_INT, rank, 0, communicator, &sendRequest[nbSendRequest]);
[688]358//ym  --> attention taille GloId
[1614]359        nbSendRequest++;
360      }
361      else
362      {
[1639]363        MPI_Issend(sendNeighIds[rank], 4*nbRecvElement[rank], MPI_INT, rank, 0, communicator, &sendRequest[nbSendRequest]);
[688]364//ym  --> attention taille GloId
[1614]365        nbSendRequest++;
366      }
367    }
368    if (nbSendElement[rank] > 0)
369    {
[2506]370      recvValue[rank]   = new double[nbSendElement[rank]];
371      recvArea[rank]    = new double[nbSendElement[rank]];
372      recvGivenArea[rank] = new double[nbSendElement[rank]];
373      recvVertexOffset[rank] = new int[nbSendElement[rank]];
374
375      if (order == 2)
376      {
377        recvNeighIds[rank] = new GloId[nbSendVertex[rank]];
378        recvGrad[rank]     = new Coord[nbSendVertex[rank]];
379      }
380      else recvNeighIds[rank] = new GloId[nbSendElement[rank]];
381
382
[1639]383      MPI_Irecv(recvValue[rank],  nbSendElement[rank], MPI_DOUBLE, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]384      nbRecvRequest++;
[1639]385      MPI_Irecv(recvArea[rank],  nbSendElement[rank], MPI_DOUBLE, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]386      nbRecvRequest++;
[1639]387      MPI_Irecv(recvGivenArea[rank],  nbSendElement[rank], MPI_DOUBLE, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]388      nbRecvRequest++;
[2506]389      MPI_Irecv(recvVertexOffset[rank],  nbSendElement[rank], MPI_INT, rank, 0, communicator, &recvRequest[nbRecvRequest]);
390      nbRecvRequest++;
391
[1614]392      if (order == 2)
393      {
[2506]394        MPI_Irecv(recvGrad[rank], 3*nbSendVertex[rank], MPI_DOUBLE, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]395        nbRecvRequest++;
[2506]396        MPI_Irecv(recvNeighIds[rank], 4*nbSendVertex[rank], MPI_INT, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[688]397//ym  --> attention taille GloId
[1614]398        nbRecvRequest++;
399      }
400      else
401      {
[1639]402        MPI_Irecv(recvNeighIds[rank], 4*nbSendElement[rank], MPI_INT, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[688]403//ym  --> attention taille GloId
[1614]404        nbRecvRequest++;
405      }
406    }
407  }
[1158]408       
[2506]409  MPI_Waitall(nbSendRequest, sendRequest, status);
[1639]410  MPI_Waitall(nbRecvRequest, recvRequest, status);
[1614]411 
[688]412
[1614]413  /* now that all values and gradients are available use them to computed interpolated values on target
414     and also to compute weights */
415  int i = 0;
416  for (int j = 0; j < nbElements; j++)
417  {
418    Elt& e = elements[j];
[688]419
[1614]420    /* since for the 2nd order case source grid elements can contribute to a destination grid element over several "paths"
421       (step1: gradient is computed using neighbours on same grid, step2: intersection uses several elements on other grid)
422       accumulate them so that there is only one final weight between two elements */
423    map<GloId,double> wgt_map;
[688]424
[1614]425    /* for destination element `e` loop over all intersetions/the corresponding source elements */
426    for (list<Polyg *>::iterator it = e.is.begin(); it != e.is.end(); it++)
427    {
428      /* it is the intersection element, so it->x and it->area are barycentre and area of intersection element (super mesh)
429      but it->id is id of the source element that it intersects */
430      int n1 = (*it)->id.ind;
431      int rank = (*it)->id.rank;
432      double fk = recvValue[rank][n1];
433      double srcArea = recvArea[rank][n1];
434      double srcGivenArea = recvGivenArea[rank][n1];
435      double w = (*it)->area;
[1158]436      if (quantity) w/=srcArea ;
[1614]437      else w=w*srcGivenArea/srcArea*e.area/e.given_area ;
[688]438
[1614]439      /* first order: src value times weight (weight = supermesh area), later divide by target area */
[2506]440//      int kk = (order == 2) ? n1 * (NMAX + 1) : n1;
441      int offset ;
442      int nvertex ;
443      if (n1==0) 
444      {
445        offset=0 ;
446        nvertex=recvVertexOffset[rank][0] ;
447      }
448      else 
449      {
450        offset = recvVertexOffset[rank][n1-1];
451        nvertex = recvVertexOffset[rank][n1]-recvVertexOffset[rank][n1-1];
452      }
453
454      GloId neighID = recvNeighIds[rank][offset];
[1614]455      wgt_map[neighID] += w;
[688]456
[1614]457      if (order == 2)
458      {
[2506]459        for (int k = 0; k < nvertex; k++)
[1614]460        {
[2506]461          int kk = offset + k;
[1614]462          GloId neighID = recvNeighIds[rank][kk];
463          if (neighID.ind != -1)  wgt_map[neighID] += w * scalarprod(recvGrad[rank][kk], (*it)->x);
464        }
[688]465
[1614]466      }
467    }
[844]468
469    double renorm=0;
470    if (renormalize) 
[1614]471    {
472      if (quantity) for (map<GloId,double>::iterator it = wgt_map.begin(); it != wgt_map.end(); it++) renorm+=it->second ;
473      else for (map<GloId,double>::iterator it = wgt_map.begin(); it != wgt_map.end(); it++) renorm+=it->second / e.area;
474    }
[844]475    else renorm=1. ;
476
477    for (map<GloId,double>::iterator it = wgt_map.begin(); it != wgt_map.end(); it++)
[1614]478    {
[2506]479      if (quantity)  this->remapMatrix.push_back((it->second ) / renorm);
480      else this->remapMatrix.push_back((it->second / e.area) / renorm);
481      this->srcAddress.push_back(it->first.ind);
482      this->srcRank.push_back(it->first.rank);
483      this->dstAddress.push_back(j);
484      this->sourceWeightId.push_back(it->first.globalId) ;
485      this->targetWeightId.push_back(targetGlobalId[j]) ;
[1614]486      i++;
487    }
488  }
[688]489
[1614]490  /* free all memory allocated in this function */
491  for (int rank = 0; rank < mpiSize; rank++)
492  {
493    if (nbSendElement[rank] > 0)
494    {
495      delete[] sendElement[rank];
496      delete[] recvValue[rank];
497      delete[] recvArea[rank];
498      delete[] recvGivenArea[rank];
[2506]499      delete[] recvVertexOffset[rank];
[1614]500      if (order == 2)
501      {
502        delete[] recvGrad[rank];
503      }
504      delete[] recvNeighIds[rank];
505    }
506    if (nbRecvElement[rank] > 0)
507    {
508      delete[] recvElement[rank];
509      delete[] sendValue[rank];
510      delete[] sendArea[rank];
511      delete[] sendGivenArea[rank];
[2506]512      delete[] sendVertexOffset[rank];
[1614]513      if (order == 2)
514        delete[] sendGrad[rank];
515      delete[] sendNeighIds[rank];
516    }
517  }
518  delete[] status;
519  delete[] sendRequest;
520  delete[] recvRequest;
521  delete[] elementList;
522  delete[] nbSendElement;
523  delete[] nbRecvElement;
[2506]524  delete[] nbSendVertex;
525  delete[] nbRecvVertex;
[1614]526  delete[] sendElement;
527  delete[] recvElement;
528  delete[] sendValue;
529  delete[] recvValue;
530  delete[] sendGrad;
531  delete[] recvGrad;
532  delete[] sendNeighIds;
533  delete[] recvNeighIds;
534  return i;
[688]535}
536
537void Mapper::computeGrads()
538{
[1614]539  /* array of pointers to collect local elements and elements received from other cpu */
540  vector<Elt*> globalElements(sstree.nbLocalElements + nbNeighbourElements);
541  int index = 0;
542  for (int i = 0; i < sstree.nbLocalElements; i++, index++)
543    globalElements[index] = &(sstree.localElements[i]);
544  for (int i = 0; i < nbNeighbourElements; i++, index++)
545    globalElements[index] = &neighbourElements[i];
[688]546
[1614]547  update_baryc(sstree.localElements, sstree.nbLocalElements);
548  computeGradients(&globalElements[0], sstree.nbLocalElements);
[688]549}
550
551/** for each element of the source grid, finds all the neighbouring elements that share an edge
552    (filling array neighbourElements). This is used later to compute gradients */
553void Mapper::buildMeshTopology()
554{
[1614]555  int mpiSize, mpiRank;
[1639]556  MPI_Comm_size(communicator, &mpiSize);
557  MPI_Comm_rank(communicator, &mpiRank);
[688]558
[1614]559  vector<Node> *routingList = new vector<Node>[mpiSize];
560  vector<vector<int> > routes(sstree.localTree.leafs.size());
[688]561
[1614]562  sstree.routeIntersections(routes, sstree.localTree.leafs);
[688]563
[1614]564  for (int i = 0; i < routes.size(); ++i)
565    for (int k = 0; k < routes[i].size(); ++k)
566      routingList[routes[i][k]].push_back(sstree.localTree.leafs[i]);
567  routingList[mpiRank].clear();
[688]568
569
[1614]570  CMPIRouting mpiRoute(communicator);
571  mpiRoute.init(routes);
572  int nRecv = mpiRoute.getTotalSourceElement();
[923]573// cout << mpiRank << " NRECV " << nRecv << "(" << routes.size() << ")"<< endl;
[688]574
[1614]575  int *nbSendNode = new int[mpiSize];
576  int *nbRecvNode = new int[mpiSize];
577  int *sendMessageSize = new int[mpiSize];
578  int *recvMessageSize = new int[mpiSize];
[688]579
[1614]580  for (int rank = 0; rank < mpiSize; rank++)
581  {
582    nbSendNode[rank] = routingList[rank].size();
583    sendMessageSize[rank] = 0;
584    for (size_t j = 0; j < routingList[rank].size(); j++)
585    {
586      Elt *elt = (Elt *) (routingList[rank][j].data);
587      sendMessageSize[rank] += packedPolygonSize(*elt);
588    }
589  }
[688]590
[1639]591  MPI_Alltoall(nbSendNode, 1, MPI_INT, nbRecvNode, 1, MPI_INT, communicator);
592  MPI_Alltoall(sendMessageSize, 1, MPI_INT, recvMessageSize, 1, MPI_INT, communicator);
[688]593
[1614]594  char **sendBuffer = new char*[mpiSize];
595  char **recvBuffer = new char*[mpiSize];
596  int *pos = new int[mpiSize];
[688]597
[1614]598  for (int rank = 0; rank < mpiSize; rank++)
599  {
600    if (nbSendNode[rank] > 0) sendBuffer[rank] = new char[sendMessageSize[rank]];
601    if (nbRecvNode[rank] > 0) recvBuffer[rank] = new char[recvMessageSize[rank]];
602  }
[688]603
[1614]604  for (int rank = 0; rank < mpiSize; rank++)
605  {
606    pos[rank] = 0;
607    for (size_t j = 0; j < routingList[rank].size(); j++)
608    {
609      Elt *elt = (Elt *) (routingList[rank][j].data);
610      packPolygon(*elt, sendBuffer[rank], pos[rank]);
611    }
612  }
613  delete [] routingList;
[688]614
615
[1614]616  int nbSendRequest = 0;
617  int nbRecvRequest = 0;
[1639]618  MPI_Request *sendRequest = new MPI_Request[mpiSize];
619  MPI_Request *recvRequest = new MPI_Request[mpiSize];
620  MPI_Status  *status      = new MPI_Status[mpiSize];
[688]621
[1614]622  for (int rank = 0; rank < mpiSize; rank++)
623  {
624    if (nbSendNode[rank] > 0)
625    {
[1639]626      MPI_Issend(sendBuffer[rank], sendMessageSize[rank], MPI_CHAR, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]627      nbSendRequest++;
628    }
629    if (nbRecvNode[rank] > 0)
630    {
[1639]631      MPI_Irecv(recvBuffer[rank], recvMessageSize[rank], MPI_CHAR, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]632      nbRecvRequest++;
633    }
634  }
[688]635
[1639]636  MPI_Waitall(nbRecvRequest, recvRequest, status);
637  MPI_Waitall(nbSendRequest, sendRequest, status);
[688]638
[1614]639  for (int rank = 0; rank < mpiSize; rank++)
640    if (nbSendNode[rank] > 0) delete [] sendBuffer[rank];
641  delete [] sendBuffer;
[688]642
[1614]643  char **sendBuffer2 = new char*[mpiSize];
644  char **recvBuffer2 = new char*[mpiSize];
[688]645
[1614]646  for (int rank = 0; rank < mpiSize; rank++)
647  {
648    nbSendNode[rank] = 0;
649    sendMessageSize[rank] = 0;
[688]650
[1614]651    if (nbRecvNode[rank] > 0)
652    {
653      set<NodePtr> neighbourList;
654      pos[rank] = 0;
655      for (int j = 0; j < nbRecvNode[rank]; j++)
656      {
657        Elt elt;
658        unpackPolygon(elt, recvBuffer[rank], pos[rank]);
659        Node node(elt.x, cptRadius(elt), &elt);
660        findNeighbour(sstree.localTree.root, &node, neighbourList);
661      }
662      nbSendNode[rank] = neighbourList.size();
663      for (set<NodePtr>::iterator it = neighbourList.begin(); it != neighbourList.end(); it++)
664      {
665        Elt *elt = (Elt *) ((*it)->data);
666        sendMessageSize[rank] += packedPolygonSize(*elt);
667      }
[688]668
[1614]669      sendBuffer2[rank] = new char[sendMessageSize[rank]];
670      pos[rank] = 0;
[688]671
[1614]672      for (set<NodePtr>::iterator it = neighbourList.begin(); it != neighbourList.end(); it++)
673      {
674        Elt *elt = (Elt *) ((*it)->data);
675        packPolygon(*elt, sendBuffer2[rank], pos[rank]);
676      }
677    }
678  }
679  for (int rank = 0; rank < mpiSize; rank++)
680    if (nbRecvNode[rank] > 0) delete [] recvBuffer[rank];
681  delete [] recvBuffer;
[688]682
683
[1639]684  MPI_Barrier(communicator);
685  MPI_Alltoall(nbSendNode, 1, MPI_INT, nbRecvNode, 1, MPI_INT, communicator);
686  MPI_Alltoall(sendMessageSize, 1, MPI_INT, recvMessageSize, 1, MPI_INT, communicator);
[688]687
[1614]688  for (int rank = 0; rank < mpiSize; rank++)
689    if (nbRecvNode[rank] > 0) recvBuffer2[rank] = new char[recvMessageSize[rank]];
[688]690
[1614]691  nbSendRequest = 0;
692  nbRecvRequest = 0;
[688]693
[1614]694  for (int rank = 0; rank < mpiSize; rank++)
695  {
696    if (nbSendNode[rank] > 0)
697    {
[1639]698      MPI_Issend(sendBuffer2[rank], sendMessageSize[rank], MPI_CHAR, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]699      nbSendRequest++;
700    }
701    if (nbRecvNode[rank] > 0)
702    {
[1639]703      MPI_Irecv(recvBuffer2[rank], recvMessageSize[rank], MPI_CHAR, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]704      nbRecvRequest++;
705    }
706  }
[688]707
[1639]708  MPI_Waitall(nbRecvRequest, recvRequest, status);
709  MPI_Waitall(nbSendRequest, sendRequest, status);
[688]710
[1614]711  int nbNeighbourNodes = 0;
712  for (int rank = 0; rank < mpiSize; rank++)
713    nbNeighbourNodes += nbRecvNode[rank];
[688]714
[1614]715  neighbourElements = new Elt[nbNeighbourNodes];
716  nbNeighbourElements = nbNeighbourNodes;
[688]717
[1614]718  int index = 0;
719  for (int rank = 0; rank < mpiSize; rank++)
720  {
721    pos[rank] = 0;
722    for (int j = 0; j < nbRecvNode[rank]; j++)
723    {
724      unpackPolygon(neighbourElements[index], recvBuffer2[rank], pos[rank]);
725      neighbourElements[index].id.ind = sstree.localTree.leafs.size() + index;
726      index++;
727    }
728  }
729  for (int rank = 0; rank < mpiSize; rank++)
730  {
731    if (nbRecvNode[rank] > 0) delete [] recvBuffer2[rank];
732    if (nbSendNode[rank] > 0) delete [] sendBuffer2[rank];
733  }
734  delete [] recvBuffer2;
735  delete [] sendBuffer2;
736  delete [] sendMessageSize;
737  delete [] recvMessageSize;
738  delete [] nbSendNode;
739  delete [] nbRecvNode;
740  delete [] sendRequest;
741  delete [] recvRequest;
742  delete [] status;
743  delete [] pos;
[688]744
[1614]745  /* re-compute on received elements to avoid having to send this information */
746  neighbourNodes.resize(nbNeighbourNodes);
747  setCirclesAndLinks(neighbourElements, neighbourNodes);
748  cptAllEltsGeom(neighbourElements, nbNeighbourNodes, srcGrid.pole);
[688]749
[1614]750  /* the local SS tree must include nodes from other cpus if they are potential
[688]751           intersector of a local node */
[1614]752  sstree.localTree.insertNodes(neighbourNodes);
[688]753
[1614]754  /* for every local element,
[688]755           use the SS-tree to find all elements (including neighbourElements)
756           who are potential neighbours because their circles intersect,
[1614]757     then check all canditates for common edges to build up connectivity information
758  */
759  for (int j = 0; j < sstree.localTree.leafs.size(); j++)
760  {
761    Node& node = sstree.localTree.leafs[j];
[688]762
[1614]763    /* find all leafs whoes circles that intersect node's circle and save into node->intersectors */
764    node.search(sstree.localTree.root);
[688]765
[1614]766    Elt *elt = (Elt *)(node.data);
[688]767
[1614]768    for (int i = 0; i < elt->n; i++) elt->neighbour[i] = NOT_FOUND;
[688]769
[1614]770    /* for element `elt` loop through all nodes in the SS-tree
[688]771                   whoes circles intersect with the circle around `elt` (the SS intersectors)
772                   and check if they are neighbours in the sense that the two elements share an edge.
773                   If they do, save this information for elt */
[1614]774    for (list<NodePtr>::iterator it = (node.intersectors).begin(); it != (node.intersectors).end(); ++it)
775    {
776      Elt *elt2 = (Elt *)((*it)->data);
777      set_neighbour(*elt, *elt2);
778    }
[688]779
[844]780/*
[1614]781    for (int i = 0; i < elt->n; i++)
782    {
783      if (elt->neighbour[i] == NOT_FOUND)
784        error_exit("neighbour not found");
785    }
[844]786*/
[1614]787  }
[688]788}
789
790/** @param elements are the target grid elements */
791void Mapper::computeIntersection(Elt *elements, int nbElements)
792{
[1614]793  int mpiSize, mpiRank;
[1639]794  MPI_Comm_size(communicator, &mpiSize);
795  MPI_Comm_rank(communicator, &mpiRank);
[688]796
[1639]797  MPI_Barrier(communicator);
[688]798
[1614]799  vector<Node> *routingList = new vector<Node>[mpiSize];
[688]800
[1614]801  vector<Node> routeNodes;  routeNodes.reserve(nbElements);
802  for (int j = 0; j < nbElements; j++)
803  {
804    elements[j].id.ind = j;
805    elements[j].id.rank = mpiRank;
806    routeNodes.push_back(Node(elements[j].x, cptRadius(elements[j]), &elements[j]));
807  }
[688]808
[1614]809  vector<vector<int> > routes(routeNodes.size());
810  sstree.routeIntersections(routes, routeNodes);
811  for (int i = 0; i < routes.size(); ++i)
812    for (int k = 0; k < routes[i].size(); ++k)
813      routingList[routes[i][k]].push_back(routeNodes[i]);
[688]814
[1614]815  if (verbose >= 2)
816  {
817    cout << " --> rank  " << mpiRank << " nbElements " << nbElements << " : ";
818    for (int rank = 0; rank < mpiSize; rank++)
819      cout << routingList[rank].size() << "   ";
820    cout << endl;
821  }
[1639]822  MPI_Barrier(communicator);
[688]823
[1614]824  int *nbSendNode = new int[mpiSize];
825  int *nbRecvNode = new int[mpiSize];
826  int *sentMessageSize = new int[mpiSize];
827  int *recvMessageSize = new int[mpiSize];
[688]828
[1614]829  for (int rank = 0; rank < mpiSize; rank++)
830  {
831    nbSendNode[rank] = routingList[rank].size();
832    sentMessageSize[rank] = 0;
833    for (size_t j = 0; j < routingList[rank].size(); j++)
834    {
835      Elt *elt = (Elt *) (routingList[rank][j].data);
836      sentMessageSize[rank] += packedPolygonSize(*elt);
837    }
838  }
[688]839
[1639]840  MPI_Alltoall(nbSendNode, 1, MPI_INT, nbRecvNode, 1, MPI_INT, communicator);
841  MPI_Alltoall(sentMessageSize, 1, MPI_INT, recvMessageSize, 1, MPI_INT, communicator);
[688]842
[1614]843  int total = 0;
[688]844
[1614]845  for (int rank = 0; rank < mpiSize; rank++)
846  {
847    total = total + nbRecvNode[rank];
848  }
[688]849
[1614]850  if (verbose >= 2) cout << "---> rank " << mpiRank << " : compute intersection : total received nodes  " << total << endl;
851  char **sendBuffer = new char*[mpiSize];
852  char **recvBuffer = new char*[mpiSize];
853  int *pos = new int[mpiSize];
[688]854
[1614]855  for (int rank = 0; rank < mpiSize; rank++)
856  {
857    if (nbSendNode[rank] > 0) sendBuffer[rank] = new char[sentMessageSize[rank]];
858    if (nbRecvNode[rank] > 0) recvBuffer[rank] = new char[recvMessageSize[rank]];
859  }
[688]860
[1614]861  for (int rank = 0; rank < mpiSize; rank++)
862  {
863    pos[rank] = 0;
864    for (size_t j = 0; j < routingList[rank].size(); j++)
865    {
866      Elt* elt = (Elt *) (routingList[rank][j].data);
867      packPolygon(*elt, sendBuffer[rank], pos[rank]);
868    }
869  }
870  delete [] routingList;
[688]871
[1614]872  int nbSendRequest = 0;
873  int nbRecvRequest = 0;
[1639]874  MPI_Request *sendRequest = new MPI_Request[mpiSize];
875  MPI_Request *recvRequest = new MPI_Request[mpiSize];
876  MPI_Status   *status = new MPI_Status[mpiSize];
[688]877
[1614]878  for (int rank = 0; rank < mpiSize; rank++)
879  {
880    if (nbSendNode[rank] > 0)
881    {
[1639]882      MPI_Issend(sendBuffer[rank], sentMessageSize[rank], MPI_CHAR, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]883      nbSendRequest++;
884    }
885    if (nbRecvNode[rank] > 0)
886    {
[1639]887      MPI_Irecv(recvBuffer[rank], recvMessageSize[rank], MPI_CHAR, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]888      nbRecvRequest++;
889    }
890  }
[688]891
[1639]892  MPI_Waitall(nbRecvRequest, recvRequest, status);
893  MPI_Waitall(nbSendRequest, sendRequest, status);
[1614]894  char **sendBuffer2 = new char*[mpiSize];
895  char **recvBuffer2 = new char*[mpiSize];
[688]896
[1614]897  double tic = cputime();
898  for (int rank = 0; rank < mpiSize; rank++)
899  {
900    sentMessageSize[rank] = 0;
[688]901
[1614]902    if (nbRecvNode[rank] > 0)
903    {
904      Elt *recvElt = new Elt[nbRecvNode[rank]];
905      pos[rank] = 0;
906      for (int j = 0; j < nbRecvNode[rank]; j++)
907      {
908        unpackPolygon(recvElt[j], recvBuffer[rank], pos[rank]);
909        cptEltGeom(recvElt[j], tgtGrid.pole);
910        Node recvNode(recvElt[j].x, cptRadius(recvElt[j]), &recvElt[j]);
911        recvNode.search(sstree.localTree.root);
912        /* for a node holding an element of the target, loop throught candidates for intersecting source */
913        for (list<NodePtr>::iterator it = (recvNode.intersectors).begin(); it != (recvNode.intersectors).end(); ++it)
914        {
915          Elt *elt2 = (Elt *) ((*it)->data);
916          /* recvElt is target, elt2 is source */
917//          intersect(&recvElt[j], elt2);
918          intersect_ym(&recvElt[j], elt2);
919        }
[688]920
[1614]921        if (recvElt[j].is.size() > 0) sentMessageSize[rank] += packIntersectionSize(recvElt[j]);
[688]922
[1614]923        // here recvNode goes out of scope
924      }
[688]925
[1614]926      if (sentMessageSize[rank] > 0)
927      {
928        sentMessageSize[rank] += sizeof(int);
929        sendBuffer2[rank] = new char[sentMessageSize[rank]];
930        *((int *) sendBuffer2[rank]) = 0;
931        pos[rank] = sizeof(int);
932        for (int j = 0; j < nbRecvNode[rank]; j++)
933        {
934          packIntersection(recvElt[j], sendBuffer2[rank], pos[rank]);
935          //FIXME should be deleted: recvElt[j].delete_intersections(); // intersection areas have been packed to buffer and won't be used any more
936        }
937      }
938      delete [] recvElt;
[688]939
[1614]940    }
941  }
942  delete [] pos;
[688]943
[1614]944  for (int rank = 0; rank < mpiSize; rank++)
945  {
946    if (nbSendNode[rank] > 0) delete [] sendBuffer[rank];
947    if (nbRecvNode[rank] > 0) delete [] recvBuffer[rank];
948    nbSendNode[rank] = 0;
949  }
[688]950
[1614]951  if (verbose >= 2) cout << "Rank " << mpiRank << "  Compute (internal) intersection " << cputime() - tic << " s" << endl;
[1639]952  MPI_Alltoall(sentMessageSize, 1, MPI_INT, recvMessageSize, 1, MPI_INT, communicator);
[688]953
[1614]954  for (int rank = 0; rank < mpiSize; rank++)
955    if (recvMessageSize[rank] > 0)
956      recvBuffer2[rank] = new char[recvMessageSize[rank]];
[688]957
[1614]958  nbSendRequest = 0;
959  nbRecvRequest = 0;
[688]960
[1614]961  for (int rank = 0; rank < mpiSize; rank++)
962  {
963    if (sentMessageSize[rank] > 0)
964    {
[1639]965      MPI_Issend(sendBuffer2[rank], sentMessageSize[rank], MPI_CHAR, rank, 0, communicator, &sendRequest[nbSendRequest]);
[1614]966      nbSendRequest++;
967    }
968    if (recvMessageSize[rank] > 0)
969    {
[1639]970      MPI_Irecv(recvBuffer2[rank], recvMessageSize[rank], MPI_CHAR, rank, 0, communicator, &recvRequest[nbRecvRequest]);
[1614]971      nbRecvRequest++;
972    }
973  }
[688]974
[1639]975  MPI_Waitall(nbRecvRequest, recvRequest, status);
976  MPI_Waitall(nbSendRequest, sendRequest, status);
[688]977
[1614]978  delete [] sendRequest;
979  delete [] recvRequest;
980  delete [] status;
981  for (int rank = 0; rank < mpiSize; rank++)
982  {
983    if (nbRecvNode[rank] > 0)
984    {
985      if (sentMessageSize[rank] > 0)
986        delete [] sendBuffer2[rank];
987    }
[688]988
[1614]989    if (recvMessageSize[rank] > 0)
990    {
991      unpackIntersection(elements, recvBuffer2[rank]);
992      delete [] recvBuffer2[rank];
993    }
994  }
995  delete [] sendBuffer2;
996  delete [] recvBuffer2;
997  delete [] sendBuffer;
998  delete [] recvBuffer;
[688]999
[1614]1000  delete [] nbSendNode;
1001  delete [] nbRecvNode;
1002  delete [] sentMessageSize;
1003  delete [] recvMessageSize;
[688]1004}
1005
1006Mapper::~Mapper()
1007{
[2506]1008
[688]1009}
1010
1011}
Note: See TracBrowser for help on using the repository browser.