ParallelDomainBase.cc 53 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 "SystemVector.h"
14
#include "VtkWriter.h"
15
#include "ElementDofIterator.h"
16
17
#include "ProblemStatBase.h"
#include "StandardProblemIteration.h"
18
#include "ElementFileWriter.h"
19
20

#include "petscksp.h"
21
22
23

namespace AMDiS {

24
  PetscErrorCode myKSPMonitor(KSP ksp, PetscInt iter, PetscReal rnorm, void *)
25
  {    
26
    //    if (iter % 100 == 0 && MPI::COMM_WORLD.Get_rank() == 0)
Thomas Witkowski's avatar
Thomas Witkowski committed
27
      std::cout << "  Petsc-Iteration " << iter << ": " << rnorm << std::endl;
28
29
30
31

    return 0;
  }

32
33
34
35
36
  inline bool cmpDofsByValue(const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2)
  {
    return (*dof1 < *dof2);
  }

Thomas Witkowski's avatar
Thomas Witkowski committed
37
  ParallelDomainBase::ParallelDomainBase(std::string name,
38
39
40
41
					 ProblemIterationInterface *iIF,
					 ProblemTimeInterface *tIF,
					 FiniteElemSpace *fe,
					 RefinementManager *refineManager)
42
43
    : iterationIF(iIF),
      timeIF(tIF),
44
45
      feSpace(fe),
      mesh(fe->getMesh()),
46
      refinementManager(refineManager),
47
      initialPartitionMesh(true),
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
48
      nRankDOFs(0),
49
50
      rstart(0),
      nComponents(1)
51
  {
Thomas Witkowski's avatar
Thomas Witkowski committed
52
53
54
55
56
57
58
    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");

59
60
61
62
63
64
    mpiRank = MPI::COMM_WORLD.Get_rank();
    mpiSize = MPI::COMM_WORLD.Get_size();
    mpiComm = MPI::COMM_WORLD;
    partitioner = new ParMetisPartitioner(mesh, &mpiComm);
  }

65
  void ParallelDomainBase::initParallelization(AdaptInfo *adaptInfo)
66
67
68
69
  {
    if (mpiSize <= 1)
      return;

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#if 0
    if (mpiRank == 0) {
      std::map<int, double> vec;
      
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1,
					   Mesh::CALL_LEAF_EL | Mesh::FILL_NEIGH);
      while (elInfo) {
	vec[elInfo->getElement()->getIndex()] = static_cast<double>(elInfo->getElement()->getIndex());
	elInfo = stack.traverseNext(elInfo);
      }

      ElementFileWriter::writeFile(vec, feSpace, "test.vtu");
    }
#endif


87
88
89
90
91
    // 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();

92
93
94
95
96
97
98
    // 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
99
100
101
102
#if (DEBUG != 0)
    ElementIdxToDofs elMap;
    DbgCreateElementMap(elMap);
#endif
103

104
    // === Create new global and local DOF numbering. ===
105

106
107
108
    // 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
109
    nRankDOFs = 0;
110
    // Number of all DOFs in the macro mesh.
111
    int nOverallDOFs = 0;
112

113
    createLocalGlobalNumbering(rankDOFs, nRankDOFs, nOverallDOFs);
114

Thomas Witkowski's avatar
Thomas Witkowski committed
115
116
    // === Create interior boundary information ===

117
    createInteriorBoundaryInfo(rankDOFs);
Thomas Witkowski's avatar
Thomas Witkowski committed
118

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
119
120
121
122
    // === Remove all macro elements that are not part of the rank partition. ===

    removeMacroElements();

Thomas Witkowski's avatar
Thomas Witkowski committed
123
#if (DEBUG != 0)
Thomas Witkowski's avatar
Thomas Witkowski committed
124
    DbgTestElementMap(elMap);
Thomas Witkowski's avatar
Thomas Witkowski committed
125
126
    DbgTestInteriorBoundary();
#endif
Thomas Witkowski's avatar
Thomas Witkowski committed
127

128

129
    // === Reset all DOFAdmins of the mesh. ===
130

131
    updateDofAdmins();
132

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#if 0
    if (mpiRank == 0) {
      TraverseStack stack;
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
      while (elInfo) {
	if (elInfo->getElement()->getIndex() == 4) {
	  WorldVector<double> x;
	  mesh->getDofIndexCoords(elInfo->getElement()->getDOF(0), feSpace, x);
	  std::cout << "FOUND!" << std::endl;
	  x.print();
	}

	elInfo = stack.traverseNext(elInfo);
      }
    }
#endif

150

151
    // === Global refinements. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
152

Thomas Witkowski's avatar
Thomas Witkowski committed
153
154
155
    int globalRefinement = 0;
    GET_PARAMETER(0, "testgr", "%d", &globalRefinement);

Thomas Witkowski's avatar
Thomas Witkowski committed
156
157
    if (globalRefinement > 0) {
      refinementManager->globalRefine(mesh, globalRefinement);
158

159
160
161
162
163
#if (DEBUG != 0)
      elMap.clear();
      DbgCreateElementMap(elMap);
#endif

Thomas Witkowski's avatar
Thomas Witkowski committed
164
      updateLocalGlobalNumbering(nRankDOFs, nOverallDOFs);
165
166
167
168
169
170

      updateDofAdmins();

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

173

Thomas Witkowski's avatar
Thomas Witkowski committed
174
#if (DEBUG != 0)
175
    DbgTestCommonDofs(true);
Thomas Witkowski's avatar
Thomas Witkowski committed
176
#endif
177

178

179
    // === Create petsc matrix. ===
180

181
182
    int nRankRows = nRankDOFs * nComponents;
    int nOverallRows = nOverallDOFs * nComponents;
183

184
185
186
    MatCreate(PETSC_COMM_WORLD, &petscMatrix);
    MatSetSizes(petscMatrix, nRankRows, nRankRows, nOverallRows, nOverallRows);
    MatSetType(petscMatrix, MATAIJ);
187

188
189
190
191
192
193
194
    VecCreate(PETSC_COMM_WORLD, &petscRhsVec);
    VecSetSizes(petscRhsVec, nRankRows, nOverallRows);
    VecSetType(petscRhsVec, VECMPI);

    VecCreate(PETSC_COMM_WORLD, &petscSolVec);
    VecSetSizes(petscSolVec, nRankRows, nOverallRows);
    VecSetType(petscSolVec, VECMPI);
195
196
  }

197
198
199

  void ParallelDomainBase::exitParallelization(AdaptInfo *adaptInfo)
  {
200
201
202
    MatDestroy(petscMatrix);
    VecDestroy(petscRhsVec);
    VecDestroy(petscSolVec);
203
  }
204

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  
  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());
    }
  }

223

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  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");
  }

245
246
  void ParallelDomainBase::setDofMatrix(DOFMatrix* mat, int dispMult, 
					int dispAddRow, int dispAddCol)
247
  {
248
249
250
251
    FUNCNAME("ParallelDomainBase::setDofMatrix()");

    TEST_EXIT(mat)("No DOFMatrix!\n");

252
253
254
255
256
257
258
259
260
261
262
    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;

263
264
265
266
    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)
267
	if (value(*icursor) != 0.0) {
268
269
 	  int r = mapLocalGlobalDOFs[row(*icursor)] * dispMult + dispAddRow;
 	  int c = mapLocalGlobalDOFs[col(*icursor)] * dispMult + dispAddCol;  
270
	  double v = value(*icursor);
271

272
	  MatSetValues(petscMatrix, 1, &r, 1, &c, &v, ADD_VALUES);
273
	}
274
  }
275

276

277
278
279
  void ParallelDomainBase::setDofVector(DOFVector<double>* vec, 
					int dispMult, int dispAdd)
  {
280
281
    DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
    for (dofIt.reset(); !dofIt.end(); ++dofIt) {
282
      int index = mapLocalGlobalDOFs[dofIt.getDOFIndex()] * dispMult + dispAdd;
283
284
285
      double value = *dofIt;

      VecSetValues(petscRhsVec, 1, &index, &value, ADD_VALUES);
286
    }    
287
288
  }

289

290
291
292
293
294
295
296
  void ParallelDomainBase::fillPetscMatrix(DOFMatrix *mat, DOFVector<double> *vec)
  {
    setDofMatrix(mat);

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

Thomas Witkowski's avatar
Thomas Witkowski committed
297
298
299
300
    setDofVector(vec);

    VecAssemblyBegin(petscRhsVec);
    VecAssemblyEnd(petscRhsVec);
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  }

  
  void ParallelDomainBase::fillPetscMatrix(Matrix<DOFMatrix*> *mat, SystemVector *vec)
  {
    using mtl::tag::major; using mtl::tag::nz; using mtl::begin; using mtl::end;
    namespace traits= mtl::traits;
    typedef DOFMatrix::base_matrix_type Matrix;

    for (int i = 0; i < nComponents; i++)
      for (int j = 0; j < nComponents; j++)
	if ((*mat)[i][j]) 
	  setDofMatrix((*mat)[i][j], nComponents, i, j);

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

    for (int i = 0; i < nComponents; i++)
      setDofVector(vec->getDOFVector(i), nComponents, i);
  }


323
  void ParallelDomainBase::solvePetscMatrix(DOFVector<double> *vec)
324
  {
Thomas Witkowski's avatar
Thomas Witkowski committed
325
326
    FUNCNAME("ParallelDomainBase::solvePetscMatrix()");

327
328
329
330
331
332
    KSP ksp;
    PC pc;

    KSPCreate(PETSC_COMM_WORLD, &ksp);
    KSPSetOperators(ksp, petscMatrix, petscMatrix, DIFFERENT_NONZERO_PATTERN);
    KSPGetPC(ksp, &pc);
Thomas Witkowski's avatar
Thomas Witkowski committed
333
334
    PCSetType(pc, PCJACOBI);
    //    PCSetType(pc, PCILU);
335
    KSPSetTolerances(ksp, 1.e-7, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
336
337
    KSPSetType(ksp, KSPBCGS);
    //KSPSetType(ksp, KSPCG);
338
    KSPMonitorSet(ksp, myKSPMonitor, PETSC_NULL, 0);
339
340
    KSPSolve(ksp, petscRhsVec, petscSolVec);

Thomas Witkowski's avatar
Thomas Witkowski committed
341
342
343
344
345
346
#if (DEBUG != 0)
    int size = 0;
    VecGetLocalSize(petscSolVec, &size);
    TEST_EXIT(size == nRankDOFs)("Vector and rank DOFs does not fit together!\n");
#endif

347
348
349
    PetscScalar *vecPointer;
    VecGetArray(petscSolVec, &vecPointer);

Thomas Witkowski's avatar
Thomas Witkowski committed
350
    for (int i = 0; i < nRankDOFs; i++)
351
      (*vec)[mapLocalToDofIndex[i]] = vecPointer[i];
352
353
354

    VecRestoreArray(petscSolVec, &vecPointer);

355
356
    std::vector<double*> sendBuffers(sendDofs.size());
    std::vector<double*> recvBuffers(recvDofs.size());
Thomas Witkowski's avatar
Thomas Witkowski committed
357
358
359

    MPI::Request request[sendDofs.size() + recvDofs.size()];
    int requestCounter = 0;
360
361
    
    int i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
362
    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
363
	 sendIt != sendDofs.end(); ++sendIt, i++) {
364
365
      int nSendDOFs = sendIt->second.size();
      sendBuffers[i] = new double[nSendDOFs];
366

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

Thomas Witkowski's avatar
Thomas Witkowski committed
370
371
      request[requestCounter++] =
	mpiComm.Isend(sendBuffers[i], nSendDOFs, MPI_DOUBLE, sendIt->first, 0);
372
373
374
    }

    i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
375
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
376
	 recvIt != recvDofs.end(); ++recvIt, i++) {
377
378
      int nRecvDOFs = recvIt->second.size();
      recvBuffers[i] = new double[nRecvDOFs];
379

Thomas Witkowski's avatar
Thomas Witkowski committed
380
381
      request[requestCounter++] =
	mpiComm.Irecv(recvBuffers[i], nRecvDOFs, MPI_DOUBLE, recvIt->first, 0);
382
383
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
384
385
386

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

387
    i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
388
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
389
	 recvIt != recvDofs.end(); ++recvIt, i++) {
Thomas Witkowski's avatar
Thomas Witkowski committed
390
      for (int j = 0; j < static_cast<int>(recvIt->second.size()); j++)
Thomas Witkowski's avatar
Thomas Witkowski committed
391
	(*vec)[*(recvIt->second)[j]] = recvBuffers[i][j];
392
393
394
395

      delete [] recvBuffers[i];
    }
    
396
    for (int i = 0; i < static_cast<int>(sendBuffers.size()); i++)
397
      delete [] sendBuffers[i];
398
399
  }

400

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  void ParallelDomainBase::solvePetscMatrix(SystemVector *vec)
  {
    FUNCNAME("ParallelDomainBase::solvePetscMatrix()");

    KSP ksp;
    PC pc;

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

#if (DEBUG != 0)
    int size = 0;
    VecGetLocalSize(petscSolVec, &size);
422
423
    TEST_EXIT(size == nRankDOFs * nComponents)
      ("Vector and rank DOFs does not fit together!\n");
424
425
426
427
428
429
430
431
432
433
434
435
436
#endif

    PetscScalar *vecPointer;
    VecGetArray(petscSolVec, &vecPointer);

    for (int i = 0; i < nComponents; i++) {
      DOFVector<double> *dofvec = vec->getDOFVector(i);
      for (int j = 0; j < nRankDOFs; j++)
	(*dofvec)[mapLocalToDofIndex[j]] = vecPointer[j * nComponents + i];
    }

    VecRestoreArray(petscSolVec, &vecPointer);

437

438
439
440
441
442
443
444
445
446
    std::vector<double*> sendBuffers(sendDofs.size());
    std::vector<double*> recvBuffers(recvDofs.size());

    MPI::Request request[sendDofs.size() + recvDofs.size()];
    int requestCounter = 0;
    
    int i = 0;
    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); ++sendIt, i++) {
447
448
      int nSendDOFs = sendIt->second.size();
      sendBuffers[i] = new double[nSendDOFs * nComponents];
449
450
451
452
453
454
455
456

      int counter = 0;
      for (int j = 0; j < nComponents; j++) {
	DOFVector<double> *dofvec = vec->getDOFVector(j);
	for (int k = 0; k < nSendDOFs; k++)
	  sendBuffers[i][counter++] = (*dofvec)[*((sendIt->second)[k])];
      }

457
458
      request[requestCounter++] = mpiComm.Isend(sendBuffers[i], nSendDOFs * nComponents,
						MPI_DOUBLE, sendIt->first, 0);
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
    }

    i = 0;
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt, i++) {
      int nRecvDOFs = recvIt->second.size() * nComponents;
      recvBuffers[i] = new double[nRecvDOFs];

      request[requestCounter++] =
	mpiComm.Irecv(recvBuffers[i], nRecvDOFs, MPI_DOUBLE, recvIt->first, 0);
    }


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

    i = 0;
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt, i++) {
      int nRecvDOFs = recvIt->second.size();

      int counter = 0;
      for (int j = 0; j < nComponents; j++) {
	DOFVector<double> *dofvec = vec->getDOFVector(j);
482
483
 	for (int k = 0; k < nRecvDOFs; k++)
 	  (*dofvec)[*(recvIt->second)[k]] = recvBuffers[i][counter++];
484
485
486
487
488
489
490
491
492
493
      }

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


494
  double ParallelDomainBase::setElemWeights(AdaptInfo *adaptInfo) 
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  {
    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
515
	TEST_EXIT_DBG(elNum != -1)("invalid element number\n");
516
517
518
519
520
521
522
523
524
525
526
527
	if (element->isLeaf()) {
	  elemWeights[elNum] += 1.0;
	  localWeightSum += 1.0;
	}
      }

      elInfo = stack.traverseNext(elInfo);
    }

    return localWeightSum;
  }

528

529
  void ParallelDomainBase::partitionMesh(AdaptInfo *adaptInfo)
530
531
532
533
534
535
536
537
538
539
540
541
542
  {
    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);
  }

543

544
  void ParallelDomainBase::createInteriorBoundaryInfo(DofContainer& rankDOFs)
545
  {
546
    FUNCNAME("ParallelDomainBase::createInteriorBoundaryInfo()");
Thomas Witkowski's avatar
Thomas Witkowski committed
547
548
549

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

550
    TraverseStack stack;
551
552
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, 
					 Mesh::CALL_LEAF_EL | Mesh::FILL_NEIGH);
553
554
555
556
557
558
559
560
561
562
563
564
    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));
565

566
 	  if (neighbourPartitionData->getPartitionStatus() == OUT) {
567
568
	    // We have found an element that is at an interior boundary. 

569
570
	    // === 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. ===
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595

	    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;

596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
#if 0
	    if (mpiRank == 3 && ranksBoundary && 
		partitionVec[elInfo->getNeighbour(i)->getIndex()] == 2) {
	      std::cout << "ADD MY BOUND " << element->getIndex() << "/" << i 
			<< "  with  " 
			<< elInfo->getNeighbour(i)->getIndex() << "/"
			<< elInfo->getSideOfNeighbour(i) << std::endl;
	    }

	    if (mpiRank == 2 && !ranksBoundary && 
		partitionVec[elInfo->getNeighbour(i)->getIndex()] == 3) {
	      std::cout << "ADD OT BOUND " << element->getIndex() << "/" << i 
			<< "  with  " 
			<< elInfo->getNeighbour(i)->getIndex() << "/"
			<< elInfo->getSideOfNeighbour(i) << std::endl;
	    }
#endif

614
	    // === And add the part of the interior boundary. ===
615
616

	    AtomicBoundary& bound = 
Thomas Witkowski's avatar
Thomas Witkowski committed
617
618
619
620
	      (ranksBoundary ?
	       myIntBoundary.getNewAtomicBoundary(partitionVec[elInfo->getNeighbour(i)->getIndex()]) :
	       otherIntBoundary.getNewAtomicBoundary(partitionVec[elInfo->getNeighbour(i)->getIndex()]));

621
	    bound.rankObject.el = element;
622
	    bound.rankObject.elIndex = element->getIndex();
623
624
	    bound.rankObject.subObjAtBoundary = EDGE;
	    bound.rankObject.ithObjAtBoundary = i;
625
626
627
628
	    // Do not set a pointer to the element, because if will be deleted from
	    // mesh after partitioning and the pointer would become invalid.
	    bound.neighbourObject.el = NULL;
	    bound.neighbourObject.elIndex = elInfo->getNeighbour(i)->getIndex();
629
	    bound.neighbourObject.subObjAtBoundary = EDGE;
630
631
632
633
634
	    bound.neighbourObject.ithObjAtBoundary = elInfo->getSideOfNeighbour(i);

	    // i == 2  =>  getSideOfNeighbour(i) == 2
	    TEST_EXIT_DBG(i != 2 || elInfo->getSideOfNeighbour(i) == 2)
	      ("Should not happen!\n");
635
636
637
638
639
640
 	  }
	}
      }

      elInfo = stack.traverseNext(elInfo);
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
641
642
643


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

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

Thomas Witkowski's avatar
Thomas Witkowski committed
649
650
651
652
    MPI::Request request[myIntBoundary.boundary.size() + 
			 otherIntBoundary.boundary.size()];
    int requestCounter = 0;

Thomas Witkowski's avatar
Thomas Witkowski committed
653
654
    for (RankToBoundMap::iterator rankIt = myIntBoundary.boundary.begin();
	 rankIt != myIntBoundary.boundary.end(); ++rankIt) {    
Thomas Witkowski's avatar
Thomas Witkowski committed
655
      int nSendInt = rankIt->second.size();
656
657
658
659
660
      int* buffer = new int[nSendInt * 2];
      for (int i = 0; i < nSendInt; i++) {
	buffer[i * 2] = (rankIt->second)[i].rankObject.elIndex;
	buffer[i * 2 + 1] = (rankIt->second)[i].rankObject.ithObjAtBoundary;
      }
Thomas Witkowski's avatar
Thomas Witkowski committed
661
662
      sendBuffers.push_back(buffer);
      
Thomas Witkowski's avatar
Thomas Witkowski committed
663
      request[requestCounter++] =
664
	mpiComm.Isend(buffer, nSendInt * 2, MPI_INT, rankIt->first, 0);
Thomas Witkowski's avatar
Thomas Witkowski committed
665
666
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
667
668
    for (RankToBoundMap::iterator rankIt = otherIntBoundary.boundary.begin();
	 rankIt != otherIntBoundary.boundary.end(); ++rankIt) {
Thomas Witkowski's avatar
Thomas Witkowski committed
669
      int nRecvInt = rankIt->second.size();
670
      int *buffer = new int[nRecvInt * 2];
Thomas Witkowski's avatar
Thomas Witkowski committed
671
      recvBuffers.push_back(buffer);
Thomas Witkowski's avatar
Thomas Witkowski committed
672

Thomas Witkowski's avatar
Thomas Witkowski committed
673
      request[requestCounter++] = 
674
	mpiComm.Irecv(buffer, nRecvInt * 2, MPI_INT, rankIt->first, 0);
Thomas Witkowski's avatar
Thomas Witkowski committed
675
676
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
677
678
679

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

Thomas Witkowski's avatar
Thomas Witkowski committed
680
681

    int i = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
682
683
    for (RankToBoundMap::iterator rankIt = otherIntBoundary.boundary.begin();
	 rankIt != otherIntBoundary.boundary.end(); ++rankIt) {
Thomas Witkowski's avatar
Thomas Witkowski committed
684
685
686
687
688
689
690

      // === 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.
691
692
	if ((rankIt->second)[j].neighbourObject.elIndex != recvBuffers[i][j * 2] ||
	    (rankIt->second)[j].neighbourObject.ithObjAtBoundary != recvBuffers[i][j * 2 + 1]) {
Thomas Witkowski's avatar
Thomas Witkowski committed
693
694
	  int k = j + 1;
	  for (; k < static_cast<int>(rankIt->second.size()); k++)
695
696
	    if ((rankIt->second)[k].neighbourObject.elIndex == recvBuffers[i][j * 2] && 
		(rankIt->second)[k].neighbourObject.ithObjAtBoundary == recvBuffers[i][j * 2 + 1])
Thomas Witkowski's avatar
Thomas Witkowski committed
697
698
699
	      break;

	  // The element must always be found, because the list is just in another order.
Thomas Witkowski's avatar
Thomas Witkowski committed
700
	  TEST_EXIT_DBG(k < static_cast<int>(rankIt->second.size()))
701
	    ("Should never happen!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
702
703
704
705
706
707
708
709
710
711
712
713
714

	  // 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];
715
716
717
  }


718
  void ParallelDomainBase::removeMacroElements()
719
720
721
722
723
724
725
726
727
728
729
730
  {
    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
731
    mesh->removeMacroElements(macrosToRemove, feSpace);
732
733
734
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
735
736
737
  void ParallelDomainBase::createLocalGlobalNumbering(DofContainer& rankDOFs,
						      int& nRankDOFs, 
						      int& nOverallDOFs)
738
  {
739
    FUNCNAME("ParallelDomainBase::createLocalGlobalNumbering()");
740
741

    // === Get rank information about DOFs. ===
742
743
744

    // 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
745
    DofContainer rankAllDofs;
746
    DofToRank boundaryDofs;
747

748
    createDOFMemberInfo(partitionDOFs, rankDOFs, rankAllDofs, boundaryDofs);
749
750
751
752

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

753

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

756
    rstart = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
757
    mpiComm.Scan(&nRankDOFs, &rstart, 1, MPI_INT, MPI_SUM);
758
759
    rstart -= nRankDOFs;

760
761
762
763
    
    // === 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
764

Thomas Witkowski's avatar
Thomas Witkowski committed
765

766
767
768
    // 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
769
770
771
    int i = 0;
    for (DofContainer::iterator dofIt = rankAllDofs.begin();
	 dofIt != rankAllDofs.end(); ++dofIt) {
Thomas Witkowski's avatar
Thomas Witkowski committed
772
773
774
775
776
777
778
779
780
781

#if 0
      if (mpiRank == 0) {
	std::cout << "COORDs of dof = " << i << std::endl;
	WorldVector<double> x;
	mesh->getDofIndexCoords(*dofIt, feSpace, x);
	x.print();	
      }
#endif

782
783
784
      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
785
      isRankDof[i] = true;
786
      i++;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
787
788
    }

789
790
791

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

792
793
    // Stores for dofs in rank a new global index.
    DofIndexMap rankDofsNewGlobalIndex;
794
795
796
    // Stores for all rank owned dofs a continues local index.
    DofIndexMap rankOwnedDofsNewLocalIndex;

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
797
798
799
    i = 0;
    for (DofContainer::iterator dofIt = rankDOFs.begin();
	 dofIt != rankDOFs.end(); ++dofIt) {
800
      rankDofsNewGlobalIndex[*dofIt] = i + rstart;
801
      rankOwnedDofsNewLocalIndex[*dofIt] = i;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
802
803
804
      i++;
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
805
 
806
807
808
809
810
811
    // === 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;
812

813
814
815
816
    // 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;
817

818
    for (DofToRank::iterator it = boundaryDofs.begin(); it != boundaryDofs.end(); ++it) {
819
820
821
822
823
824
825
826

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

831
	    sendNewDofs[*itRanks][it->first] = rankDofsNewGlobalIndex[it->first];
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
832
	  }
833
834
	}
      } else {
Thomas Witkowski's avatar
Thomas Witkowski committed
835
836
	// 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.
837
838
839
840
	if (recvNewDofs.find(it->second) == recvNewDofs.end()) 
	  recvNewDofs[it->second] = 1;
	else
	  recvNewDofs[it->second]++;
841
842
843
      }
    }

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
844

845
    // === Send and receive the dof indices at boundary. ===
846

Thomas Witkowski's avatar
Thomas Witkowski committed
847
    std::vector<int*> sendBuffers(sendNewDofs.size()), recvBuffers(recvNewDofs.size());
848
849
850

    sendDofs.clear();
    recvDofs.clear();
851
    
Thomas Witkowski's avatar
Thomas Witkowski committed
852
853
854
    MPI::Request request[sendNewDofs.size() + recvNewDofs.size()];
    int requestCounter = 0;

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
855
    i = 0;
856
857
    for (std::map<int, std::map<const DegreeOfFreedom*, DegreeOfFreedom> >::iterator 
	   sendIt = sendNewDofs.begin();
858
859
	 sendIt != sendNewDofs.end();
	 ++sendIt, i++) {
860
861
      int nSendDofs = sendIt->second.size() * 2;
      sendBuffers[i] = new int[nSendDofs];
862

863
      int c = 0;
864
865
      for (std::map<const DegreeOfFreedom*, DegreeOfFreedom>::iterator 
	     dofIt = sendIt->second.begin();
866
	   dofIt != sendIt->second.end();
867
	   ++dofIt) {
Thomas Witkowski's avatar
Thomas Witkowski committed
868
	sendBuffers[i][c++] = *(dofIt->first);
869
	sendBuffers[i][c++] = dofIt->second;
870

871
872
873
874
875
#if 0
	if (mpiRank == 3 && sendIt->first == 2)
	  std::cout << "SEND DOF: " << dofIt->first << std::endl;
#endif

876
	sendDofs[sendIt->first].push_back(dofIt->first);
877
878
      }

Thomas Witkowski's avatar
Thomas Witkowski committed
879
880
      request[requestCounter++] =
	mpiComm.Isend(sendBuffers[i], nSendDofs, MPI_INT, sendIt->first, 0);
881
882
883
    }

    i = 0;
884
    for (std::map<int, int>::iterator recvIt = recvNewDofs.begin();
885
886
	 recvIt != recvNewDofs.end();
	 ++recvIt, i++) {
887
888
      int nRecvDOFs = recvIt->second * 2;
      recvBuffers[i] = new int[nRecvDOFs];
889

Thomas Witkowski's avatar
Thomas Witkowski committed
890
891
      request[requestCounter++] =
	mpiComm.Irecv(recvBuffers[i], nRecvDOFs, MPI_INT, recvIt->first, 0);
892
893
894
    }


Thomas Witkowski's avatar
Thomas Witkowski committed
895
    MPI::Request::Waitall(requestCounter, request);
896
897

    
898
    // === Delete send buffers. ===
899

Thomas Witkowski's avatar
Thomas Witkowski committed
900
901
    for (int j = 0; j < static_cast<int>(sendBuffers.size()); j++)
      delete [] sendBuffers[j];
902
903


904
    // === Change dof indices at boundary from other ranks. ===
905

Thomas Witkowski's avatar
Thomas Witkowski committed
906
907
    // 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
908
    // 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
909
910
911
912
913
    // 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;
914
    for (DofToRank::iterator dofIt = boundaryDofs.begin(); dofIt != boundaryDofs.end();
Thomas Witkowski's avatar
Thomas Witkowski committed
915
	 ++dofIt)
Thomas Witkowski's avatar
Thomas Witkowski committed
916
917
      dofChanged[dofIt->first] = false;

918
    i = 0;
919
    for (std::map<int, int>::iterator recvIt = recvNewDofs.begin();
920
921
922
	 recvIt != recvNewDofs.end();
	 ++recvIt, i++) {

923
      for (int j = 0; j < recvIt->second; j++) {
924

925
926
	DegreeOfFreedom oldDof = recvBuffers[i][j * 2];
	DegreeOfFreedom newGlobalDof = recvBuffers[i][j * 2 + 1];
927

928
	bool found = false;
929

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

932
933
	for (DofToRank::iterator dofIt = boundaryDofs.begin(); 
	     dofIt != boundaryDofs.end(); ++dofIt) {
934

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

938
939
940
941
942
#if 0
	    if (mpiRank == 2 && recvIt->first == 3)
	      std::cout << "RECV DOF: " << dofIt->first << std::endl;
#endif
	
943
	    recvDofs[recvIt->first].push_back(dofIt->first);
944
	    rankDofsNewGlobalIndex[dofIt->first] = newGlobalDof;
Thomas Witkowski's avatar
n    
Thomas Witkowski committed
945
	    isRankDof[rankDofsNewLocalIndex[dofIt->first]] = false;
Thomas Witkowski's avatar
Thomas Witkowski committed
946

947
	    found = true;
948
949
950
	    break;
	  }
	}
951

Thomas Witkowski's avatar
Thomas Witkowski committed
952
	TEST_EXIT_DBG(found)("Should not happen!\n");
953
954
955
956
      }

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

958
    // === Create now the local to global index and local to dof index mappings.  ===
959

960
961
    createLocalMappings(rankDofsNewLocalIndex, rankOwnedDofsNewLocalIndex,
			rankDofsNewGlobalIndex);
962
963
964
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
965
  void ParallelDomainBase::updateLocalGlobalNumbering(int& nRankDOFs, int& nOverallDOFs)
966
  {
967
    FUNCNAME("ParallelDomainBase::updateLocalGlobalNumbering()");
Thomas Witkowski's avatar
Thomas Witkowski committed
968

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

971
    // === Get all DOFs in ranks partition. ===
972

Thomas Witkowski's avatar
Thomas Witkowski committed
973
    ElementDofIterator elDofIt(feSpace);
974
    DofSet rankDOFSet;
975
976
977
    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
    while (elInfo) {
Thomas Witkowski's avatar
Thomas Witkowski committed
978
      Element *element = elInfo->getElement();     
Thomas Witkowski's avatar
Thomas Witkowski committed
979
980
      elDofIt.reset(element);
      do {
981
	rankDOFSet.insert(elDofIt.getDofPtr());
Thomas Witkowski's avatar
Thomas Witkowski committed
982
      } while(elDofIt.next());
983
984
985
986

      elInfo = stack.traverseNext(elInfo);
    }

987
    DofContainer rankAllDofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
988
989
    for (DofSet::iterator dofIt = rankDOFSet.begin(); dofIt != rankDOFSet.end(); ++dofIt)
      rankAllDofs.push_back(*dofIt);    
990
991
992
993
    sort(rankAllDofs.begin(), rankAllDofs.end(), cmpDofsByValue);
    DofContainer rankDOFs = rankAllDofs;


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

997
998
    sendDofs.clear();
    recvDofs.clear();
999

Thomas Witkowski's avatar
Thomas Witkowski committed
1000
1001
1002
    for (RankToBoundMap::iterator it =  myIntBoundary.boundary.begin();
	 it != myIntBoundary.boundary.end(); ++it) {

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

1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
#if 0
	if (mpiRank == 3 && it->first == 2) 
	  std::cout << "GO ON MY BOUND: " << boundIt->rankObject.elIndex 
		    << "/" << boundIt->rankObject.ithObjAtBoundary << " with "
		    << boundIt->neighbourObject.elIndex << "/"
		    << boundIt->neighbourObject.ithObjAtBoundary
		    << std::endl;
#endif


1016
1017
	DofContainer dofs;
	DofContainer &dofsToSend = sendDofs[it->first];
Thomas Witkowski's avatar
Thomas Witkowski committed
1018
1019
1020

	switch (boundIt->rankObject.ithObjAtBoundary) {
	case 0:
1021
1022
	  dofs.push_back(boundIt->rankObject.el->getDOF(1));
	  dofs.push_back(boundIt->rankObject.el->getDOF(2));
Thomas Witkowski's avatar
Thomas Witkowski committed
1023
1024
	  break;
	case 1:
1025
1026
	  dofs.push_back(boundIt->rankObject.el->getDOF(0));
	  dofs.push_back(boundIt->rankObject.el->getDOF(2));
Thomas Witkowski's avatar
Thomas Witkowski committed
1027
1028
	  break;
	case 2:
1029
1030
	  dofs.push_back(boundIt->rankObject.el->getDOF(0));
	  dofs.push_back(boundIt->rankObject.el->getDOF(1));
Thomas Witkowski's avatar
Thomas Witkowski committed
1031
1032
1033
1034
1035
	  break;
	default:
	  ERROR_EXIT("Should never happen!\n");
	}

1036
1037
1038
1039
1040
1041
1042
#if 0
	if (mpiRank == 3 && it->first == 2) {
	  WorldVector<double> x;
	  mesh->getDofIndexCoords(dofs[0], feSpace, x);
	  x.print();
	  mesh->getDofIndexCoords(dofs[1], feSpace, x);
	  x.print();
1043
	}
1044
1045
1046
1047
1048
1049
#endif
	

	for (DofContainer::iterator dofIt = dofs.begin(); dofIt != dofs.end(); ++dofIt)
	  if (find(dofsToSend.begin(), dofsToSend.end(), *dofIt) == dofsToSend.end())
	    dofsToSend.push_back(*dofIt);	
1050

1051
1052
1053
1054
1055
	dofs.clear();
	addAllVertexDOFs(boundIt->rankObject.el, boundIt->rankObject.ithObjAtBoundary,
			 dofs);	
  	addAllEdgeDOFs(boundIt->rankObject.el, boundIt->rankObject.ithObjAtBoundary,
  		       dofs);
1056
	for (int i = 0; i < static_cast<int>(dofs.size()); i++)
1057
	  dofsToSend.push_back(dofs[i]);
1058
      }
1059
1060
1061
    }

    
1062

Thomas Witkowski's avatar
Thomas Witkowski committed
1063
1064
1065
    for (RankToBoundMap::iterator it = otherIntBoundary.boundary.begin();
	 it != otherIntBoundary.boundary.end(); ++it) {

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

1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
#if 0
	if (mpiRank == 2 && it->first == 3) 
	  std::cout << "GO ON OT BOUND: " << boundIt->rankObject.elIndex 
		    << "/" << boundIt->rankObject.ithObjAtBoundary << " with "
		    << boundIt->neighbourObject.elIndex << "/"
		    << boundIt->neighbourObject.ithObjAtBoundary
		    << std::endl;
#endif


1079
1080
	DofContainer dofs;
	DofContainer &dofsToRecv = recvDofs[it->first];
1081
1082
1083

	switch (boundIt->rankObject.ithObjAtBoundary) {
	case 0:
1084
1085
1086
1087
1088
1089
1090
	  if (boundIt->neighbourObject.ithObjAtBoundary == 0) {
	    dofs.push_back(boundIt->rankObject.el->getDOF(2));
	    dofs.push_back(boundIt->rankObject.el->getDOF(1));
	  } else {
	    dofs.push_back(boundIt->rankObject.el->getDOF(1));
	    dofs.push_back(boundIt->rankObject.el->getDOF(2));
	  }
1091
1092
	  break;
	case 1:
1093
1094
1095
1096
1097
1098
1099
	  if (boundIt->neighbourObject.ithObjAtBoundary == 0) {
	    dofs.push_back(boundIt->rankObject.el->getDOF(0));
	    dofs.push_back(boundIt->rankObject.el->getDOF(2));
	  } else {
	    dofs.push_back(boundIt->rankObject.el->getDOF(2));
	    dofs.push_back(boundIt->rankObject.el->getDOF(0));
	  }
1100
1101
	  break;
	case 2:
1102