MeshDistributor.cc 71.7 KB
Newer Older
Thomas Witkowski's avatar
Thomas Witkowski committed
1
#include <algorithm>
2
3
#include <iostream>
#include <fstream>
4
5
#include <limits>
#include <stdint.h>
Thomas Witkowski's avatar
Thomas Witkowski committed
6
#include <boost/lexical_cast.hpp>
7
8
#include <boost/filesystem.hpp>

9
#include "parallel/MeshDistributor.h"
10
#include "parallel/MeshManipulation.h"
11
#include "parallel/ParallelDebug.h"
12
#include "parallel/StdMpi.h"
13
#include "parallel/ParMetisPartitioner.h"
14
15
16
#include "io/ElementFileWriter.h"
#include "io/MacroInfo.h"
#include "io/VtkWriter.h"
17
18
19
20
21
#include "Mesh.h"
#include "Traverse.h"
#include "ElInfo.h"
#include "Element.h"
#include "MacroElement.h"
22
23
#include "DOFMatrix.h"
#include "DOFVector.h"
24
#include "SystemVector.h"
25
#include "ElementDofIterator.h"
26
27
#include "ProblemStatBase.h"
#include "StandardProblemIteration.h"
28
#include "VertexVector.h"
29
#include "MeshStructure.h"
Thomas Witkowski's avatar
Thomas Witkowski committed
30
31
#include "ProblemVec.h"
#include "ProblemInstat.h"
32
#include "Debug.h"
33

34
35
namespace AMDiS {

Thomas Witkowski's avatar
Thomas Witkowski committed
36
  using boost::lexical_cast;
37
  using namespace boost::filesystem;
Thomas Witkowski's avatar
Thomas Witkowski committed
38

39
40
41
42
43
  inline bool cmpDofsByValue(const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2)
  {
    return (*dof1 < *dof2);
  }

44

45
46
47
48
49
50
51
52
  MeshDistributor::MeshDistributor(std::string str)
    : probStat(0),
      name(str),
      feSpace(NULL),
      mesh(NULL),
      refineManager(NULL),
      info(10),
      partitioner(NULL),
53
      nRankDofs(0),
54
      nOverallDofs(0),
55
      rstart(0),
56
      deserialized(false),
57
      writeSerializationFile(false),
58
      repartitioningAllowed(false),
59
60
      lastMeshChangeIndex(0),
      macroElementStructureConsisten(false)
61
  {
62
    FUNCNAME("MeshDistributor::ParalleDomainBase()");
Thomas Witkowski's avatar
Thomas Witkowski committed
63

64
65
66
    mpiRank = MPI::COMM_WORLD.Get_rank();
    mpiSize = MPI::COMM_WORLD.Get_size();
    mpiComm = MPI::COMM_WORLD;
67
68
69
70

    int tmp = 0;
    GET_PARAMETER(0, name + "->repartitioning", "%d", &tmp);
    repartitioningAllowed = (tmp > 0);
71
72
  }

Thomas Witkowski's avatar
Thomas Witkowski committed
73

74
  void MeshDistributor::initParallelization()
75
  {
76
    FUNCNAME("MeshDistributor::initParallelization()");
77
78
79
80

    TEST_EXIT(mpiSize > 1)
      ("Parallelization does not work with only one process!\n");

81
82
    TEST_EXIT(feSpace)("No FE space has been defined for the mesh distributor!\n");
    TEST_EXIT(mesh)("No mesh has been defined for the mesh distributor!\n");
83

84
85
86
    // If the problem has been already read from a file, we need only to set
    // isRankDofs to all matrices and rhs vector and to remove periodic 
    // boundary conditions (if there are some).
87
    if (deserialized) {
88
      setRankDofs();
89
      removePeriodicBoundaryConditions();
90

91
      return;
92
    }
93

94
   
95
96
97
98
99
    // 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();

100
101
102
103
    // For later mesh repartitioning, we need to store some information about the
    // macro mesh.
    createMacroElementInfo();

104
105
    // create an initial partitioning of the mesh
    partitioner->createPartitionData();
106

107
    // set the element weights, which are 1 at the very first begin
108
    setInitialElementWeights();
109
110
111
112
113
114

    // and now partition the mesh    
    partitioner->fillCoarsePartitionVec(&oldPartitionVec);
    partitioner->partition(&elemWeights, INITIAL);
    partitioner->fillCoarsePartitionVec(&partitionVec);

115

Thomas Witkowski's avatar
Thomas Witkowski committed
116
#if (DEBUG != 0)
117
118
    debug::ElementIdxToDofs elMap;
    debug::createSortedDofs(mesh, elMap);
119
120
121
    if (mpiRank == 0) {
      int writePartMesh = 1;
      GET_PARAMETER(0, "dbg->write part mesh", "%d", &writePartMesh);
122

123
124
      if (writePartMesh > 0) {
	debug::writeElementIndexMesh(mesh, "elementIndex.vtu");
125
	writePartitioningMesh("part.vtu");
126
      } else {
127
	MSG("Skip write part mesh!\n");
128
      }
129
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
130
#endif
131

132

133
    // === Create interior boundary information. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
134

135
    createInteriorBoundaryInfo();
Thomas Witkowski's avatar
Thomas Witkowski committed
136

137
#if (DEBUG != 0)
138
    ParallelDebug::printBoundaryInfo(*this);
139
140
#endif

141

142
143
    // === Create new global and local DOF numbering. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
144
    //    createLocalGlobalNumbering();
145

146

Thomas Witkowski's avatar
n  
Thomas Witkowski committed
147
148
149
    // === Remove all macro elements that are not part of the rank partition. ===

    removeMacroElements();
150
151
    macroElementStructureConsisten = true;

Thomas Witkowski's avatar
n  
Thomas Witkowski committed
152

Thomas Witkowski's avatar
Thomas Witkowski committed
153
154
    updateLocalGlobalNumbering(true);

155
156
157
158
    // === Reset all DOFAdmins of the mesh. ===

    updateDofAdmins();

159

160
161
    // === If in debug mode, make some tests. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
162
#if (DEBUG != 0)
163
    MSG("AMDiS runs in debug mode, so make some test ...\n");
164
    ParallelDebug::testAllElements(*this);
165
    debug::testSortedDofs(mesh, elMap);
166
167
    ParallelDebug::testInteriorBoundary(*this);
    ParallelDebug::testCommonDofs(*this, true);
168
    ParallelDebug::testGlobalIndexByCoords(*this);
169
    MSG("Debug mode tests finished!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
170

171
    debug::writeMesh(feSpace, -1, "macro_mesh");   
172
#endif
173

174

175
176
    // === Create periodic dof mapping, if there are periodic boundaries. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
177
    createPeriodicMap();    
178

179
    // === Global refinements. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
180

Thomas Witkowski's avatar
Thomas Witkowski committed
181
    int globalRefinement = 0;
182
    GET_PARAMETER(0, mesh->getName() + "->global refinements", "%d", &globalRefinement);
Thomas Witkowski's avatar
Thomas Witkowski committed
183

Thomas Witkowski's avatar
Thomas Witkowski committed
184
    if (globalRefinement > 0) {
185
      refineManager->globalRefine(mesh, globalRefinement);
186

187
#if (DEBUG != 0)
188
      debug::writeMesh(feSpace, -1, "gr_mesh");
189
190
#endif

191
      mesh->dofCompress();
Thomas Witkowski's avatar
Thomas Witkowski committed
192
      updateLocalGlobalNumbering(false);
193
194

     
195
      // === Update periodic mapping, if there are periodic boundaries. ===
196
      
197
      createPeriodicMap();
Thomas Witkowski's avatar
Thomas Witkowski committed
198
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
199

200

Thomas Witkowski's avatar
Thomas Witkowski committed
201
202
    /// === Set DOF rank information to all matrices and vectors. ===

203
    setRankDofs();
Thomas Witkowski's avatar
Thomas Witkowski committed
204

205

Thomas Witkowski's avatar
Thomas Witkowski committed
206
207
    // === Remove periodic boundary conditions in sequential problem definition. ===

208
    removePeriodicBoundaryConditions();
209
210
  }

211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  void MeshDistributor::addProblemStat(ProblemVec *probVec)
  {
    FUNCNAME("MeshDistributor::addProblemVec()");

    if (feSpace != NULL) {
      std::vector<FiniteElemSpace*> feSpaces = probVec->getFeSpaces();
      for (unsigned int i = 0; i < feSpaces.size(); i++) {
	TEST_EXIT(feSpace == feSpaces[i])
	  ("Parallelizaton is not supported for multiple FE spaces!\n");
      }
    } else {
      feSpace = probVec->getFeSpace(0);
      mesh = feSpace->getMesh();
      info = probVec->getInfo();
      
      TEST_EXIT(mesh->getNumberOfDOFAdmin() == 1)
	("Only meshes with one DOFAdmin are supported!\n");
229
      TEST_EXIT(mesh->getDofAdmin(0).getNumberOfPreDOFs(0) == 0)
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
	("Wrong pre dof number for DOFAdmin!\n");
      
      switch (mesh->getDim()) {
      case 2:
	refineManager = new RefinementManager2d();
	break;
      case 3:
	refineManager = new RefinementManager3d();
	break;
      default:
	ERROR_EXIT("This should not happen for dim = %d!\n", mesh->getDim());
      }

      partitioner = new ParMetisPartitioner(mesh, &mpiComm);
    }

    // Create parallel serialization file writer, if needed.
    int writeSerialization = 0;
248
249
250
    GET_PARAMETER(0, probVec->getName() + "->output->write serialization", "%d", 
		  &writeSerialization);
    if (writeSerialization && !writeSerializationFile) {
251
252
253
254
255
      std::string filename = "";
      GET_PARAMETER(0, name + "->output->serialization filename", &filename);
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel serialization file!\n");
256
257
258
259
260

      int tsModulo = -1;
      GET_PARAMETER(0, probVec->getName() + "->output->write every i-th timestep", 
		    "%d", &tsModulo);
      
261
      probVec->getFileWriterList().push_back(new Serializer<MeshDistributor>(this, filename, tsModulo));
262
263
      writeSerializationFile = true;
    }    
264
265

    int readSerialization = 0;
266
267
    GET_PARAMETER(0, probVec->getName() + "->input->read serialization", "%d", 
		  &readSerialization);
268
269
270
271
    if (readSerialization) {
      std::string filename = "";
      GET_PARAMETER(0, probVec->getName() + "->input->serialization filename", &filename);
      filename += ".p" + lexical_cast<std::string>(mpiRank);
272
      MSG("Start deserialization with %s\n", filename.c_str());
273
      std::ifstream in(filename.c_str());
274
275
276
277

      TEST_EXIT(!in.fail())("Could not open deserialization file: %s\n",
			    filename.c_str());

278
      probVec->deserialize(in);
279
      in.close();
280
281
      MSG("Deserialization from file: %s\n", filename.c_str());

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
      filename = "";
      GET_PARAMETER(0, name + "->input->serialization filename", &filename);
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel deserialization file!\n");
      
      std::string rankFilename = filename + ".p" + lexical_cast<std::string>(mpiRank);
      in.open(rankFilename.c_str());
      
      TEST_EXIT(!in.fail())("Could not open parallel deserialization file: %s\n",
			    filename.c_str());
      
      deserialize(in);
      in.close();
      MSG("Deserializtion of mesh distributor from file: %s\n", rankFilename.c_str());
      deserialized = true;
298
299
300
301
302
303
    }

    probStat.push_back(probVec);
  }


304
  void MeshDistributor::exitParallelization()
305
  {}
306

307
  
308
  void MeshDistributor::updateDofAdmins()
309
  {
310
    FUNCNAME("MeshDistributor::updateDofAdmins()");
311
312

    for (int i = 0; i < mesh->getNumberOfDOFAdmin(); i++) {
313
      DOFAdmin& admin = const_cast<DOFAdmin&>(mesh->getDofAdmin(i));
314
315
316

      // There must be always more allocated DOFs than used DOFs in DOFAdmin. Otherwise,
      // it is not possible to define a first DOF hole.
317
      if (static_cast<unsigned int>(admin.getSize()) == mapLocalGlobalDofs.size())
318
	admin.enlargeDOFLists();
319
320
321
      
      for (int j = 0; j < admin.getSize(); j++)
	admin.setDOFFree(j, true);
322
      for (unsigned int j = 0; j < mapLocalGlobalDofs.size(); j++)
323
324
 	admin.setDOFFree(j, false);

325
326
327
      admin.setUsedSize(mapLocalGlobalDofs.size());
      admin.setUsedCount(mapLocalGlobalDofs.size());
      admin.setFirstHole(mapLocalGlobalDofs.size());
328
329
330
    }
  }

331

332
  void MeshDistributor::testForMacroMesh()
333
  {
334
    FUNCNAME("MeshDistributor::testForMacroMesh()");
335
336
337
338
339
340
341

    int nMacroElements = 0;

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

      TEST_EXIT(elInfo->getType() == 0)
	("Only macro elements with level 0 are supported!\n");
346
347
348
349
350
351
352
353
354
355
      
      nMacroElements++;

      elInfo = stack.traverseNext(elInfo);
    }

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

356

357
  void MeshDistributor::synchVector(DOFVector<double> &vec)
358
  {
Thomas Witkowski's avatar
Thomas Witkowski committed
359
    StdMpi<std::vector<double> > stdMpi(mpiComm);
360
361

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
362
	 sendIt != sendDofs.end(); ++sendIt) {
363
      std::vector<double> dofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
364
365
      int nSendDofs = sendIt->second.size();
      dofs.reserve(nSendDofs);
366
      
Thomas Witkowski's avatar
Thomas Witkowski committed
367
368
      for (int i = 0; i < nSendDofs; i++)
	dofs.push_back(vec[*((sendIt->second)[i])]);
369
370
371
372

      stdMpi.send(sendIt->first, dofs);
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
373
374
375
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt)
      stdMpi.recv(recvIt->first, recvIt->second.size());
376

Thomas Witkowski's avatar
Thomas Witkowski committed
377
    stdMpi.startCommunication<double>(MPI_DOUBLE);
378

Thomas Witkowski's avatar
Thomas Witkowski committed
379
380
381
382
383
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt)
      for (unsigned int i = 0; i < recvIt->second.size(); i++)
	vec[*(recvIt->second)[i]] = stdMpi.getRecvData(recvIt->first)[i];
  }
384
385


386
  void MeshDistributor::synchVector(SystemVector &vec)
Thomas Witkowski's avatar
Thomas Witkowski committed
387
  {
388
    int nComponents = vec.getSize();
Thomas Witkowski's avatar
Thomas Witkowski committed
389
390
391
392
393
394
395
396
397
398
399
400
    StdMpi<std::vector<double> > stdMpi(mpiComm);

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); ++sendIt) {
      std::vector<double> dofs;
      int nSendDofs = sendIt->second.size();
      dofs.reserve(nComponents * nSendDofs);
      
      for (int i = 0; i < nComponents; i++) {
	DOFVector<double> *dofvec = vec.getDOFVector(i);
	for (int j = 0; j < nSendDofs; j++)
	  dofs.push_back((*dofvec)[*((sendIt->second)[j])]);
401
402
      }

Thomas Witkowski's avatar
Thomas Witkowski committed
403
      stdMpi.send(sendIt->first, dofs);
404
405
406
    }

    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
407
408
	 recvIt != recvDofs.end(); ++recvIt)
      stdMpi.recv(recvIt->first, recvIt->second.size() * nComponents);
409

Thomas Witkowski's avatar
Thomas Witkowski committed
410
    stdMpi.startCommunication<double>(MPI_DOUBLE);
411
412

    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
413
414
	 recvIt != recvDofs.end(); ++recvIt) {
      int nRecvDofs = recvIt->second.size();
415
416

      int counter = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
417
418
419
420
421
      for (int i = 0; i < nComponents; i++) {
	DOFVector<double> *dofvec = vec.getDOFVector(i);
 	for (int j = 0; j < nRecvDofs; j++)
	  (*dofvec)[*(recvIt->second)[j]] = 
	    stdMpi.getRecvData(recvIt->first)[counter++];
422
423
424
425
      }
    }
  }

426

427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  void MeshDistributor::setRankDofs()
  {
    for (unsigned int i = 0; i < probStat.size(); i++) {
      int nComponents = probStat[i]->getNumComponents();
      for (int j = 0; j < nComponents; j++) {
	for (int k = 0; k < nComponents; k++)
	  if (probStat[i]->getSystemMatrix(j, k))
	    probStat[i]->getSystemMatrix(j, k)->setRankDofs(isRankDof);

	TEST_EXIT_DBG(probStat[i]->getRhs()->getDOFVector(j))("No RHS vector!\n");
	TEST_EXIT_DBG(probStat[i]->getSolution()->getDOFVector(j))("No solution vector!\n");
	
	probStat[i]->getRhs()->getDOFVector(j)->setRankDofs(isRankDof);
	probStat[i]->getSolution()->getDOFVector(j)->setRankDofs(isRankDof);
      }
    }
  }


446
447
  void MeshDistributor::removePeriodicBoundaryConditions()
  {
448
449
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

450
451
452
453
454
455
456
457
    // Remove periodic boundaries in boundary manager on matrices and vectors.
    for (unsigned int i = 0; i < probStat.size(); i++) {
      int nComponents = probStat[i]->getNumComponents();

      for (int j = 0; j < nComponents; j++) {
	for (int k = 0; k < nComponents; k++) {
	  DOFMatrix* mat = probStat[i]->getSystemMatrix(j, k);
	  if (mat && mat->getBoundaryManager())
458
	    removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(mat->getBoundaryManager()->getBoundaryConditionMap()));
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
	}
	
	if (probStat[i]->getSolution()->getDOFVector(j)->getBoundaryManager())
	  removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(probStat[i]->getSolution()->getDOFVector(j)->getBoundaryManager()->getBoundaryConditionMap()));
	
	if (probStat[i]->getRhs()->getDOFVector(j)->getBoundaryManager())
	  removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(probStat[i]->getRhs()->getDOFVector(j)->getBoundaryManager()->getBoundaryConditionMap()));
      }
    }

    // Remove periodic boundaries on elements in mesh.
    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(mesh,  -1, Mesh::CALL_EVERY_EL_PREORDER);
    while (elInfo) {
      elInfo->getElement()->deleteElementData(PERIODIC);
      elInfo = stack.traverseNext(elInfo);
    }    
476
477
478
479

    // Remove periodic vertex associations
    for (std::map<BoundaryType, VertexVector*>::iterator it = mesh->getPeriodicAssociations().begin();
	 it != mesh->getPeriodicAssociations().end(); ++it)
480
      const_cast<DOFAdmin&>(mesh->getDofAdmin(0)).removeDOFContainer(dynamic_cast<DOFContainer*>(it->second));
481
    mesh->getPeriodicAssociations().clear();
482
483
484
485
  }


  void MeshDistributor::removePeriodicBoundaryConditions(BoundaryIndexMap& boundaryMap)
Thomas Witkowski's avatar
Thomas Witkowski committed
486
487
488
489
490
491
492
493
494
495
496
  {
    BoundaryIndexMap::iterator it = boundaryMap.begin();
    while (it != boundaryMap.end()) {
      if (it->second->isPeriodic())
	boundaryMap.erase(it++);
      else
	++it;      
    }    
  }


497
  void MeshDistributor::checkMeshChange()
498
  {
499
    FUNCNAME("MeshDistributor::checkMeshChange()");    
500

501
502
503
504
#if (DEBUG != 0)
    debug::writeMesh(feSpace, -1, "before_check_mesh");
#endif

505
506
507
508
509
    // === If mesh has not been changed on all ranks, return. ===

    int recvAllValues = 0;
    int sendValue = static_cast<int>(mesh->getChangeIndex() != lastMeshChangeIndex);
    mpiComm.Allreduce(&sendValue, &recvAllValues, 1, MPI_INT, MPI_SUM);
510

511
    if (recvAllValues == 0)
512
513
      return;

514
515
    // === At least one rank mesh has been changed, so the boundaries must be ===
    // === adapted to the new mesh structure.                                 ===
516

517
518
519
520
521
    clock_t first = clock();
    
    do {
      // To check the interior boundaries, the ownership of the boundaries is not 
      // important. Therefore, we add all boundaries to one boundary container.
522
      RankToBoundMap allBound;
Thomas Witkowski's avatar
Thomas Witkowski committed
523
524

      for (InteriorBoundary::iterator it(myIntBoundary); !it.end(); ++it)
525
526
	if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	    (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
527
 	  allBound[it.getRank()].push_back(*it);
Thomas Witkowski's avatar
Thomas Witkowski committed
528
529

      for (InteriorBoundary::iterator it(otherIntBoundary); !it.end(); ++it)
530
531
	if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	    (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
532
	  allBound[it.getRank()].push_back(*it);
Thomas Witkowski's avatar
Thomas Witkowski committed
533

534
      for (InteriorBoundary::iterator it(periodicBoundary); !it.end(); ++it)
535
536
	if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	    (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
537
 	  allBound[it.getRank()].push_back(*it);	
538

539

540
      // === Check the boundaries and adapt mesh if necessary. ===
541
542
543
544
#if (DEBUG != 0)
      MSG("Run checkAndAdaptBoundary ...\n");
#endif

545
546
547
548
549
550
551
      bool meshChanged = checkAndAdaptBoundary(allBound);

      // === Check on all ranks if at least one rank's mesh has changed. ===

      int sendValue = static_cast<int>(!meshChanged);
      recvAllValues = 0;
      mpiComm.Allreduce(&sendValue, &recvAllValues, 1, MPI_INT, MPI_SUM);
552
553
554
555

#if (DEBUG != 0)
      MSG("Mesh changed on %d ranks!\n", recvAllValues);
#endif
556
    } while (recvAllValues != 0);
557

558
#if (DEBUG != 0)
559
    debug::writeMesh(feSpace, -1, "mesh");
560
561
562
563
564
565
#endif

    INFO(info, 8)("Parallel mesh adaption needed %.5f seconds\n", 
		  TIME_USED(first, clock()));

    // === Because the mesh has been changed, update the DOF numbering and mappings. ===
566

567
    mesh->dofCompress();
Thomas Witkowski's avatar
Thomas Witkowski committed
568
    updateLocalGlobalNumbering(false);
569
570
571
572

    // === Update periodic mapping, if there are periodic boundaries. ===

    createPeriodicMap();
573
574
575
576


    // === The mesh has changed, so check if it is required to repartition the mesh. ===

577
578
    if (repartitioningAllowed)
      repartitionMesh();
579
580
581
  }

  
582
  bool MeshDistributor::checkAndAdaptBoundary(RankToBoundMap &allBound)
583
  {
584
    FUNCNAME("MeshDistributor::checkAndAdaptBoundary()");
585
586
587
588
589
590

    // === Create mesh structure codes for all ranks boundary elements. ===
       
    std::map<int, MeshCodeVec> sendCodes;
   
    for (RankToBoundMap::iterator it = allBound.begin(); it != allBound.end(); ++it) {
591

592
593
594
      for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
	   boundIt != it->second.end(); ++boundIt) {
	MeshStructure elCode;
595
	elCode.init(boundIt->rankObj);
596
597
598
599
	sendCodes[it->first].push_back(elCode);
      }
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
600
    StdMpi<MeshCodeVec> stdMpi(mpiComm, true);
601
    stdMpi.send(sendCodes);
602
    stdMpi.recv(allBound);
603
    stdMpi.startCommunication<uint64_t>(MPI_UNSIGNED_LONG);
604
 
605
    // === Compare received mesh structure codes. ===
606
    
607
608
    bool meshFitTogether = true;

609
    for (RankToBoundMap::iterator it = allBound.begin(); it != allBound.end(); ++it) {
610
     
611
612
      MeshCodeVec &recvCodes = stdMpi.getRecvData()[it->first];
      int i = 0;
613
      
614
615
      for (std::vector<AtomicBoundary>::iterator boundIt = it->second.begin();
	   boundIt != it->second.end(); ++boundIt) {
616

617
618
	MeshStructure elCode;	
	elCode.init(boundIt->rankObj);
619

620
621
	if (elCode.getCode() != recvCodes[i].getCode()) {
	  TEST_EXIT_DBG(refineManager)("Refinement manager is not set correctly!\n");
622

623
624
625
626
627
628
	  bool b = startFitElementToMeshCode(recvCodes[i], 
					     boundIt->rankObj.el,
					     boundIt->rankObj.subObj,
					     boundIt->rankObj.ithObj, 
					     boundIt->rankObj.elType,
					     boundIt->rankObj.reverseMode);
629

630
	  if (b)
631
	    meshFitTogether = false;	  
632
 	}
633

634
	i++;
635
636
637
      }
    }

638
    return meshFitTogether;
639
  }
640
641


642
643
644
645
646
647
  bool MeshDistributor::startFitElementToMeshCode(MeshStructure &code, 
						  Element *el, 
						  GeoIndex subObj,
						  int ithObj, 
						  int elType,
						  bool reverseMode)
648
  {
649
    FUNCNAME("MeshDistributor::startFitElementToMeshCode()");
650

651
652
    TEST_EXIT_DBG(el)("No element given!\n");

653
654
    // If the code is empty, the element does not matter and the function can
    // return without chaning the mesh.
655
656
    if (code.empty())
      return false;
657

658
659
660
661
662
    // s0 and s1 are the number of the edge/face in both child of the element,
    // which contain the edge/face the function has to traverse through. If the
    // edge/face is not contained in one of the children, s0 or s1 is -1.
    int s0 = el->getSubObjOfChild(0, subObj, ithObj, elType);
    int s1 = el->getSubObjOfChild(1, subObj, ithObj, elType);
663

664
    TEST_EXIT_DBG(s0 != -1 || s1 != -1)("This should not happen!\n");
665

666
    bool meshChanged = false;
667
668
669
    Flag traverseFlag = 
      Mesh::CALL_EVERY_EL_PREORDER | Mesh::FILL_NEIGH | Mesh::FILL_BOUND;

670
671
672
673
674
    // Test for reverse mode, in which the left and right children of elements
    // are flipped.
    if (reverseMode)
      traverseFlag |= Mesh::CALL_REVERSE_MODE;    

675

676
677
678
679
680
    // === If the edge/face is contained in both children. ===

    if (s0 != -1 && s1 != -1) {
      // Create traverse stack and traverse within the mesh until the element,
      // which should be fitted to the mesh structure code, is reached.
681
      TraverseStack stack;
682
      ElInfo *elInfo = stack.traverseFirst(el->getMesh(), -1, traverseFlag);
683
684
      while (elInfo && elInfo->getElement() != el)
	elInfo = stack.traverseNext(elInfo);      
685

686
687
      TEST_EXIT_DBG(elInfo->getElement() == el)("This should not happen!\n");

688
      meshChanged = fitElementToMeshCode(code, stack, subObj, ithObj, reverseMode);
689
690
      return meshChanged;
    }
691

692
693
694

    // === The edge/face is contained in only on of the both children. ===

695
    if (el->isLeaf()) {
696
697

      // If element is leaf and code contains only one leaf element, we are finished.
698
699
700
      if (code.getNumElements() == 1 && code.isLeafElement())
	return false;     

701
      // Create traverse stack and traverse the mesh to the element.
702
      TraverseStack stack;
703
      ElInfo *elInfo = stack.traverseFirst(el->getMesh(), -1, traverseFlag);
704
705
      while (elInfo && elInfo->getElement() != el)
	elInfo = stack.traverseNext(elInfo);      
706
707
708

      TEST_EXIT_DBG(elInfo)("This should not happen!\n");

709
      // Code is not leaf, therefore refine the element.
710
      el->setMark(1);
711
712
      refineManager->setMesh(el->getMesh());
      refineManager->setStack(&stack);
713
      refineManager->refineFunction(elInfo);
714
      meshChanged = true;
715
    }
716

717
718
    Element *child0 = el->getFirstChild();
    Element *child1 = el->getSecondChild();
719
720
721
722
    if (reverseMode) {
      std::swap(s0, s1);
      std::swap(child0, child1);    
    }
723

724
725
726
    // === We know that the edge/face is contained in only one of the children. ===
    // === Therefore, traverse the mesh to this children and fit this element   ===
    // === To the mesh structure code.                                          ===
727

728
729
    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(el->getMesh(), -1, traverseFlag);
730

731
732
733
    if (s0 != -1) {
      while (elInfo && elInfo->getElement() != child0)
	elInfo = stack.traverseNext(elInfo);     
734

735
736
737
738
      meshChanged |= fitElementToMeshCode(code, stack, subObj, s0, reverseMode);
    } else {
      while (elInfo && elInfo->getElement() != child1) 
	elInfo = stack.traverseNext(elInfo);      
739

740
      meshChanged |= fitElementToMeshCode(code, stack, subObj, s1, reverseMode);
741
742
    }

743

744
    return meshChanged;
745
746
  }

747

748
749
750
751
752
  bool MeshDistributor::fitElementToMeshCode(MeshStructure &code, 
					     TraverseStack &stack,
					     GeoIndex subObj,
					     int ithObj, 
					     bool reverseMode)
753
  {
754
755
756
757
    FUNCNAME("MeshDistributor::fitElementToMeshCode()");


    // === Test if there are more elements in stack to check with the code. ===
758

759
760
    ElInfo *elInfo = stack.getElInfo();
    if (!elInfo)
761
      return false;
762

763
764
765
766

    // === Test if code contains a leaf element. If this is the case, the ===
    // === current element is finished. Traverse the mesh to the next     ===
    // === coarser element.                                               ===
767
768
769
770
771
772
773

    if (code.isLeafElement()) {
      int level = elInfo->getLevel();

      do {
	elInfo = stack.traverseNext(elInfo);
      } while (elInfo && elInfo->getLevel() > level);
774

775
      return false;
776
    }
777

778
779
780
781
782
783

    bool meshChanged = false;
    Element *el = elInfo->getElement();


    // === If element is leaf (and the code is not), refine the element. ===
784

785
    if (el->isLeaf()) {
786
787
      TEST_EXIT_DBG(elInfo->getLevel() < 255)("This should not happen!\n");

788
      el->setMark(1);
789
790
      refineManager->setMesh(el->getMesh());
      refineManager->setStack(&stack);
791
      refineManager->refineFunction(elInfo);
792
      meshChanged = true;
793
794
    }

795
796
797
798
799
800

    // === Continue fitting the mesh structure code to the children of the ===
    // === current element.                                                ===

    int s0 = el->getSubObjOfChild(0, subObj, ithObj, elInfo->getType());
    int s1 = el->getSubObjOfChild(1, subObj, ithObj, elInfo->getType());
801
802
803
    Element *child0 = el->getFirstChild();
    Element *child1 = el->getSecondChild();
    if (reverseMode) {
804
      std::swap(s0, s1);
805
806
      std::swap(child0, child1);
    }
807

808
809
810
811
812
813
814
    
    // === Traverse left child. ===

    if (s0 != -1) {
      // The edge/face is contained in the left child, therefore fit this
      // child to the mesh structure code.

815
      stack.traverseNext(elInfo);
816
      code.nextElement();
817
      meshChanged |= fitElementToMeshCode(code, stack, subObj, s0, reverseMode);
818
819
      elInfo = stack.getElInfo();
    } else {
820
821
822
823
      // The edge/face is not contained in the left child. Hence we need
      // to traverse through all subelements of the left child until we get
      // the second child of the current element.

824
825
      do {
	elInfo = stack.traverseNext(elInfo);
826
827
828
      } while (elInfo && elInfo->getElement() != child1); 

      TEST_EXIT_DBG(elInfo != NULL)("This should not happen!\n");
829
830
    }  

831
832
833
834
835
836
837
838
839
840
    TEST_EXIT_DBG(elInfo->getElement() == child1)
      ("Got wrong child with idx = %d! Searched for child idx = %d\n",
       elInfo->getElement()->getIndex(), child1->getIndex());


    // === Traverse right child. ===

    if (s1 != -1) {
      // The edge/face is contained in the right child, therefore fit this
      // child to the mesh structure code.
841
842

      code.nextElement();
843
      meshChanged |= fitElementToMeshCode(code, stack, subObj, s1, reverseMode);
844
    } else {
845
846
847
848
      // The edge/face is not contained in the right child. Hence we need
      // to traverse through all subelements of the right child until we have
      // finished traversing the current element with all its subelements.

849
      int level = elInfo->getLevel();
850

851
852
853
854
      do {
	elInfo = stack.traverseNext(elInfo);
      } while (elInfo && elInfo->getLevel() > level);
    }
855

856
857

    return meshChanged;
858
859
  }

860
  
861
  void MeshDistributor::serialize(std::ostream &out, DofContainer &data)
Thomas Witkowski's avatar
Thomas Witkowski committed
862
  {    
863
    int vecSize = data.size();
864
    SerUtil::serialize(out, vecSize);
865
866
    for (int i = 0; i < vecSize; i++) {
      int dofIndex = (*data[i]);