ParallelDomainBase.cc 42.9 KB
Newer Older
Thomas Witkowski's avatar
Thomas Witkowski committed
1
2
#include <algorithm>

3
#include "ParallelDomainBase.h"
4
5
6
7
8
9
10
#include "ParMetisPartitioner.h"
#include "Mesh.h"
#include "Traverse.h"
#include "ElInfo.h"
#include "Element.h"
#include "MacroElement.h"
#include "PartitionElementData.h"
11
12
#include "DOFMatrix.h"
#include "DOFVector.h"
13
#include "VtkWriter.h"
14
#include "ElementDofIterator.h"
15
16

#include "petscksp.h"
17
18
19

namespace AMDiS {

20
21
  PetscErrorCode myKSPMonitor(KSP ksp, PetscInt iter, PetscReal rnorm, void *)
  {
22
    if (iter % 100 == 0 && MPI::COMM_WORLD.Get_rank() == 0)
23
      std::cout << "  Iteration " << iter << ": " << rnorm << std::endl;
24
25
26
27

    return 0;
  }

28
29
30
31
32
  inline bool cmpDofsByValue(const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2)
  {
    return (*dof1 < *dof2);
  }

33
34
35
36
37
  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, nRankDOFs, nOverallDOFs);
92

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

95
    createInteriorBoundaryInfo(rankDOFs);
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

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

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

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

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

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

      updateDofAdmins();

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

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

137

138
    // === Create petsc matrix. ===
139

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

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

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

154
155
156
157

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

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  
  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());
    }
  }

177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  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)
202
  {
203
204
205
206
207
208
209
210
211
212
213
    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;

214
215
216
217
    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)
218
	if (value(*icursor) != 0.0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
219
220
 	  int r = mapLocalGlobalDOFs[row(*icursor)];
 	  int c = mapLocalGlobalDOFs[col(*icursor)];  
221
	  double v = value(*icursor);
222

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

226
227
228
229

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

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

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

240

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

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

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

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

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

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

    VecRestoreArray(petscSolVec, &vecPointer);

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

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

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

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

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

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

Thomas Witkowski's avatar
Thomas Witkowski committed
304
305
306

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

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

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

321

322
  double ParallelDomainBase::setElemWeights(AdaptInfo *adaptInfo) 
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  {
    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
343
	TEST_EXIT_DBG(elNum != -1)("invalid element number\n");
344
345
346
347
348
349
350
351
352
353
354
355
	if (element->isLeaf()) {
	  elemWeights[elNum] += 1.0;
	  localWeightSum += 1.0;
	}
      }

      elInfo = stack.traverseNext(elInfo);
    }

    return localWeightSum;
  }

356

357
  void ParallelDomainBase::partitionMesh(AdaptInfo *adaptInfo)
358
359
360
361
362
363
364
365
366
367
368
369
370
  {
    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);
  }

371

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

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

378
    TraverseStack stack;
379
380
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, 
					 Mesh::CALL_LEAF_EL | Mesh::FILL_NEIGH);
381
382
383
384
385
386
387
388
389
390
391
392
    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));
393

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

397
398
	    // === 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. ===
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423

	    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;

424
	    // === And add the part of the interior boundary. ===
425
426

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

431
432
433
434
435
436
	    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;
437
438
439
440
441
442
 	  }
	}
      }

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


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

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

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

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

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

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

Thomas Witkowski's avatar
Thomas Witkowski committed
477
478
479

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

Thomas Witkowski's avatar
Thomas Witkowski committed
480
481

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

      // === 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
498
	  TEST_EXIT_DBG(k < static_cast<int>(rankIt->second.size()))
499
	    ("Should never happen!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
500
501
502
503
504
505
506
507
508
509
510
511
512

	  // 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];
513
514
515
  }


516
  void ParallelDomainBase::removeMacroElements()
517
518
519
520
521
522
523
524
525
526
527
528
  {
    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
529
    mesh->removeMacroElements(macrosToRemove, feSpace);
530
531
532
  }


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

    // === Get rank information about DOFs. ===
540
541
542

    // 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
543
    DofContainer rankAllDofs;
544
    DofToRank boundaryDofs;
545

546
    createDOFMemberInfo(partitionDOFs, rankDOFs, rankAllDofs, boundaryDofs);
547
548
549
550

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

551

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

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

558
559
560
561
    
    // === 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
562

Thomas Witkowski's avatar
Thomas Witkowski committed
563

564
565
566
    // 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
567
568
569
    int i = 0;
    for (DofContainer::iterator dofIt = rankAllDofs.begin();
	 dofIt != rankAllDofs.end(); ++dofIt) {
570
571
572
      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
573
      isRankDof[i] = true;
574
      i++;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
575
576
    }

577
578
579

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

580
581
    // Stores for dofs in rank a new global index.
    DofIndexMap rankDofsNewGlobalIndex;
582
583
584
    // Stores for all rank owned dofs a continues local index.
    DofIndexMap rankOwnedDofsNewLocalIndex;

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

Thomas Witkowski's avatar
Thomas Witkowski committed
593
 
594
595
596
597
598
599
    // === 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;
600

601
602
603
604
    // 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;
605

606
    for (DofToRank::iterator it = boundaryDofs.begin(); it != boundaryDofs.end(); ++it) {
607
608
609
610
611
612
613
614

      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
615
	  if (*itRanks != mpiRank) {
616
	    TEST_EXIT_DBG(rankDofsNewGlobalIndex.count(it->first) == 1)
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
617
618
	      ("DOF Key not found!\n");

619
	    sendNewDofs[*itRanks][it->first] = rankDofsNewGlobalIndex[it->first];
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
620
	  }
621
622
	}
      } else {
Thomas Witkowski's avatar
Thomas Witkowski committed
623
624
	// 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.
625
626
627
628
	if (recvNewDofs.find(it->second) == recvNewDofs.end()) 
	  recvNewDofs[it->second] = 1;
	else
	  recvNewDofs[it->second]++;
629
630
631
      }
    }

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
632

633
    // === Send and receive the dof indices at boundary. ===
634

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

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

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

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

659
	sendDofs[sendIt->first].push_back(dofIt->first);
660
661
      }

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

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

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


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

    
681
    // === Delete send buffers. ===
682

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


687
    // === Change dof indices at boundary from other ranks. ===
688

Thomas Witkowski's avatar
Thomas Witkowski committed
689
690
    // 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
691
    // a and b in boundaryDofs. Then we have to change index a to b and b to c. When
Thomas Witkowski's avatar
Thomas Witkowski committed
692
693
694
695
696
    // 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;
697
    for (DofToRank::iterator dofIt = boundaryDofs.begin(); dofIt != boundaryDofs.end();
Thomas Witkowski's avatar
Thomas Witkowski committed
698
	 ++dofIt)
Thomas Witkowski's avatar
Thomas Witkowski committed
699
700
      dofChanged[dofIt->first] = false;

701
    i = 0;
702
    for (std::map<int, int>::iterator recvIt = recvNewDofs.begin();
703
704
705
	 recvIt != recvNewDofs.end();
	 ++recvIt, i++) {

706
      for (int j = 0; j < recvIt->second; j++) {
707

708
709
	DegreeOfFreedom oldDof = recvBuffers[i][j * 2];
	DegreeOfFreedom newGlobalDof = recvBuffers[i][j * 2 + 1];
710

711
	bool found = false;
712

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

715
716
	for (DofToRank::iterator dofIt = boundaryDofs.begin(); 
	     dofIt != boundaryDofs.end(); ++dofIt) {
717

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

721
	    recvDofs[recvIt->first].push_back(dofIt->first);
722
	    rankDofsNewGlobalIndex[dofIt->first] = newGlobalDof;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
723
	    isRankDof[rankDofsNewLocalIndex[dofIt->first]] = false;
Thomas Witkowski's avatar
Thomas Witkowski committed
724

725
	    found = true;
726
727
728
	    break;
	  }
	}
729

Thomas Witkowski's avatar
Thomas Witkowski committed
730
	TEST_EXIT_DBG(found)("Should not happen!\n");
731
732
733
734
      }

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

736
    // === Create now the local to global index and local to dof index mappings.  ===
737

738
739
    createLocalMappings(rankDofsNewLocalIndex, rankOwnedDofsNewLocalIndex,
			rankDofsNewGlobalIndex);
740
741
742
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
743
  void ParallelDomainBase::updateLocalGlobalNumbering(int& nRankDOFs, int& nOverallDOFs)
744
  {
745
    FUNCNAME("ParallelDomainBase::updateLocalGlobalNumbering()");
Thomas Witkowski's avatar
Thomas Witkowski committed
746

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

749
    // === Get all DOFs in ranks partition. ===
750

Thomas Witkowski's avatar
Thomas Witkowski committed
751
    ElementDofIterator elDofIt(feSpace);
752
    DofSet rankDOFSet;
753
754
755
    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
    while (elInfo) {
Thomas Witkowski's avatar
Thomas Witkowski committed
756
      Element *element = elInfo->getElement();     
Thomas Witkowski's avatar
Thomas Witkowski committed
757
758
      elDofIt.reset(element);
      do {
759
	rankDOFSet.insert(elDofIt.getDofPtr());
Thomas Witkowski's avatar
Thomas Witkowski committed
760
      } while(elDofIt.next());
761
762
763
764

      elInfo = stack.traverseNext(elInfo);
    }

765
766
767
768
769
770
771
    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
772
    // === Traverse on interior boundaries and move all not ranked owned DOFs from ===
773
    // === rankDOFs to boundaryDOFs.                                               ===
774

775
776
    sendDofs.clear();
    recvDofs.clear();
777

Thomas Witkowski's avatar
Thomas Witkowski committed
778
779
780
    for (RankToBoundMap::iterator it =  myIntBoundary.boundary.begin();
	 it != myIntBoundary.boundary.end(); ++it) {

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

784
785
	DofContainer dofs;
	DofContainer &dofsToSend = sendDofs[it->first];
Thomas Witkowski's avatar
Thomas Witkowski committed
786
787
788

	switch (boundIt->rankObject.ithObjAtBoundary) {
	case 0:
789
790
	  dofs.push_back(boundIt->rankObject.el->getDOF(1));
	  dofs.push_back(boundIt->rankObject.el->getDOF(2));
Thomas Witkowski's avatar
Thomas Witkowski committed
791
792
	  break;
	case 1:
793
794
	  dofs.push_back(boundIt->rankObject.el->getDOF(0));
	  dofs.push_back(boundIt->rankObject.el->getDOF(2));
Thomas Witkowski's avatar
Thomas Witkowski committed
795
796
	  break;
	case 2:
797
798
	  dofs.push_back(boundIt->rankObject.el->getDOF(0));
	  dofs.push_back(boundIt->rankObject.el->getDOF(1));
Thomas Witkowski's avatar
Thomas Witkowski committed
799
800
801
802
803
	  break;
	default:
	  ERROR_EXIT("Should never happen!\n");
	}

804
805
806
807
	for (DofContainer::iterator dofIt = dofs.begin(); dofIt != dofs.end(); ++dofIt) {
	  if (find(dofsToSend.begin(), dofsToSend.end(), *dofIt) == dofsToSend.end())
	    dofsToSend.push_back(*dofIt);
	}
808

809
810
811
812
813
814
815
	dofs.clear();
	addAllVertexDOFs(boundIt->rankObject.el, boundIt->rankObject.ithObjAtBoundary,
			 dofs);	
  	addAllEdgeDOFs(boundIt->rankObject.el, boundIt->rankObject.ithObjAtBoundary,
  		       dofs);
	for (int i = 0; i < static_cast<int>(dofs.size()); i++) {
	  dofsToSend.push_back(dofs[i]);
816
	}
Thomas Witkowski's avatar
Thomas Witkowski committed
817
	
818
819
820
      }
    }    

Thomas Witkowski's avatar
Thomas Witkowski committed
821
822
823
    for (RankToBoundMap::iterator it = otherIntBoundary.boundary.begin();
	 it != otherIntBoundary.boundary.end(); ++it) {

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

827
828
	DofContainer dofs;
	DofContainer &dofsToRecv = recvDofs[it->first];
829
830
831

	switch (boundIt->rankObject.ithObjAtBoundary) {
	case 0:
832
833
	  dofs.push_back(boundIt->rankObject.el->getDOF(1));
	  dofs.push_back(boundIt->rankObject.el->getDOF(2));
834
835
	  break;
	case 1:
836
837
	  dofs.push_back(boundIt->rankObject.el->getDOF(0));
	  dofs.push_back(boundIt->rankObject.el->getDOF(2));
838
839
	  break;
	case 2:
840
841
	  dofs.push_back(boundIt->rankObject.el->getDOF(1));
	  dofs.push_back(boundIt->rankObject.el->getDOF(0));
842
843
844
845
846
	  break;
	default:
	  ERROR_EXIT("Should never happen!\n");
	}

847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
	for (DofContainer::iterator dofIt = dofs.begin(); dofIt != dofs.end(); ++dofIt) {
	  DofContainer::iterator eraseIt = find(rankDOFs.begin(), rankDOFs.end(), *dofIt);
	  if (eraseIt != rankDOFs.end())
	    rankDOFs.erase(eraseIt);
	  if (find(dofsToRecv.begin(), dofsToRecv.end(), *dofIt) == dofsToRecv.end())
	    dofsToRecv.push_back(*dofIt);
	}

	dofs.clear();
	addAllEdgeDOFs(boundIt->rankObject.el, boundIt->rankObject.ithObjAtBoundary, 
		       dofs);
	addAllVertexDOFs(boundIt->rankObject.el, boundIt->rankObject.ithObjAtBoundary,
			 dofs);

	for (int i = static_cast<int>(dofs.size()) - 1; i >= 0; i--) {
	  TEST_EXIT_DBG(find(rankDOFs.begin(), rankDOFs.end(), dofs[i]) != rankDOFs.end())
863
864
	    ("Should never happen!\n");

865
	  DofContainer::iterator eraseIt = find(rankDOFs.begin(), rankDOFs.end(), dofs[i]);
866
867
868
	  if (eraseIt != rankDOFs.end())
	    rankDOFs.erase(eraseIt);

869
	  dofsToRecv.push_back(dofs[i]);
870
	}
Thomas Witkowski's avatar
Thomas Witkowski committed
871
872
873
      }
    }

874
875
876
877
878
    nRankDOFs = rankDOFs.size();

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

    int rstart = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
879
    mpiComm.Scan(&nRankDOFs, &rstart, 1, MPI_INT, MPI_SUM);
880
881
882
883
884
    rstart -= nRankDOFs;


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

Thomas Witkowski's avatar
Thomas Witkowski committed
885
    mpiComm.Allreduce(&nRankDOFs, &nOverallDOFs, 1, MPI_INT, MPI_SUM);
886
887


888
889
890
    // Do not change the indices now, but create a new indexing a store it here.
    DofIndexMap rankDofsNewLocalIndex;
    isRankDof.clear();
891
    int i = 0;
892
893
    for (DofContainer::iterator dofIt = rankAllDofs.begin();
	 dofIt != rankAllDofs.end(); ++dofIt) {
894

895
896
897
      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
898
      isRankDof[i] = true;
899
      i++;
900
901
    }

902
    // Stores for all rank owned dofs a new global index.
903
    DofIndexMap rankDofsNewGlobalIndex;
904
905
906
907
908
909
    // Stores for all rank owned dofs a continues local index.
    DofIndexMap rankOwnedDofsNewLocalIndex;

    i = 0;
    for (DofContainer::iterator dofIt = rankDOFs.begin();
	 dofIt != rankDOFs.end(); ++dofIt) {
910
      rankDofsNewGlobalIndex[*dofIt] = i + rstart;
911
912
913
914
915
      rankOwnedDofsNewLocalIndex[*dofIt] = i;
      i++;
    }


916
917
    // === Send new DOF indices. ===

918
919
    std::vector<int*> sendBuffers(sendDofs.size());
    std::vector<int*> recvBuffers(recvDofs.size());
920

921
    MPI::Request request[sendDofs.size() + recvDofs.size()];
Thomas Witkowski's avatar
Thomas Witkowski committed
922
923
    int requestCounter = 0;

924
    i = 0;
925
926
    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); ++sendIt, i++) {
927
928
929
      int nSendDofs = sendIt->second.size();
      sendBuffers[i] = new int[nSendDofs];
      int c = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
930
      for (DofContainer::iterator dofIt = sendIt->second.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
931
	   dofIt != sendIt->second.end(); ++dofIt)
932
	sendBuffers[i][c++] = rankDofsNewGlobalIndex[*dofIt];
933

Thomas Witkowski's avatar
Thomas Witkowski committed
934
935
      request[requestCounter++] = 
	mpiComm.Isend(sendBuffers[i], nSendDofs, MPI_INT, sendIt->first, 0);
936
937
938
    }

    i = 0;
939
940
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt, i++) {
941
942
943
      int nRecvDofs = recvIt->second.size();
      recvBuffers[i] = new int[nRecvDofs];
	
Thomas Witkowski's avatar
Thomas Witkowski committed
944
945
      request[requestCounter++] = 
	mpiComm.Irecv(recvBuffers[i], nRecvDofs, MPI_INT, recvIt->first, 0);
946
947
    }

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

950
951
    for (int j = 0; j < static_cast<int>(sendBuffers.size()); j++)
      delete [] sendBuffers[j];
952
953

    i = 0;
954
955
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt) {      
956
      int j = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
957
      for (DofContainer::iterator dofIt = recvIt->second.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
958
	   dofIt != recvIt->second.end(); ++dofIt) {
959

960
961
	rankDofsNewGlobalIndex[*dofIt] = recvBuffers[i][j];
	isRankDof[rankDofsNewLocalIndex[*dofIt]] = false;
962
963
964
965
	j++;
      }

      delete [] recvBuffers[i++];
966
967
    }

968

969
    // === Create now the local to global index and local to dof index mappings.  ===
970

971
972
973
    createLocalMappings(rankDofsNewLocalIndex, rankOwnedDofsNewLocalIndex,
			rankDofsNewGlobalIndex);
  }
974

975
976
977
978
  void ParallelDomainBase::createLocalMappings(DofIndexMap &rankDofsNewLocalIndex,
					       DofIndexMap &rankOwnedDofsNewLocalIndex,
					       DofIndexMap &rankDofsNewGlobalIndex)
  {
979
    mapLocalGlobalDOFs.clear();
980
    mapLocalToDofIndex.clear();
981
982
983
984

    for (DofIndexMap::iterator dofIt = rankDofsNewLocalIndex.begin();
	 dofIt != rankDofsNewLocalIndex.end(); ++dofIt) {
      DegreeOfFreedom localDof = dofIt->second;
985
      DegreeOfFreedom globalDof = rankDofsNewGlobalIndex[dofIt->first];
986
987
988
989
990
991
992
993

      *const_cast<DegreeOfFreedom*>(dofIt->first) = localDof;
      mapLocalGlobalDOFs[localDof] = globalDof;
    }

    for (DofIndexMap::iterator dofIt = rankOwnedDofsNewLocalIndex.begin();
	 dofIt != rankOwnedDofsNewLocalIndex.end(); ++dofIt)
      mapLocalToDofIndex[dofIt->second] = *(dofIt->first);
994
995
  }

Thomas Witkowski's avatar
Thomas Witkowski committed
996
997
  void ParallelDomainBase::addAllVertexDOFs(Element *el, int ithEdge, 
					    DofContainer& dofs)
998
  {
Thomas Witkowski's avatar
Thomas Witkowski committed
999
    FUNCNAME("ParallelDomainBase::addAllVertexDOFs()");
1000