MeshDistributor.cc 68.4 KB
Newer Older
1
//
2
3
4
5
6
7
8
9
10
11
12
// Software License for AMDiS
//
// Copyright (c) 2010 Dresden University of Technology 
// All rights reserved.
// Authors: Simon Vey, Thomas Witkowski et al.
//
// This file is part of AMDiS
//
// See also license.opensource.txt in the distribution.


Thomas Witkowski's avatar
Thomas Witkowski committed
13
#include <algorithm>
14
15
#include <iostream>
#include <fstream>
16
17
#include <limits>
#include <stdint.h>
Thomas Witkowski's avatar
Thomas Witkowski committed
18
#include <boost/lexical_cast.hpp>
19
20
#include <boost/filesystem.hpp>

21
#include "parallel/MeshDistributor.h"
22
#include "parallel/MeshManipulation.h"
23
#include "parallel/ParallelDebug.h"
24
#include "parallel/StdMpi.h"
25
#include "parallel/ParMetisPartitioner.h"
26
27
28
#include "io/ElementFileWriter.h"
#include "io/MacroInfo.h"
#include "io/VtkWriter.h"
29
30
31
32
33
#include "Mesh.h"
#include "Traverse.h"
#include "ElInfo.h"
#include "Element.h"
#include "MacroElement.h"
34
35
#include "DOFMatrix.h"
#include "DOFVector.h"
36
#include "SystemVector.h"
37
#include "ElementDofIterator.h"
38
39
#include "ProblemStatBase.h"
#include "StandardProblemIteration.h"
40
#include "VertexVector.h"
41
#include "MeshStructure.h"
Thomas Witkowski's avatar
Thomas Witkowski committed
42
43
#include "ProblemVec.h"
#include "ProblemInstat.h"
44
#include "Debug.h"
45

46
47
namespace AMDiS {

Thomas Witkowski's avatar
Thomas Witkowski committed
48
  using boost::lexical_cast;
49
  using namespace boost::filesystem;
50
  using namespace std;
Thomas Witkowski's avatar
Thomas Witkowski committed
51

52
53
54
55
56
  inline bool cmpDofsByValue(const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2)
  {
    return (*dof1 < *dof2);
  }

57

58
  MeshDistributor::MeshDistributor(string str)
59
60
61
62
63
64
65
    : probStat(0),
      name(str),
      feSpace(NULL),
      mesh(NULL),
      refineManager(NULL),
      info(10),
      partitioner(NULL),
66
      nRankDofs(0),
67
      nOverallDofs(0),
68
      rstart(0),
69
      deserialized(false),
70
      writeSerializationFile(false),
71
      repartitioningAllowed(false),
72
      repartitionIthChange(20),
73
      nTimestepsAfterLastRepartitioning(0),
74
      repartCounter(0),
75
      debugOutputDir(""),
76
      lastMeshChangeIndex(0)
77
  {
78
    FUNCNAME("MeshDistributor::ParalleDomainBase()");
Thomas Witkowski's avatar
Thomas Witkowski committed
79

80
81
82
    mpiRank = MPI::COMM_WORLD.Get_rank();
    mpiSize = MPI::COMM_WORLD.Get_size();
    mpiComm = MPI::COMM_WORLD;
83
84
85
86

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

88
89
    GET_PARAMETER(0, name + "->debug output dir", &debugOutputDir);
    GET_PARAMETER(0, name + "->repartition ith change", "%d", &repartitionIthChange);
90
91
92
93

    tmp = 0;
    GET_PARAMETER(0, name + "->log main rank", "%d", &tmp);
    Msg::outputMainRank = (tmp > 0);
94
95
  }

Thomas Witkowski's avatar
Thomas Witkowski committed
96

97
  void MeshDistributor::initParallelization()
98
  {
99
    FUNCNAME("MeshDistributor::initParallelization()");
100
101
102
103

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

104
105
    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");
106

107
108
    elObjects.setFeSpace(feSpace);

109
110
111
    // 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).
112
    if (deserialized) {
113
114
      updateMacroElementInfo();

115
      setRankDofs();
116

117
      removePeriodicBoundaryConditions();
118

119
120
      macroElIndexMap.clear();
      macroElIndexTypeMap.clear();
121

122
123
      map<int, bool>& elementInRank = partitioner->getElementInRank();
      for (vector<MacroElement*>::iterator it = allMacroElements.begin();
124
125
	   it != allMacroElements.end(); ++it) {
	elementInRank[(*it)->getIndex()] = false;
126
127
128
129
	macroElIndexMap[(*it)->getIndex()] = (*it)->getElement();
	macroElIndexTypeMap[(*it)->getIndex()] = (*it)->getElType();
      }

130
      for (deque<MacroElement*>::iterator it = mesh->getMacroElements().begin();
131
132
133
	   it != mesh->getMacroElements().end(); ++it)
	elementInRank[(*it)->getIndex()] = true;      

134
      return;
135
    }
136

137
   
138
139
140
141
142
    // 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();

143
144
145
146
    // For later mesh repartitioning, we need to store some information about the
    // macro mesh.
    createMacroElementInfo();

147
148
    // create an initial partitioning of the mesh
    partitioner->createPartitionData();
149

150
    // set the element weights, which are 1 at the very first begin
151
    setInitialElementWeights();
152
153
154

    // and now partition the mesh    
    partitioner->fillCoarsePartitionVec(&oldPartitionVec);
155
156
157
158

    bool partitioningSucceed = partitioner->partition(elemWeights, INITIAL);
    TEST_EXIT(partitioningSucceed)("Initial partitioning does not work!\n");

159
160
    partitioner->fillCoarsePartitionVec(&partitionVec);

161

Thomas Witkowski's avatar
Thomas Witkowski committed
162
#if (DEBUG != 0)
163
164
    debug::ElementIdxToDofs elMap;
    debug::createSortedDofs(mesh, elMap);
165
166
167
    if (mpiRank == 0) {
      int writePartMesh = 1;
      GET_PARAMETER(0, "dbg->write part mesh", "%d", &writePartMesh);
168

169
      if (writePartMesh > 0) {
170
171
	debug::writeElementIndexMesh(mesh, debugOutputDir + "elementIndex.vtu");
	writePartitioningMesh(debugOutputDir + "part.vtu");
172
      } else {
173
	MSG("Skip write part mesh!\n");
174
      }
175
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
176
#endif
177

178

179
    // === Create interior boundary information. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
180

181
    createInteriorBoundaryInfo();
Thomas Witkowski's avatar
Thomas Witkowski committed
182

183
#if (DEBUG != 0)
184
    ParallelDebug::printBoundaryInfo(*this);
185
186
#endif

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
    for (deque<MacroElement*>::iterator it = mesh->firstMacroElement();
	 it != mesh->endOfMacroElements(); ++it) {
      for (int i = 0; i < mesh->getGeo(NEIGH); i++) {
	if ((*it)->getNeighbour(i) && 
	    mesh->isPeriodicAssociation((*it)->getBoundary(i))) {
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

	  macroElementNeighbours[(*it)->getIndex()][i] = -1;
	}
      }
    }

    for (vector<MacroElement*>::iterator it = allMacroElements.begin();
	 it != allMacroElements.end(); ++it) {
      for (int i = 0; i < mesh->getGeo(NEIGH); i++) {
	if ((*it)->getNeighbour(i) && 
	    mesh->isPeriodicAssociation((*it)->getBoundary(i))) {
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

	  macroElementNeighbours[(*it)->getIndex()][i] = -1;
	}
      }
    }
214

Thomas Witkowski's avatar
n  
Thomas Witkowski committed
215
216
217
    // === Remove all macro elements that are not part of the rank partition. ===

    removeMacroElements();
218

Thomas Witkowski's avatar
n  
Thomas Witkowski committed
219

220
221
    // === Create new global and local DOF numbering. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
222

223
224
225
    // We have to remove the VertexVectors, which contain periodic assoiciations, 
    // because they are not valid anymore after some macro elements have been removed
    // and the corresponding DOFs were deleted.
226
    for (map<BoundaryType, VertexVector*>::iterator it = mesh->getPeriodicAssociations().begin();
227
228
	 it != mesh->getPeriodicAssociations().end(); ++it)
      const_cast<DOFAdmin&>(mesh->getDofAdmin(0)).removeDOFContainer(dynamic_cast<DOFContainer*>(it->second));
229

230
    updateLocalGlobalNumbering();
231

232

233
234
    // === If in debug mode, make some tests. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
235
#if (DEBUG != 0)
236
    MSG("AMDiS runs in debug mode, so make some test ...\n");
237

238
    ParallelDebug::testAllElements(*this);
239
    debug::testSortedDofs(mesh, elMap);
240
241
    ParallelDebug::testInteriorBoundary(*this);
    ParallelDebug::testCommonDofs(*this, true);
242
    ParallelDebug::testGlobalIndexByCoords(*this);
Thomas Witkowski's avatar
Thomas Witkowski committed
243

244
    debug::writeMesh(feSpace, -1, debugOutputDir + "macro_mesh");   
245
246

    MSG("Debug mode tests finished!\n");
247
#endif
248

249

250
251
    // === Create periodic dof mapping, if there are periodic boundaries. ===

252
    createPeriodicMap();
253

254

255
    // === Global refinements. ===
256
    
Thomas Witkowski's avatar
Thomas Witkowski committed
257
    int globalRefinement = 0;
258
    GET_PARAMETER(0, mesh->getName() + "->global refinements", "%d", &globalRefinement);
259
    
Thomas Witkowski's avatar
Thomas Witkowski committed
260
    if (globalRefinement > 0) {
261
      refineManager->globalRefine(mesh, globalRefinement);
262

263
      updateLocalGlobalNumbering();
264
265

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

268
      createPeriodicMap();
Thomas Witkowski's avatar
Thomas Witkowski committed
269
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
270

271

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

274
    setRankDofs();
Thomas Witkowski's avatar
Thomas Witkowski committed
275

276

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

279
    removePeriodicBoundaryConditions();
280
281
  }

282

283
284
285
286
287
  void MeshDistributor::addProblemStat(ProblemVec *probVec)
  {
    FUNCNAME("MeshDistributor::addProblemVec()");

    if (feSpace != NULL) {
288
      vector<FiniteElemSpace*> feSpaces = probVec->getFeSpaces();
289
290
291
292
293
294
295
296
297
298
299
      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");
300
      TEST_EXIT(mesh->getDofAdmin(0).getNumberOfPreDofs(VERTEX) == 0)
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
	("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;
319
320
321
    GET_PARAMETER(0, probVec->getName() + "->output->write serialization", "%d", 
		  &writeSerialization);
    if (writeSerialization && !writeSerializationFile) {
322
      string filename = "";
323
324
325
326
      GET_PARAMETER(0, name + "->output->serialization filename", &filename);
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel serialization file!\n");
327
328
329
330
331

      int tsModulo = -1;
      GET_PARAMETER(0, probVec->getName() + "->output->write every i-th timestep", 
		    "%d", &tsModulo);
      
332
      probVec->getFileWriterList().push_back(new Serializer<MeshDistributor>(this, filename, tsModulo));
333
334
      writeSerializationFile = true;
    }    
335
336

    int readSerialization = 0;
337
338
    GET_PARAMETER(0, probVec->getName() + "->input->read serialization", "%d", 
		  &readSerialization);
339
    if (readSerialization) {
340
      string filename = "";
341
      GET_PARAMETER(0, probVec->getName() + "->input->serialization filename", &filename);
342
      filename += ".p" + lexical_cast<string>(mpiRank);
343
      MSG("Start deserialization with %s\n", filename.c_str());
344
      ifstream in(filename.c_str());
345
346
347
348

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

349
      probVec->deserialize(in);
350
      in.close();
351
352
      MSG("Deserialization from file: %s\n", filename.c_str());

353
354
355
356
357
358
      filename = "";
      GET_PARAMETER(0, name + "->input->serialization filename", &filename);
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel deserialization file!\n");
      
359
      string rankFilename = filename + ".p" + lexical_cast<string>(mpiRank);
360
361
362
363
364
365
366
367
368
      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;
369
370
371
372
373
374
    }

    probStat.push_back(probVec);
  }


375
  void MeshDistributor::exitParallelization()
376
  {}
377

378
  
379
  void MeshDistributor::testForMacroMesh()
380
  {
381
    FUNCNAME("MeshDistributor::testForMacroMesh()");
382
383
384
385
386
387
388

    int nMacroElements = 0;

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

      TEST_EXIT(elInfo->getType() == 0)
	("Only macro elements with level 0 are supported!\n");
393
394
395
396
397
398
399
400
401
402
      
      nMacroElements++;

      elInfo = stack.traverseNext(elInfo);
    }

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

403

404
  void MeshDistributor::synchVector(DOFVector<double> &vec)
405
  {
406
    StdMpi<vector<double> > stdMpi(mpiComm);
407
408

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
409
	 sendIt != sendDofs.end(); ++sendIt) {
410
      vector<double> dofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
411
412
      int nSendDofs = sendIt->second.size();
      dofs.reserve(nSendDofs);
413
      
Thomas Witkowski's avatar
Thomas Witkowski committed
414
415
      for (int i = 0; i < nSendDofs; i++)
	dofs.push_back(vec[*((sendIt->second)[i])]);
416
417
418
419

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

Thomas Witkowski's avatar
Thomas Witkowski committed
420
421
422
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt)
      stdMpi.recv(recvIt->first, recvIt->second.size());
423

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

Thomas Witkowski's avatar
Thomas Witkowski committed
426
427
428
429
430
    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];
  }
431
432


433
  void MeshDistributor::synchVector(SystemVector &vec)
Thomas Witkowski's avatar
Thomas Witkowski committed
434
  {
435
    int nComponents = vec.getSize();
436
    StdMpi<vector<double> > stdMpi(mpiComm);
Thomas Witkowski's avatar
Thomas Witkowski committed
437
438
439

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); ++sendIt) {
440
      vector<double> dofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
441
442
443
444
445
446
447
      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])]);
448
449
      }

Thomas Witkowski's avatar
Thomas Witkowski committed
450
      stdMpi.send(sendIt->first, dofs);
451
452
453
    }

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

Thomas Witkowski's avatar
Thomas Witkowski committed
457
    stdMpi.startCommunication<double>(MPI_DOUBLE);
458
459

    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
460
461
	 recvIt != recvDofs.end(); ++recvIt) {
      int nRecvDofs = recvIt->second.size();
462
463

      int counter = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
464
465
466
467
468
      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++];
469
470
471
472
      }
    }
  }

473

474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  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);
      }
    }
  }


493
494
  void MeshDistributor::removePeriodicBoundaryConditions()
  {
495
496
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

497
498
499
500
501
502
503
504
    // 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())
505
	    removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(mat->getBoundaryManager()->getBoundaryConditionMap()));
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
	}
	
	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);
    }    
523
524
525

    // Remove periodic vertex associations
    mesh->getPeriodicAssociations().clear();
526
527
528
529
  }


  void MeshDistributor::removePeriodicBoundaryConditions(BoundaryIndexMap& boundaryMap)
Thomas Witkowski's avatar
Thomas Witkowski committed
530
531
532
533
534
535
536
537
538
539
540
  {
    BoundaryIndexMap::iterator it = boundaryMap.begin();
    while (it != boundaryMap.end()) {
      if (it->second->isPeriodic())
	boundaryMap.erase(it++);
      else
	++it;      
    }    
  }


541
  void MeshDistributor::checkMeshChange()
542
  {
543
    FUNCNAME("MeshDistributor::checkMeshChange()");    
544

545
546
    double first = MPI::Wtime();

547
548
549
550
551
    // === 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);
552

553
    if (recvAllValues == 0)
554
555
      return;

556
557
    // === At least one rank mesh has been changed, so the boundaries must be ===
    // === adapted to the new mesh structure.                                 ===
558
   
559
560
561
    do {
      // To check the interior boundaries, the ownership of the boundaries is not 
      // important. Therefore, we add all boundaries to one boundary container.
562
      RankToBoundMap allBound;
Thomas Witkowski's avatar
Thomas Witkowski committed
563
564

      for (InteriorBoundary::iterator it(myIntBoundary); !it.end(); ++it)
565
566
	if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	    (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
567
 	  allBound[it.getRank()].push_back(*it);
Thomas Witkowski's avatar
Thomas Witkowski committed
568
569

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

574
575
      for (InteriorBoundary::iterator it(periodicBoundary); !it.end(); ++it) {
	if (it.getRank() == mpiRank) {
576
	  WARNING("Na, du weisst schon!\n");
577
578
579
580
581
582
	} else {
	  if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	      (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
	    allBound[it.getRank()].push_back(*it);	
	}
      }
583

584

585
      // === Check the boundaries and adapt mesh if necessary. ===
586
587
588
589
#if (DEBUG != 0)
      MSG("Run checkAndAdaptBoundary ...\n");
#endif

590
591
592
593
594
595
596
      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);
597
598
599
600

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

603
#if (DEBUG != 0)
604
    debug::writeMesh(feSpace, -1, debugOutputDir + "mesh");
605
606
607
#endif

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

609
610
    updateLocalGlobalNumbering();

611
612
613

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

614
    createPeriodicMap();    
615

616
617
618
619
620

    INFO(info, 8)("Parallel mesh adaption needed %.5f seconds\n", 
		  MPI::Wtime() - first);


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

623
624
625
    nTimestepsAfterLastRepartitioning++;

    if (repartitioningAllowed) {
626
      if (nTimestepsAfterLastRepartitioning >= repartitionIthChange) {
627
628
	repartitionMesh();
	nTimestepsAfterLastRepartitioning = 0;
629
      }
630
    }
631
632
633
  }

  
634
  bool MeshDistributor::checkAndAdaptBoundary(RankToBoundMap &allBound)
635
  {
636
    FUNCNAME("MeshDistributor::checkAndAdaptBoundary()");
637
638
639

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

644
      for (vector<AtomicBoundary>::iterator boundIt = it->second.begin();
645
646
	   boundIt != it->second.end(); ++boundIt) {
	MeshStructure elCode;
647
	elCode.init(boundIt->rankObj);
648
649
650
651
	sendCodes[it->first].push_back(elCode);
      }
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
652
    StdMpi<MeshCodeVec> stdMpi(mpiComm, true);
653
    stdMpi.send(sendCodes);
654
    stdMpi.recv(allBound);
655
    stdMpi.startCommunication<uint64_t>(MPI_UNSIGNED_LONG);
656
 
657
    // === Compare received mesh structure codes. ===
658
    
659
660
    bool meshFitTogether = true;

661
    for (RankToBoundMap::iterator it = allBound.begin(); it != allBound.end(); ++it) {
662
     
663
664
      MeshCodeVec &recvCodes = stdMpi.getRecvData()[it->first];
      int i = 0;
665
      
666
      for (vector<AtomicBoundary>::iterator boundIt = it->second.begin();
667
	   boundIt != it->second.end(); ++boundIt) {
668

669
670
	MeshStructure elCode;	
	elCode.init(boundIt->rankObj);
671

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

675
676
677
678
679
680
	  bool b = startFitElementToMeshCode(recvCodes[i], 
					     boundIt->rankObj.el,
					     boundIt->rankObj.subObj,
					     boundIt->rankObj.ithObj, 
					     boundIt->rankObj.elType,
					     boundIt->rankObj.reverseMode);
681

682
	  if (b)
683
	    meshFitTogether = false;	  
684
 	}
685

686
	i++;
687
688
689
      }
    }

690
    return meshFitTogether;
691
  }
692
693


694
695
696
697
698
699
  bool MeshDistributor::startFitElementToMeshCode(MeshStructure &code, 
						  Element *el, 
						  GeoIndex subObj,
						  int ithObj, 
						  int elType,
						  bool reverseMode)
700
  {
701
    FUNCNAME("MeshDistributor::startFitElementToMeshCode()");
702

703
704
    TEST_EXIT_DBG(el)("No element given!\n");

705
706
    // If the code is empty, the element does not matter and the function can
    // return without chaning the mesh.
707
708
    if (code.empty())
      return false;
709

710
711
712
713
714
    // 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);
715

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

718
    bool meshChanged = false;
719
720
721
    Flag traverseFlag = 
      Mesh::CALL_EVERY_EL_PREORDER | Mesh::FILL_NEIGH | Mesh::FILL_BOUND;

722
723
724
725
726
    // Test for reverse mode, in which the left and right children of elements
    // are flipped.
    if (reverseMode)
      traverseFlag |= Mesh::CALL_REVERSE_MODE;    

727

728
729
730
731
732
    // === 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.
733
      TraverseStack stack;
734
      ElInfo *elInfo = stack.traverseFirst(el->getMesh(), -1, traverseFlag);
735
736
      while (elInfo && elInfo->getElement() != el)
	elInfo = stack.traverseNext(elInfo);      
737

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

740
      meshChanged = fitElementToMeshCode(code, stack, subObj, ithObj, reverseMode);
741
742
      return meshChanged;
    }
743

744
745
746

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

747
    if (el->isLeaf()) {
748
749

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

753
      // Create traverse stack and traverse the mesh to the element.
754
      TraverseStack stack;
755
      ElInfo *elInfo = stack.traverseFirst(el->getMesh(), -1, traverseFlag);
756
757
      while (elInfo && elInfo->getElement() != el)
	elInfo = stack.traverseNext(elInfo);      
758
759
760

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

761
      // Code is not leaf, therefore refine the element.
762
      el->setMark(1);
763
764
      refineManager->setMesh(el->getMesh());
      refineManager->setStack(&stack);
765
      refineManager->refineFunction(elInfo);
766
      meshChanged = true;
767
    }
768

769
770
    Element *child0 = el->getFirstChild();
    Element *child1 = el->getSecondChild();
771
    if (reverseMode) {
772
773
      swap(s0, s1);
      swap(child0, child1);    
774
    }
775

776
777
778
    // === 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.                                          ===
779

780
781
    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(el->getMesh(), -1, traverseFlag);
782

783
784
785
    if (s0 != -1) {
      while (elInfo && elInfo->getElement() != child0)
	elInfo = stack.traverseNext(elInfo);     
786

787
788
789
790
      meshChanged |= fitElementToMeshCode(code, stack, subObj, s0, reverseMode);
    } else {
      while (elInfo && elInfo->getElement() != child1) 
	elInfo = stack.traverseNext(elInfo);      
791

792
      meshChanged |= fitElementToMeshCode(code, stack, subObj, s1, reverseMode);
793
794
    }

795

796
    return meshChanged;
797
798
  }

799

800
801
802
803
804
  bool MeshDistributor::fitElementToMeshCode(MeshStructure &code, 
					     TraverseStack &stack,
					     GeoIndex subObj,
					     int ithObj, 
					     bool reverseMode)
805
  {
806
807
808
809
    FUNCNAME("MeshDistributor::fitElementToMeshCode()");


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

811
812
    ElInfo *elInfo = stack.getElInfo();
    if (!elInfo)
813
      return false;
814

815
816
817
818

    // === 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.                                               ===
819
820
821
822
823
824
825

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

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

827
      return false;
828
    }
829

830
831
832
833
834
835

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


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

837
    if (el->isLeaf()) {
838
839
      TEST_EXIT_DBG(elInfo->getLevel() < 255)("This should not happen!\n");

840
      el->setMark(1);
841
842
      refineManager->setMesh(el->getMesh());
      refineManager->setStack(&stack);
843
      refineManager->refineFunction(elInfo);
844
      meshChanged = true;
845
846
    }

847
848
849
850
851
852

    // === 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());
Thomas Witkowski's avatar