ParallelDomainProblem.cc 46 KB
Newer Older
Thomas Witkowski's avatar
Thomas Witkowski committed
1
2
3
#include <boost/lambda/lambda.hpp>
#include <algorithm>

4
5
6
7
8
9
10
11
12
13
#include "ParallelDomainProblem.h"
#include "ProblemScal.h"
#include "ProblemInstat.h"
#include "ParMetisPartitioner.h"
#include "Mesh.h"
#include "Traverse.h"
#include "ElInfo.h"
#include "Element.h"
#include "MacroElement.h"
#include "PartitionElementData.h"
14
15
#include "DOFMatrix.h"
#include "DOFVector.h"
16
#include "VtkWriter.h"
17
#include "ElementDofIterator.h"
18
19

#include "petscksp.h"
20
21

namespace AMDiS {
Thomas Witkowski's avatar
Thomas Witkowski committed
22
23
  
  using namespace boost::lambda;
24

25
26
  PetscErrorCode myKSPMonitor(KSP ksp, PetscInt iter, PetscReal rnorm, void *)
  {
27
28
    if (iter % 1 == 0 && MPI::COMM_WORLD.Get_rank() == 0)
      std::cout << "  Iteration " << iter << ": " << rnorm << std::endl;
29
30
31
32
33
34
35
36
37

    return 0;
  }

  ParallelDomainBase::ParallelDomainBase(const std::string& name,
					 ProblemIterationInterface *iIF,
					 ProblemTimeInterface *tIF,
					 FiniteElemSpace *fe,
					 RefinementManager *refineManager)
38
39
    : iterationIF(iIF),
      timeIF(tIF),
40
41
      feSpace(fe),
      mesh(fe->getMesh()),
42
      refinementManager(refineManager),
43
      initialPartitionMesh(true),
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
44
45
      nRankDOFs(0),
      rstart(0)
46
  {
Thomas Witkowski's avatar
Thomas Witkowski committed
47
48
49
50
51
52
53
    FUNCNAME("ParallelDomainBase::ParalleDomainBase()");

    TEST_EXIT(mesh->getNumberOfDOFAdmin() == 1)
      ("Only meshes with one DOFAdmin are supported!\n");
    TEST_EXIT(mesh->getDOFAdmin(0).getNumberOfPreDOFs(0) == 0)
      ("Wrong pre dof number for DOFAdmin!\n");

54
55
56
57
58
59
    mpiRank = MPI::COMM_WORLD.Get_rank();
    mpiSize = MPI::COMM_WORLD.Get_size();
    mpiComm = MPI::COMM_WORLD;
    partitioner = new ParMetisPartitioner(mesh, &mpiComm);
  }

60
  void ParallelDomainBase::initParallelization(AdaptInfo *adaptInfo)
61
62
63
64
  {
    if (mpiSize <= 1)
      return;

65
66
67
68
69
    // Test, if the mesh is the macro mesh only! Paritioning of the mesh is supported
    // only for macro meshes, so it will not work yet if the mesh is already refined
    // in some way.
    testForMacroMesh();

70
71
72
73
74
75
76
    // create an initial partitioning of the mesh
    partitioner->createPartitionData();
    // set the element weights, which are 1 at the very first begin
    setElemWeights(adaptInfo);
    // and now partition the mesh
    partitionMesh(adaptInfo);   

Thomas Witkowski's avatar
Thomas Witkowski committed
77
78
79
80
#if (DEBUG != 0)
    ElementIdxToDofs elMap;
    DbgCreateElementMap(elMap);
#endif
81

82
    // === Create new global and local DOF numbering. ===
83

84
85
86
    // Set of all DOFs of the rank.
    std::vector<const DegreeOfFreedom*> rankDOFs;
    // Number of DOFs in ranks partition that are owned by the rank.
Thomas Witkowski's avatar
Thomas Witkowski committed
87
    nRankDOFs = 0;
88
    // Number of all DOFs in the macro mesh.
89
    int nOverallDOFs = 0;
90
91

    createLocalGlobalNumbering(rankDOFs, boundaryDOFs, nRankDOFs, nOverallDOFs);
92

Thomas Witkowski's avatar
Thomas Witkowski committed
93
94
    // === Create interior boundary information ===

95
    createInteriorBoundaryInfo(rankDOFs, boundaryDOFs);
Thomas Witkowski's avatar
Thomas Witkowski committed
96

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
97
98
99
100
    // === Remove all macro elements that are not part of the rank partition. ===

    removeMacroElements();

Thomas Witkowski's avatar
Thomas Witkowski committed
101
#if (DEBUG != 0)
Thomas Witkowski's avatar
Thomas Witkowski committed
102
    DbgTestElementMap(elMap);
Thomas Witkowski's avatar
Thomas Witkowski committed
103
104
    DbgTestInteriorBoundary();
#endif
Thomas Witkowski's avatar
Thomas Witkowski committed
105

106

107
    // === Reset all DOFAdmins of the mesh. ===
108

109
    updateDofAdmins();
110

Thomas Witkowski's avatar
Thomas Witkowski committed
111

112
    // === Global refinements. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
113

Thomas Witkowski's avatar
Thomas Witkowski committed
114
115
116
    int globalRefinement = 0;
    GET_PARAMETER(0, "testgr", "%d", &globalRefinement);

Thomas Witkowski's avatar
Thomas Witkowski committed
117
118
    if (globalRefinement > 0) {
      refinementManager->globalRefine(mesh, globalRefinement);
119

120
121
122
123
124
#if (DEBUG != 0)
      elMap.clear();
      DbgCreateElementMap(elMap);
#endif

Thomas Witkowski's avatar
Thomas Witkowski committed
125
      updateLocalGlobalNumbering(nRankDOFs, nOverallDOFs);
126
127
128
129
130
131

      updateDofAdmins();

#if (DEBUG != 0)
      DbgTestElementMap(elMap);
#endif
Thomas Witkowski's avatar
Thomas Witkowski committed
132
133
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
134
#if (DEBUG != 0)
Thomas Witkowski's avatar
Thomas Witkowski committed
135
    DbgTestCommonDofs();
Thomas Witkowski's avatar
Thomas Witkowski committed
136
#endif
137

138

139
    // === Create petsc matrix. ===
140

141
142
    int ierr;
    ierr = MatCreate(PETSC_COMM_WORLD, &petscMatrix);
143
    ierr = MatSetSizes(petscMatrix, nRankDOFs, nRankDOFs, nOverallDOFs, nOverallDOFs);
144
145
146
    ierr = MatSetType(petscMatrix, MATAIJ);

    ierr = VecCreate(PETSC_COMM_WORLD, &petscRhsVec);
147
    ierr = VecSetSizes(petscRhsVec, nRankDOFs, nOverallDOFs);
148
    ierr = VecSetType(petscRhsVec, VECMPI);
149
150

    ierr = VecCreate(PETSC_COMM_WORLD, &petscSolVec);
151
    ierr = VecSetSizes(petscSolVec, nRankDOFs, nOverallDOFs);
152
    ierr = VecSetType(petscSolVec, VECMPI);
153
154
  }

155
156
157
158

  void ParallelDomainBase::exitParallelization(AdaptInfo *adaptInfo)
  {
  }
159

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  
  void ParallelDomainBase::updateDofAdmins()
  {
    int nAdmins = mesh->getNumberOfDOFAdmin();
    for (int i = 0; i < nAdmins; i++) {
      DOFAdmin& admin = const_cast<DOFAdmin&>(mesh->getDOFAdmin(i));
      
      for (int j = 0; j < admin.getSize(); j++)
	admin.setDOFFree(j, true);
      for (int j = 0; j < static_cast<int>(mapLocalGlobalDOFs.size()); j++)
 	admin.setDOFFree(j, false);

      admin.setUsedSize(mapLocalGlobalDOFs.size());
      admin.setUsedCount(mapLocalGlobalDOFs.size());
      admin.setFirstHole(mapLocalGlobalDOFs.size());
    }
  }

178

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  void ParallelDomainBase::testForMacroMesh()
  {
    FUNCNAME("ParallelDomainBase::testForMacroMesh()");

    int nMacroElements = 0;

    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
    while (elInfo) {
      TEST_EXIT(elInfo->getLevel() == 0)
	("Mesh is already refined! This does nor work with parallelization!\n");
      
      nMacroElements++;

      elInfo = stack.traverseNext(elInfo);
    }

    TEST_EXIT(nMacroElements >= mpiSize)
      ("The mesh has less macro elements than number of mpi processes!\n");
  }


  void ParallelDomainBase::fillPetscMatrix(DOFMatrix *mat, 
					   DOFVector<double> *vec)
203
  {
204
205
206
207
208
209
210
211
212
213
214
    using mtl::tag::major; using mtl::tag::nz; using mtl::begin; using mtl::end;
    namespace traits= mtl::traits;
    typedef DOFMatrix::base_matrix_type Matrix;

    traits::row<Matrix>::type row(mat->getBaseMatrix());
    traits::col<Matrix>::type col(mat->getBaseMatrix());
    traits::const_value<Matrix>::type value(mat->getBaseMatrix());

    typedef traits::range_generator<major, Matrix>::type cursor_type;
    typedef traits::range_generator<nz, cursor_type>::type icursor_type;

215
216
217
218
    for (cursor_type cursor = begin<major>(mat->getBaseMatrix()), 
	   cend = end<major>(mat->getBaseMatrix()); cursor != cend; ++cursor)
      for (icursor_type icursor = begin<nz>(cursor), 
	     icend = end<nz>(cursor); icursor != icend; ++icursor)
219
	if (value(*icursor) != 0.0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
220
221
 	  int r = mapLocalGlobalDOFs[row(*icursor)];
 	  int c = mapLocalGlobalDOFs[col(*icursor)];  
222
	  double v = value(*icursor);
223

224
	  MatSetValues(petscMatrix, 1, &r, 1, &c, &v, ADD_VALUES);
225
	}
226

227
228
229
230

    MatAssemblyBegin(petscMatrix, MAT_FINAL_ASSEMBLY);
    MatAssemblyEnd(petscMatrix, MAT_FINAL_ASSEMBLY);

231
    
232
233
    DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
    for (dofIt.reset(); !dofIt.end(); ++dofIt) {
234
      int index = mapLocalGlobalDOFs[dofIt.getDOFIndex()];
235
236
237
      double value = *dofIt;

      VecSetValues(petscRhsVec, 1, &index, &value, ADD_VALUES);
238
    }    
239
240
  }

241

242
  void ParallelDomainBase::solvePetscMatrix(DOFVector<double> *vec)
243
  {
Thomas Witkowski's avatar
Thomas Witkowski committed
244
245
    FUNCNAME("ParallelDomainBase::solvePetscMatrix()");

246
247
248
249
250
251
    KSP ksp;
    PC pc;

    KSPCreate(PETSC_COMM_WORLD, &ksp);
    KSPSetOperators(ksp, petscMatrix, petscMatrix, DIFFERENT_NONZERO_PATTERN);
    KSPGetPC(ksp, &pc);
252
253
    //    PCSetType(pc, PCNONE);
    PCSetType(pc, PCJACOBI);
254
    KSPSetTolerances(ksp, 1.e-7, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
255
256
    KSPSetType(ksp, KSPBCGS);
    //KSPSetType(ksp, KSPCG);
257
    KSPMonitorSet(ksp, myKSPMonitor, PETSC_NULL, 0);
258
259
    KSPSolve(ksp, petscRhsVec, petscSolVec);

Thomas Witkowski's avatar
Thomas Witkowski committed
260
261
262
263
264
265
#if (DEBUG != 0)
    int size = 0;
    VecGetLocalSize(petscSolVec, &size);
    TEST_EXIT(size == nRankDOFs)("Vector and rank DOFs does not fit together!\n");
#endif

266
267
268
    PetscScalar *vecPointer;
    VecGetArray(petscSolVec, &vecPointer);

Thomas Witkowski's avatar
Thomas Witkowski committed
269
    for (int i = 0; i < nRankDOFs; i++)
270
      (*vec)[mapLocalToDofIndex[i]] = vecPointer[i];
271
272
273

    VecRestoreArray(petscSolVec, &vecPointer);

274
275
    std::vector<double*> sendBuffers(sendDofs.size());
    std::vector<double*> recvBuffers(recvDofs.size());
Thomas Witkowski's avatar
Thomas Witkowski committed
276
277
278

    MPI::Request request[sendDofs.size() + recvDofs.size()];
    int requestCounter = 0;
279
280
    
    int i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
281
282
    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); 
283
	 ++sendIt, i++) {
284
285
      int nSendDOFs = sendIt->second.size();
      sendBuffers[i] = new double[nSendDOFs];
286

287
      for (int j = 0; j < nSendDOFs; j++)
Thomas Witkowski's avatar
Thomas Witkowski committed
288
	sendBuffers[i][j] = (*vec)[*((sendIt->second)[j])];
289

Thomas Witkowski's avatar
Thomas Witkowski committed
290
291
      request[requestCounter++] =
	mpiComm.Isend(sendBuffers[i], nSendDOFs, MPI_DOUBLE, sendIt->first, 0);
292
293
294
    }

    i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
295
296
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); 
297
	 ++recvIt, i++) {
298
299
      int nRecvDOFs = recvIt->second.size();
      recvBuffers[i] = new double[nRecvDOFs];
300

Thomas Witkowski's avatar
Thomas Witkowski committed
301
302
      request[requestCounter++] =
	mpiComm.Irecv(recvBuffers[i], nRecvDOFs, MPI_DOUBLE, recvIt->first, 0);
303
304
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
305
306
307

    MPI::Request::Waitall(requestCounter, request);

308
    i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
309
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
310
311
	 recvIt != recvDofs.end();
	 ++recvIt, i++) {
Thomas Witkowski's avatar
Thomas Witkowski committed
312
      for (int j = 0; j < static_cast<int>(recvIt->second.size()); j++)
Thomas Witkowski's avatar
Thomas Witkowski committed
313
	(*vec)[*(recvIt->second)[j]] = recvBuffers[i][j];
314
315
316
317

      delete [] recvBuffers[i];
    }
    
318
    for (int i = 0; i < static_cast<int>(sendBuffers.size()); i++)
319
      delete [] sendBuffers[i];
320
321
  }

322

323
  double ParallelDomainBase::setElemWeights(AdaptInfo *adaptInfo) 
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  {
    double localWeightSum = 0.0;
    int elNum = -1;

    elemWeights.clear();

    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(mesh, -1,
					 Mesh::CALL_EVERY_EL_PREORDER);
    while (elInfo) {
      Element *element = elInfo->getElement();

      // get partition data
      PartitionElementData *partitionData = dynamic_cast<PartitionElementData*>
	(element->getElementData(PARTITION_ED));

      if (partitionData && partitionData->getPartitionStatus() == IN) {
	if (partitionData->getLevel() == 0) {
	  elNum = element->getIndex();
	}
Thomas Witkowski's avatar
Thomas Witkowski committed
344
	TEST_EXIT_DBG(elNum != -1)("invalid element number\n");
345
346
347
348
349
350
351
352
353
354
355
356
	if (element->isLeaf()) {
	  elemWeights[elNum] += 1.0;
	  localWeightSum += 1.0;
	}
      }

      elInfo = stack.traverseNext(elInfo);
    }

    return localWeightSum;
  }

357

358
  void ParallelDomainBase::partitionMesh(AdaptInfo *adaptInfo)
359
360
361
362
363
364
365
366
367
368
369
370
371
  {
    if (initialPartitionMesh) {
      initialPartitionMesh = false;
      partitioner->fillCoarsePartitionVec(&oldPartitionVec);
      partitioner->partition(&elemWeights, INITIAL);
    } else {
      oldPartitionVec = partitionVec;
      partitioner->partition(&elemWeights, ADAPTIVE_REPART, 100.0 /*0.000001*/);
    }    

    partitioner->fillCoarsePartitionVec(&partitionVec);
  }

372

Thomas Witkowski's avatar
Thomas Witkowski committed
373
374
  void ParallelDomainBase::createInteriorBoundaryInfo(DofContainer& rankDOFs,
						      DofToRank& boundaryDOFs)
375
  {
376
    FUNCNAME("ParallelDomainBase::createInteriorBoundaryInfo()");
Thomas Witkowski's avatar
Thomas Witkowski committed
377
378
379

    // === First, create all the information about the interior boundaries. ===

380
    TraverseStack stack;
381
382
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, 
					 Mesh::CALL_LEAF_EL | Mesh::FILL_NEIGH);
383
384
385
386
387
388
389
390
391
392
393
394
    while (elInfo) {
      Element *element = elInfo->getElement();

      PartitionElementData *partitionData = 
	dynamic_cast<PartitionElementData*>(element->getElementData(PARTITION_ED));   
      if (partitionData->getPartitionStatus() == IN) {
	for (int i = 0; i < 3; i++) {
	  if (!elInfo->getNeighbour(i))
	    continue;

	  PartitionElementData *neighbourPartitionData =
	    dynamic_cast<PartitionElementData*>(elInfo->getNeighbour(i)->getElementData(PARTITION_ED));
395

396
 	  if (neighbourPartitionData->getPartitionStatus() == OUT) {
397
398
	    // We have found an element that is at an interior boundary. 

399
400
	    // === Find out, if the boundary part of the element corresponds to the  ===
	    // === rank or to the rank "on the other side" of the interoir boundary. ===
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425

	    const DegreeOfFreedom* boundDOF1 = NULL;
	    const DegreeOfFreedom* boundDOF2 = NULL;
	    
	    switch (i) {
	    case 0:
	      boundDOF1 = element->getDOF(1);
	      boundDOF2 = element->getDOF(2);
	      break;
	    case 1:
	      boundDOF1 = element->getDOF(0);
	      boundDOF2 = element->getDOF(2);
	      break;
	    case 2:
	      boundDOF1 = element->getDOF(0);
	      boundDOF2 = element->getDOF(1);
	      break;
	    default:
	      ERROR_EXIT("Should never happen!\n");
	    }

	    bool isRankDOF1 = (find(rankDOFs.begin(), rankDOFs.end(), boundDOF1) != rankDOFs.end());
	    bool isRankDOF2 = (find(rankDOFs.begin(), rankDOFs.end(), boundDOF2) != rankDOFs.end());
	    bool ranksBoundary = isRankDOF1 || isRankDOF2;

426
	    // === And add the part of the interior boundary. ===
427
428

	    AtomicBoundary& bound = 
Thomas Witkowski's avatar
Thomas Witkowski committed
429
430
431
432
	      (ranksBoundary ?
	       myIntBoundary.getNewAtomicBoundary(partitionVec[elInfo->getNeighbour(i)->getIndex()]) :
	       otherIntBoundary.getNewAtomicBoundary(partitionVec[elInfo->getNeighbour(i)->getIndex()]));

433
434
435
436
437
438
	    bound.rankObject.el = element;
	    bound.rankObject.subObjAtBoundary = EDGE;
	    bound.rankObject.ithObjAtBoundary = i;
	    bound.neighbourObject.el = elInfo->getNeighbour(i);
	    bound.neighbourObject.subObjAtBoundary = EDGE;
	    bound.neighbourObject.ithObjAtBoundary = -1;
439
440
441
442
443
444
 	  }
	}
      }

      elInfo = stack.traverseNext(elInfo);
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
445
446
447


    // === Once we have this information, we must care about their order. Eventually ===
Thomas Witkowski's avatar
Thomas Witkowski committed
448
449
    // === all the boundaries have to be in the same order on both ranks that share  ===
    // === the bounday.                                                              ===
Thomas Witkowski's avatar
Thomas Witkowski committed
450

Thomas Witkowski's avatar
Thomas Witkowski committed
451
    std::vector<int*> sendBuffers, recvBuffers;
Thomas Witkowski's avatar
Thomas Witkowski committed
452

Thomas Witkowski's avatar
Thomas Witkowski committed
453
454
455
456
    MPI::Request request[myIntBoundary.boundary.size() + 
			 otherIntBoundary.boundary.size()];
    int requestCounter = 0;

Thomas Witkowski's avatar
Thomas Witkowski committed
457
458
    for (RankToBoundMap::iterator rankIt = myIntBoundary.boundary.begin();
	 rankIt != myIntBoundary.boundary.end(); ++rankIt) {    
Thomas Witkowski's avatar
Thomas Witkowski committed
459
460
461
      int nSendInt = rankIt->second.size();
      int* buffer = new int[nSendInt];
      for (int i = 0; i < nSendInt; i++)
Thomas Witkowski's avatar
Thomas Witkowski committed
462
463
464
	buffer[i] = (rankIt->second)[i].rankObject.el->getIndex();
      sendBuffers.push_back(buffer);
      
Thomas Witkowski's avatar
Thomas Witkowski committed
465
466
      request[requestCounter++] =
	mpiComm.Isend(buffer, nSendInt, MPI_INT, rankIt->first, 0);
Thomas Witkowski's avatar
Thomas Witkowski committed
467
468
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
469
470
    for (RankToBoundMap::iterator rankIt = otherIntBoundary.boundary.begin();
	 rankIt != otherIntBoundary.boundary.end(); ++rankIt) {
Thomas Witkowski's avatar
Thomas Witkowski committed
471
472
      int nRecvInt = rankIt->second.size();
      int *buffer = new int[nRecvInt];
Thomas Witkowski's avatar
Thomas Witkowski committed
473
      recvBuffers.push_back(buffer);
Thomas Witkowski's avatar
Thomas Witkowski committed
474

Thomas Witkowski's avatar
Thomas Witkowski committed
475
476
      request[requestCounter++] = 
	mpiComm.Irecv(buffer, nRecvInt, MPI_INT, rankIt->first, 0);
Thomas Witkowski's avatar
Thomas Witkowski committed
477
478
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
479
480
481

    MPI::Request::Waitall(requestCounter, request);

Thomas Witkowski's avatar
Thomas Witkowski committed
482
483

    int i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
484
485
    for (RankToBoundMap::iterator rankIt = otherIntBoundary.boundary.begin();
	 rankIt != otherIntBoundary.boundary.end(); ++rankIt) {
Thomas Witkowski's avatar
Thomas Witkowski committed
486
487
488
489
490
491
492
493
494
495
496
497
498
499

      // === We have received from rank "rankIt->first" the ordered list of element ===
      // === indices. We now have to sort the corresponding list in this rank to    ===
      // === get the same order.                                                    ===
      
      for (int j = 0; j < static_cast<int>(rankIt->second.size()); j++) {
	// If the expected object is not at place, search for it.
	if ((rankIt->second)[j].neighbourObject.el->getIndex() != recvBuffers[i][j]) {
	  int k = j + 1;
	  for (; k < static_cast<int>(rankIt->second.size()); k++)
	    if ((rankIt->second)[k].neighbourObject.el->getIndex() == recvBuffers[i][j])
	      break;

	  // The element must always be found, because the list is just in another order.
Thomas Witkowski's avatar
Thomas Witkowski committed
500
	  TEST_EXIT_DBG(k < static_cast<int>(rankIt->second.size()))
501
	    ("Should never happen!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
502
503
504
505
506
507
508
509
510
511
512
513
514

	  // Swap the current with the found element.
	  AtomicBoundary tmpBound = (rankIt->second)[k];
	  (rankIt->second)[k] = (rankIt->second)[j];
	  (rankIt->second)[j] = tmpBound;	
	}
      }

      delete [] recvBuffers[i++];
    }

    for (int i = 0; i < static_cast<int>(sendBuffers.size()); i++)
      delete [] sendBuffers[i];
515
516
517
  }


518
  void ParallelDomainBase::removeMacroElements()
519
520
521
522
523
524
525
526
527
528
529
530
  {
    std::vector<MacroElement*> macrosToRemove;
    for (std::deque<MacroElement*>::iterator it = mesh->firstMacroElement();
	 it != mesh->endOfMacroElements();
	 ++it) {
      PartitionElementData *partitionData = 
	dynamic_cast<PartitionElementData*>
	((*it)->getElement()->getElementData(PARTITION_ED));
      if (partitionData->getPartitionStatus() != IN)
	macrosToRemove.push_back(*it);
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
531
    mesh->removeMacroElements(macrosToRemove, feSpace);
532
533
534
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
535
536
537
538
  void ParallelDomainBase::createLocalGlobalNumbering(DofContainer& rankDOFs,
						      DofToRank& boundaryDOFs,
						      int& nRankDOFs, 
						      int& nOverallDOFs)
539
  {
540
    FUNCNAME("ParallelDomainBase::createLocalGlobalNumbering()");
541
542

    // === Get rank information about DOFs. ===
543
544
545

    // Stores to each DOF pointer the set of ranks the DOF is part of.
    std::map<const DegreeOfFreedom*, std::set<int> > partitionDOFs;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
546
    DofContainer rankAllDofs;
547

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
548
    createDOFMemberInfo(partitionDOFs, rankDOFs, rankAllDofs, boundaryDOFs);
549
550
551
552

    nRankDOFs = rankDOFs.size();
    nOverallDOFs = partitionDOFs.size();

553

554
    // === Get starting position for global rank dof ordering. ====
555

556
    rstart = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
557
    mpiComm.Scan(&nRankDOFs, &rstart, 1, MPI_INT, MPI_SUM);
558
559
    rstart -= nRankDOFs;

560
561
562
563
    
    // === Create for all dofs in rank new indices. The new index must start at ===
    // === index 0, must be continues and have the same order as the indices    ===
    // === had before.                                                          ===
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
564

Thomas Witkowski's avatar
Thomas Witkowski committed
565

566
567
568
    // Do not change the indices now, but create a new indexing a store it here.
    DofIndexMap rankDofsNewLocalIndex;
    isRankDof.clear();
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
569
570
571
    int i = 0;
    for (DofContainer::iterator dofIt = rankAllDofs.begin();
	 dofIt != rankAllDofs.end(); ++dofIt) {
572
573
574
      rankDofsNewLocalIndex[*dofIt] = i;
      // First, we set all dofs in ranks partition to be owend by the rank. Later,
      // the dofs in ranks partition that are owned by other rank are set to false.
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
575
      isRankDof[i] = true;
576
      i++;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
577
578
    }

579
580
581
582
583
584
585
586

    // === Create for all rank owned dofs a new global indexing.                ===

    // Stores for all rank owned dofs a new global index.
    DofIndexMap rankOwnedDofsNewGlobalIndex;
    // Stores for all rank owned dofs a continues local index.
    DofIndexMap rankOwnedDofsNewLocalIndex;

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
587
588
589
    i = 0;
    for (DofContainer::iterator dofIt = rankDOFs.begin();
	 dofIt != rankDOFs.end(); ++dofIt) {
590
591
      rankOwnedDofsNewGlobalIndex[*dofIt] = i + rstart;
      rankOwnedDofsNewLocalIndex[*dofIt] = i;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
592
593
594
      i++;
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
595
 
596
597
598
599
600
601
    // === Create information which dof indices must be send and which must  ===
    // === be received.                                                      ===

    // Stores to each rank a map from DOF pointers (which are all owned by the rank
    // and lie on an interior boundary) to new global DOF indices.
    std::map<int, std::map<const DegreeOfFreedom*, DegreeOfFreedom> > sendNewDofs;
602

603
604
605
606
    // Maps to each rank the number of new DOF indices this rank will receive from.
    // All these DOFs are at an interior boundary on this rank, but are owned by
    // another rank.
    std::map<int, int> recvNewDofs;
607

Thomas Witkowski's avatar
Thomas Witkowski committed
608
    for (DofToRank::iterator it = boundaryDOFs.begin(); it != boundaryDOFs.end(); ++it) {
609
610
611
612
613
614
615
616

      if (it->second == mpiRank) {
	// If the boundary dof is a rank dof, it must be send to other ranks.

	// Search for all ranks that have this dof too.
	for (std::set<int>::iterator itRanks = partitionDOFs[it->first].begin();
	     itRanks != partitionDOFs[it->first].end();
	     ++itRanks) {
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
617
	  if (*itRanks != mpiRank) {
618
	    TEST_EXIT_DBG(rankOwnedDofsNewGlobalIndex.count(it->first) == 1)
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
619
620
	      ("DOF Key not found!\n");

621
	    sendNewDofs[*itRanks][it->first] = rankOwnedDofsNewGlobalIndex[it->first];
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
622
	  }
623
624
	}
      } else {
Thomas Witkowski's avatar
Thomas Witkowski committed
625
626
	// If the boundary dof is not a rank dof, its new dof index (and later
	// also the dof values) must be received from another rank.
627
628
629
630
	if (recvNewDofs.find(it->second) == recvNewDofs.end()) 
	  recvNewDofs[it->second] = 1;
	else
	  recvNewDofs[it->second]++;
631
632
633
      }
    }

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
634

635
    // === Send and receive the dof indices at boundary. ===
636

Thomas Witkowski's avatar
Thomas Witkowski committed
637
    std::vector<int*> sendBuffers(sendNewDofs.size()), recvBuffers(recvNewDofs.size());
638
639
640

    sendDofs.clear();
    recvDofs.clear();
641
    
Thomas Witkowski's avatar
Thomas Witkowski committed
642
643
644
    MPI::Request request[sendNewDofs.size() + recvNewDofs.size()];
    int requestCounter = 0;

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
645
    i = 0;
646
647
    for (std::map<int, std::map<const DegreeOfFreedom*, DegreeOfFreedom> >::iterator 
	   sendIt = sendNewDofs.begin();
648
649
	 sendIt != sendNewDofs.end();
	 ++sendIt, i++) {
650
651
      int nSendDofs = sendIt->second.size() * 2;
      sendBuffers[i] = new int[nSendDofs];
652

653
      int c = 0;
654
655
      for (std::map<const DegreeOfFreedom*, DegreeOfFreedom>::iterator 
	     dofIt = sendIt->second.begin();
656
	   dofIt != sendIt->second.end();
657
	   ++dofIt) {
Thomas Witkowski's avatar
Thomas Witkowski committed
658
	sendBuffers[i][c++] = *(dofIt->first);
659
	sendBuffers[i][c++] = dofIt->second;
660

661
	sendDofs[sendIt->first].push_back(dofIt->first);
662
663
      }

Thomas Witkowski's avatar
Thomas Witkowski committed
664
665
      request[requestCounter++] =
	mpiComm.Isend(sendBuffers[i], nSendDofs, MPI_INT, sendIt->first, 0);
666
667
668
    }

    i = 0;
669
    for (std::map<int, int>::iterator recvIt = recvNewDofs.begin();
670
671
	 recvIt != recvNewDofs.end();
	 ++recvIt, i++) {
672
673
      int nRecvDOFs = recvIt->second * 2;
      recvBuffers[i] = new int[nRecvDOFs];
674

Thomas Witkowski's avatar
Thomas Witkowski committed
675
676
      request[requestCounter++] =
	mpiComm.Irecv(recvBuffers[i], nRecvDOFs, MPI_INT, recvIt->first, 0);
677
678
679
    }


Thomas Witkowski's avatar
Thomas Witkowski committed
680
    MPI::Request::Waitall(requestCounter, request);
681
682

    
683
    // === Delete send buffers. ===
684

Thomas Witkowski's avatar
Thomas Witkowski committed
685
686
    for (int j = 0; j < static_cast<int>(sendBuffers.size()); j++)
      delete [] sendBuffers[j];
687
688


689
690
691
    // === Change dof indices for rank partition. ===

    mapLocalGlobalDOFs.clear();
692

693
    // === Change dof indices at boundary from other ranks. ===
694

Thomas Witkowski's avatar
Thomas Witkowski committed
695
696
697
698
699
700
701
702
    // Within this small data structure we track which dof index was already changed.
    // This is used to avoid the following situation: Assume, there are two dof indices
    // a and b in boundaryDOFs. Then we have to change index a to b and b to c. When
    // the second rule applies, we have to avoid that not the first b, resulted from
    // changing a to b, is set to c, but the second one. Therefore, after the first
    // rule was applied, the dof pointer is set to false in this data structure and 
    // is not allowed to be changed anymore.
    std::map<const DegreeOfFreedom*, bool> dofChanged;
Thomas Witkowski's avatar
Thomas Witkowski committed
703
704
    for (DofToRank::iterator dofIt = boundaryDOFs.begin(); dofIt != boundaryDOFs.end();
	 ++dofIt)
Thomas Witkowski's avatar
Thomas Witkowski committed
705
706
      dofChanged[dofIt->first] = false;

707
    i = 0;
708
    for (std::map<int, int>::iterator recvIt = recvNewDofs.begin();
709
710
711
	 recvIt != recvNewDofs.end();
	 ++recvIt, i++) {

712
      for (int j = 0; j < recvIt->second; j++) {
713

714
715
	DegreeOfFreedom oldDof = recvBuffers[i][j * 2];
	DegreeOfFreedom newGlobalDof = recvBuffers[i][j * 2 + 1];
716

717
	bool found = false;
718

Thomas Witkowski's avatar
Thomas Witkowski committed
719
720
	// Iterate over all boundary dofs to find the dof, which index we have to change.

Thomas Witkowski's avatar
Thomas Witkowski committed
721
722
	for (DofToRank::iterator dofIt = boundaryDOFs.begin(); 
	     dofIt != boundaryDOFs.end(); ++dofIt) {
723

Thomas Witkowski's avatar
Thomas Witkowski committed
724
725
726
	  if (*(dofIt->first) == oldDof && !dofChanged[dofIt->first]) {
	    dofChanged[dofIt->first] = true;

727
	    recvDofs[recvIt->first].push_back(dofIt->first);
728
	    rankOwnedDofsNewGlobalIndex[dofIt->first] = newGlobalDof;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
729
	    isRankDof[rankDofsNewLocalIndex[dofIt->first]] = false;
Thomas Witkowski's avatar
Thomas Witkowski committed
730

731
	    found = true;
732
733
734
	    break;
	  }
	}
735

Thomas Witkowski's avatar
Thomas Witkowski committed
736
	TEST_EXIT_DBG(found)("Should not happen!\n");
737
738
739
740
      }

      delete [] recvBuffers[i];
    }
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
741

742
743
744
    
    // === Create now the local to global index, and vice verse, mappings.     ===

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
745
746
747
    for (DofIndexMap::iterator dofIt = rankDofsNewLocalIndex.begin();
	 dofIt != rankDofsNewLocalIndex.end(); ++dofIt) {
      DegreeOfFreedom localDof = dofIt->second;
748
      DegreeOfFreedom globalDof = rankOwnedDofsNewGlobalIndex[dofIt->first];
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
749
750
751

      *const_cast<DegreeOfFreedom*>(dofIt->first) = localDof;
      mapLocalGlobalDOFs[localDof] = globalDof;
Thomas Witkowski's avatar
Thomas Witkowski committed
752
753
    }

754
755
756
757
    mapLocalToDofIndex.clear();
    for (DofIndexMap::iterator dofIt = rankOwnedDofsNewLocalIndex.begin();
	 dofIt != rankOwnedDofsNewLocalIndex.end(); ++dofIt)
      mapLocalToDofIndex[dofIt->second] = *(dofIt->first);
758
759
760
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
761
  void ParallelDomainBase::updateLocalGlobalNumbering(int& nRankDOFs, int& nOverallDOFs)
762
  {
763
    FUNCNAME("ParallelDomainBase::updateLocalGlobalNumbering()");
Thomas Witkowski's avatar
Thomas Witkowski committed
764

765
    typedef std::set<const DegreeOfFreedom*> DofSet;
Thomas Witkowski's avatar
Thomas Witkowski committed
766

767
    // === Get all DOFs in ranks partition. ===
768

Thomas Witkowski's avatar
Thomas Witkowski committed
769
    ElementDofIterator elDofIt(feSpace);
770
    DofSet rankDOFSet;
771
772
773
    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
    while (elInfo) {
Thomas Witkowski's avatar
Thomas Witkowski committed
774
      Element *element = elInfo->getElement();     
Thomas Witkowski's avatar
Thomas Witkowski committed
775
776
      elDofIt.reset(element);
      do {
777
	rankDOFSet.insert(elDofIt.getDofPtr());
Thomas Witkowski's avatar
Thomas Witkowski committed
778
      } while(elDofIt.next());
779
780
781
782

      elInfo = stack.traverseNext(elInfo);
    }

783
784
785
786
787
788
789
    DofContainer rankAllDofs;
    for (DofSet::iterator dofIt = rankDOFSet.begin(); dofIt != rankDOFSet.end(); ++dofIt)
      rankAllDofs.push_back(*dofIt);
    sort(rankAllDofs.begin(), rankAllDofs.end(), cmpDofsByValue);
    DofContainer rankDOFs = rankAllDofs;


Thomas Witkowski's avatar
Thomas Witkowski committed
790
    // === Traverse on interior boundaries and move all not ranked owned DOFs from ===
791
    // === rankDOFs to boundaryDOFs.                                               ===
792

793
    DofToRank newBoundaryDOFs;
Thomas Witkowski's avatar
Thomas Witkowski committed
794
795
    RankToDofContainer sendNewDofs;
    RankToDofContainer recvNewDofs;
796

Thomas Witkowski's avatar
Thomas Witkowski committed
797
798
799
    for (RankToBoundMap::iterator it =  myIntBoundary.boundary.begin();
	 it != myIntBoundary.boundary.end(); ++it) {

Thomas Witkowski's avatar
Thomas Witkowski committed
800
      for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
801
802
	   boundIt != it->second.end(); ++boundIt) {

803
	const DegreeOfFreedom *dof1, *dof2;
Thomas Witkowski's avatar
Thomas Witkowski committed
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821

	switch (boundIt->rankObject.ithObjAtBoundary) {
	case 0:
	  dof1 = boundIt->rankObject.el->getDOF(1);
	  dof2 = boundIt->rankObject.el->getDOF(2);
	  break;
	case 1:
	  dof1 = boundIt->rankObject.el->getDOF(0);
	  dof2 = boundIt->rankObject.el->getDOF(2);
	  break;
	case 2:
	  dof1 = boundIt->rankObject.el->getDOF(0);
	  dof2 = boundIt->rankObject.el->getDOF(1);
	  break;
	default:
	  ERROR_EXIT("Should never happen!\n");
	}

Thomas Witkowski's avatar
Thomas Witkowski committed
822
	TEST_EXIT_DBG(boundaryDOFs.find(dof1) != boundaryDOFs.end())
823
	  ("Should never happen!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
824
	TEST_EXIT_DBG(boundaryDOFs.find(dof2) != boundaryDOFs.end())
825
826
827
828
	  ("Should never happen!\n");

	newBoundaryDOFs[dof1] = boundaryDOFs[dof1];
	newBoundaryDOFs[dof2] = boundaryDOFs[dof2];
Thomas Witkowski's avatar
Thomas Witkowski committed
829

830
831
832
833
834
835
836
	DofContainer &dofsToSend = sendNewDofs[it->first];

  	if (find(dofsToSend.begin(), dofsToSend.end(), dof1) == dofsToSend.end())
 	  dofsToSend.push_back(dof1);
  	if (find(dofsToSend.begin(), dofsToSend.end(), dof2) == dofsToSend.end())
 	  dofsToSend.push_back(dof2);

Thomas Witkowski's avatar
Thomas Witkowski committed
837
838
839
	DofContainer boundDOFs;
	addAllVertexDOFs(boundIt->rankObject.el, 
			 boundIt->rankObject.ithObjAtBoundary,
Thomas Witkowski's avatar
Thomas Witkowski committed
840
841
842
843
			 boundDOFs);	
  	addAllEdgeDOFs(boundIt->rankObject.el, 
  		       boundIt->rankObject.ithObjAtBoundary,
  		       boundDOFs);
844
845
846

	for (int i = 0; i < static_cast<int>(boundDOFs.size()); i++) {
	  newBoundaryDOFs[boundDOFs[i]] = mpiRank;
847
	  dofsToSend.push_back(boundDOFs[i]);
848
	}
Thomas Witkowski's avatar
Thomas Witkowski committed
849
	
850
851
852
      }
    }    

Thomas Witkowski's avatar
Thomas Witkowski committed
853
854
855
    for (RankToBoundMap::iterator it = otherIntBoundary.boundary.begin();
	 it != otherIntBoundary.boundary.end(); ++it) {

856
      for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
857
858
	   boundIt != it->second.end(); ++boundIt) {

859
	const DegreeOfFreedom *dof1, *dof2;
860
861
862
863
864
865
866
867
868
869
870

	switch (boundIt->rankObject.ithObjAtBoundary) {
	case 0:
	  dof1 = boundIt->rankObject.el->getDOF(1);
	  dof2 = boundIt->rankObject.el->getDOF(2);
	  break;
	case 1:
	  dof1 = boundIt->rankObject.el->getDOF(0);
	  dof2 = boundIt->rankObject.el->getDOF(2);
	  break;
	case 2:
Thomas Witkowski's avatar
Thomas Witkowski committed
871
872
	  dof1 = boundIt->rankObject.el->getDOF(1);
	  dof2 = boundIt->rankObject.el->getDOF(0);
873
874
875
876
877
	  break;
	default:
	  ERROR_EXIT("Should never happen!\n");
	}

Thomas Witkowski's avatar
Thomas Witkowski committed
878
	TEST_EXIT_DBG(boundaryDOFs.find(dof1) != boundaryDOFs.end())
879
	  ("Should never happen!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
880
	TEST_EXIT_DBG(boundaryDOFs.find(dof2) != boundaryDOFs.end())
881
882
	  ("Should never happen!\n");

883
884
885
886
887
888
889
	DofContainer::iterator eraseIt = find(rankDOFs.begin(), rankDOFs.end(), dof1);
	if (eraseIt != rankDOFs.end())
	  rankDOFs.erase(eraseIt);
	eraseIt = find(rankDOFs.begin(), rankDOFs.end(), dof2);
	if (eraseIt != rankDOFs.end())
	  rankDOFs.erase(eraseIt);

890
891
	newBoundaryDOFs[dof1] = boundaryDOFs[dof1];
	newBoundaryDOFs[dof2] = boundaryDOFs[dof2];
Thomas Witkowski's avatar
Thomas Witkowski committed
892

893
894
895
896
897
898
899
	DofContainer &dofsToRecv = recvNewDofs[it->first];
  	if (find(dofsToRecv.begin(), dofsToRecv.end(), dof1) == dofsToRecv.end())
 	  dofsToRecv.push_back(dof1);
  	if (find(dofsToRecv.begin(), dofsToRecv.end(), dof2) == dofsToRecv.end())
 	  dofsToRecv.push_back(dof2);

	DofContainer boundDOFs;	
Thomas Witkowski's avatar
Thomas Witkowski committed
900
	addAllEdgeDOFs(boundIt->rankObject.el, 
Thomas Witkowski's avatar
Thomas Witkowski committed
901
902
 		       boundIt->rankObject.ithObjAtBoundary,
 		       boundDOFs);
Thomas Witkowski's avatar
Thomas Witkowski committed
903
904
905
906
	addAllVertexDOFs(boundIt->rankObject.el, 
			 boundIt->rankObject.ithObjAtBoundary,
			 boundDOFs);

Thomas Witkowski's avatar
Thomas Witkowski committed
907
	for (int i = static_cast<int>(boundDOFs.size()) - 1; i >= 0; i--) {
908
909
910
911
912
913
914
	  TEST_EXIT_DBG(find(rankDOFs.begin(), rankDOFs.end(), boundDOFs[i]) != rankDOFs.end())
	    ("Should never happen!\n");

	  eraseIt = find(rankDOFs.begin(), rankDOFs.end(), boundDOFs[i]);
	  if (eraseIt != rankDOFs.end())
	    rankDOFs.erase(eraseIt);

915
	  newBoundaryDOFs[boundDOFs[i]] = it->first;
916
	  dofsToRecv.push_back(boundDOFs[i]);
917
	}
Thomas Witkowski's avatar
Thomas Witkowski committed
918
919
920
      }
    }

921
922
923
924
925
    nRankDOFs = rankDOFs.size();

    // === Get starting position for global rank dof ordering. ====

    int rstart = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
926
    mpiComm.Scan(&nRankDOFs, &rstart, 1, MPI_INT, MPI_SUM);
927
928
929
930
931
    rstart -= nRankDOFs;


    // === Calculate number of overall DOFs of all partitions. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
932
    mpiComm.Allreduce(&nRankDOFs, &nOverallDOFs, 1, MPI_INT, MPI_SUM);
933
934


935
    // ===
936
937


938
939
940
    // Do not change the indices now, but create a new indexing a store it here.
    DofIndexMap rankDofsNewLocalIndex;
    isRankDof.clear();
941
    int i = 0;
942
943
944
945
946
    for (DofContainer::iterator dofIt = rankAllDofs.begin();
	 dofIt != rankAllDofs.end(); ++dofIt) {
      rankDofsNewLocalIndex[*dofIt] = i;
      // First, we set all dofs in ranks partition to be owend by the rank. Later,
      // the dofs in ranks partition that are owned by other rank are set to false.
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
947
      isRankDof[i] = true;
948
      i++;
949
950
    }

951
952
953
954
955
956
957
958
959
960
961
962
963
964
    // Stores for all rank owned dofs a new global index.
    DofIndexMap rankOwnedDofsNewGlobalIndex;
    // Stores for all rank owned dofs a continues local index.
    DofIndexMap rankOwnedDofsNewLocalIndex;

    i = 0;
    for (DofContainer::iterator dofIt = rankDOFs.begin();
	 dofIt != rankDOFs.end(); ++dofIt) {
      rankOwnedDofsNewGlobalIndex[*dofIt] = i + rstart;
      rankOwnedDofsNewLocalIndex[*dofIt] = i;
      i++;
    }


965
966
    // === Send new DOF indices. ===

967
968
969
    std::vector<int*> sendBuffers(sendNewDofs.size());
    std::vector<int*> recvBuffers(recvNewDofs.size());

Thomas Witkowski's avatar
Thomas Witkowski committed
970
971
972
    MPI::Request request[sendNewDofs.size() + recvNewDofs.size()];
    int requestCounter = 0;

973
    i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
974
    for (RankToDofContainer::iterator sendIt = sendNewDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
975
	 sendIt != sendNewDofs.end(); ++sendIt, i++) {
976
977
978
      int nSendDofs = sendIt->second.size();
      sendBuffers[i] = new int[nSendDofs];
      int c = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
979
      for (DofContainer::iterator dofIt = sendIt->second.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
980
	   dofIt != sendIt->second.end(); ++dofIt)
981
	sendBuffers[i][c++] = rankOwnedDofsNewGlobalIndex[*dofIt];
982

Thomas Witkowski's avatar
Thomas Witkowski committed
983
984
      request[requestCounter++] = 
	mpiComm.Isend(sendBuffers[i], nSendDofs, MPI_INT, sendIt->first, 0);
985
986
987
    }

    i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
988
    for (RankToDofContainer::iterator recvIt = recvNewDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
989
	 recvIt != recvNewDofs.end(); ++recvIt, i++) {
990
991
992
      int nRecvDofs = recvIt->second.size();
      recvBuffers[i] = new int[nRecvDofs];
	
Thomas Witkowski's avatar
Thomas Witkowski committed
993
994
      request[requestCounter++] = 
	mpiComm.Irecv(recvBuffers[i], nRecvDofs, MPI_INT, recvIt->first, 0);
995
996
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
997
998
    MPI::Request::Waitall(requestCounter, request);

999
1000
    for (int j = 0; j < static_cast<int>(sendBuffers.size()); j++)
      delete [] sendBuffers[j];