MeshDistributor.cc 71 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/MeshPartitioner.h"
26
#include "parallel/ParMetisPartitioner.h"
27
#include "parallel/ZoltanPartitioner.h"
Thomas Witkowski's avatar
Thomas Witkowski committed
28
#include "parallel/SimplePartitioner.h"
29
#include "parallel/CheckerPartitioner.h"
30
#include "parallel/MpiHelper.h"
31 32 33
#include "io/ElementFileWriter.h"
#include "io/MacroInfo.h"
#include "io/VtkWriter.h"
34 35 36 37 38
#include "Mesh.h"
#include "Traverse.h"
#include "ElInfo.h"
#include "Element.h"
#include "MacroElement.h"
39 40
#include "DOFMatrix.h"
#include "DOFVector.h"
41
#include "SystemVector.h"
42
#include "ElementDofIterator.h"
43 44
#include "ProblemStatBase.h"
#include "StandardProblemIteration.h"
45
#include "VertexVector.h"
46
#include "MeshStructure.h"
47
#include "ProblemStat.h"
Thomas Witkowski's avatar
Thomas Witkowski committed
48
#include "ProblemInstat.h"
49
#include "RefinementManager3d.h"
50
#include "Debug.h"
51

52 53
namespace AMDiS {

Thomas Witkowski's avatar
Thomas Witkowski committed
54
  using boost::lexical_cast;
55
  using namespace boost::filesystem;
56
  using namespace std;
Thomas Witkowski's avatar
Thomas Witkowski committed
57

58 59
  MeshDistributor* MeshDistributor::globalMeshDistributor = NULL;

60 61 62
  const Flag MeshDistributor::BOUNDARY_SUBOBJ_SORTED              = 0X01L;
  const Flag MeshDistributor::BOUNDARY_FILL_INFO_SEND_DOFS        = 0X02L;
  const Flag MeshDistributor::BOUNDARY_FILL_INFO_RECV_DOFS        = 0X04L;
Thomas Witkowski's avatar
Thomas Witkowski committed
63

64 65 66 67 68
  inline bool cmpDofsByValue(const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2)
  {
    return (*dof1 < *dof2);
  }

69

70
  MeshDistributor::MeshDistributor()
71
    : problemStat(0),
72
      initialized(false),
73
      name("parallel"),
74 75 76 77 78
      feSpace(NULL),
      mesh(NULL),
      refineManager(NULL),
      info(10),
      partitioner(NULL),
79
      nRankDofs(0),
80
      nOverallDofs(0),
81
      rstart(0),
82
      deserialized(false),
83
      writeSerializationFile(false),
84
      repartitioningAllowed(false),
85
      repartitionIthChange(20),
86 87
      nMeshChangesAfterLastRepartitioning(0),
      repartitioningCounter(0),
88
      debugOutputDir(""),
Thomas Witkowski's avatar
Thomas Witkowski committed
89 90
      lastMeshChangeIndex(0),
      createBoundaryDofFlag(0)
91
  {
92
    FUNCNAME("MeshDistributor::ParalleDomainBase()");
Thomas Witkowski's avatar
Thomas Witkowski committed
93

94 95 96
    mpiRank = MPI::COMM_WORLD.Get_rank();
    mpiSize = MPI::COMM_WORLD.Get_size();
    mpiComm = MPI::COMM_WORLD;
97 98

    int tmp = 0;
99
    Parameters::get(name + "->repartitioning", tmp);
100
    repartitioningAllowed = (tmp > 0);
101

102 103
    Parameters::get(name + "->debug output dir", debugOutputDir);
    Parameters::get(name + "->repartition ith change", repartitionIthChange);
104 105

    tmp = 0;
106
    Parameters::get(name + "->log main rank", tmp);
107
    Msg::outputMainRank = (tmp > 0);
108

109
    string partStr = "parmetis";
110
    Parameters::get(name + "->partitioner", partStr);
111 112 113 114

    if (partStr == "parmetis") 
      partitioner = new ParMetisPartitioner(&mpiComm);

Thomas Witkowski's avatar
Thomas Witkowski committed
115 116
    if (partStr == "zoltan") {
#ifdef HAVE_ZOLTAN
117
      partitioner = new ZoltanPartitioner(&mpiComm);
Thomas Witkowski's avatar
Thomas Witkowski committed
118
#else
Thomas Witkowski's avatar
Thomas Witkowski committed
119
      ERROR_EXIT("AMDiS was compiled without Zoltan support. Therefore you cannot make use of it!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
120 121
#endif
    }
122

123 124 125
    if (partStr == "checker")
      partitioner = new CheckerPartitioner(&mpiComm);

Thomas Witkowski's avatar
Thomas Witkowski committed
126 127 128
    if (partStr == "simple")
      partitioner = new SimplePartitioner(&mpiComm);

Thomas Witkowski's avatar
Thomas Witkowski committed
129
    tmp = 0;
130
    Parameters::get(name + "->box partitioning", tmp);
Thomas Witkowski's avatar
Thomas Witkowski committed
131 132
    partitioner->setBoxPartitioning(static_cast<bool>(tmp));

133
    TEST_EXIT(partitioner)("Could not create partitioner \"%s\"!\n", partStr.c_str());
134 135
  }

Thomas Witkowski's avatar
Thomas Witkowski committed
136

137
  void MeshDistributor::initParallelization()
138
  {
139
    FUNCNAME("MeshDistributor::initParallelization()");
140

141 142 143
    if (initialized)
      return;

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

147 148
    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");
149

150 151
    elObjects.setFeSpace(feSpace);

152 153 154
    // 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).
155
    if (deserialized) {
156 157
      updateMacroElementInfo();

158
      setRankDofs();
159

160
      removePeriodicBoundaryConditions();
161

162 163
      macroElIndexMap.clear();
      macroElIndexTypeMap.clear();
164

165
      for (vector<MacroElement*>::iterator it = allMacroElements.begin();
166
	   it != allMacroElements.end(); ++it) {
167 168 169 170
	macroElIndexMap[(*it)->getIndex()] = (*it)->getElement();
	macroElIndexTypeMap[(*it)->getIndex()] = (*it)->getElType();
      }

171 172
      createBoundaryDofs();

Thomas Witkowski's avatar
Thomas Witkowski committed
173
#if (DEBUG != 0)
174
      ParallelDebug::writeDebugFile(*this, debugOutputDir + "mpi-dbg", "dat");
Thomas Witkowski's avatar
Thomas Witkowski committed
175
#endif    
176 177

      initialized = true;
178
      return;
179
    }
180

181

182 183 184 185 186
    // 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();

187 188 189 190
    // For later mesh repartitioning, we need to store some information about the
    // macro mesh.
    createMacroElementInfo();

191
    // create an initial partitioning of the mesh
192
    partitioner->createInitialPartitioning();
193

194
    // set the element weights, which are 1 at the very first begin
195
    setInitialElementWeights();
196 197

    // and now partition the mesh    
198 199
    bool partitioningSucceed = partitioner->partition(elemWeights, INITIAL);
    TEST_EXIT(partitioningSucceed)("Initial partitioning does not work!\n");
200
    partitioner->createPartitionMap(partitionMap);
201

202

203
#if (DEBUG != 0)    
204 205
    debug::ElementIdxToDofs elMap;
    debug::createSortedDofs(mesh, elMap);
206 207
#endif

208
    if (mpiRank == 0) {
209
#if (DEBUG != 0)    
210
      int writePartMesh = 1;
211 212 213
#else
      int writePartMesh = 0;
#endif
214
      Parameters::get("dbg->write part mesh", writePartMesh);
215

216
      if (writePartMesh > 0) {
217
	debug::writeElementIndexMesh(mesh, debugOutputDir + "elementIndex.vtu");
218
	ParallelDebug::writePartitioning(*this, debugOutputDir + "part.vtu");
219
      }
220
    }
221

222

223
    // === Create interior boundary information. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
224

225
    createInteriorBoundaryInfo();
Thomas Witkowski's avatar
Thomas Witkowski committed
226

227
#if (DEBUG != 0)
228
    ParallelDebug::printBoundaryInfo(*this);
229 230
#endif

231 232 233
    
    // === Remove neighbourhood relations due to periodic bounday conditions. ===

234 235 236 237 238
    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))) {
239 240 241

	  int neighIndex = (*it)->getNeighbour(i)->getIndex();

242 243 244 245 246
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

	  macroElementNeighbours[(*it)->getIndex()][i] = -1;
247
	  macroElementNeighbours[neighIndex][(*it)->getOppVertex(i)] = -1;
248 249 250 251 252 253 254 255 256
	}
      }
    }

    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))) {
257 258 259

	  int neighIndex = (*it)->getNeighbour(i)->getIndex();

260 261 262 263 264
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

	  macroElementNeighbours[(*it)->getIndex()][i] = -1;
265
	  macroElementNeighbours[neighIndex][(*it)->getOppVertex(i)] = -1;
266 267 268
	}
      }
    }
269

Thomas Witkowski's avatar
n  
Thomas Witkowski committed
270 271 272
    // === Remove all macro elements that are not part of the rank partition. ===

    removeMacroElements();
273

274 275
    // === Create new global and local DOF numbering. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
276

277 278 279
    // 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.
280
    for (map<BoundaryType, VertexVector*>::iterator it = mesh->getPeriodicAssociations().begin();
281 282
	 it != mesh->getPeriodicAssociations().end(); ++it)
      const_cast<DOFAdmin&>(mesh->getDofAdmin(0)).removeDOFContainer(dynamic_cast<DOFContainer*>(it->second));
283

284
    updateLocalGlobalNumbering();
285

286 287 288 289 290 291
    // === In 3D we have to make some test, if the resulting mesh is valid. If   ===
    // === it is not valid, there is no possiblity yet to fix this problem, just ===
    // === exit with an error message.                                           ===
    
    check3dValidMesh();

292 293
    // === If in debug mode, make some tests. ===

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

297
    ParallelDebug::testAllElements(*this);
298
    debug::testSortedDofs(mesh, elMap);
299
    ParallelDebug::testInteriorBoundary(*this);
Thomas Witkowski's avatar
Thomas Witkowski committed
300

301
    debug::writeMesh(feSpace, -1, debugOutputDir + "macro_mesh");   
302 303

    MSG("Debug mode tests finished!\n");
304
#endif
305

306
    // === Create periodic DOF mapping, if there are periodic boundaries. ===
307

308
    createPeriodicMap();
309

310 311 312
#if (DEBUG != 0)
    ParallelDebug::testPeriodicBoundary(*this);
#endif
313

314
    // === Global refinements. ===
315
    
Thomas Witkowski's avatar
Thomas Witkowski committed
316
    int globalRefinement = 0;
317
    Parameters::get(mesh->getName() + "->global refinements", globalRefinement);
318
    
Thomas Witkowski's avatar
Thomas Witkowski committed
319
    if (globalRefinement > 0) {
320
      refineManager->globalRefine(mesh, globalRefinement);
321

322
      updateLocalGlobalNumbering();
323 324

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

327
      createPeriodicMap();
328 329 330 331

#if (DEBUG != 0)
    ParallelDebug::testPeriodicBoundary(*this);
#endif
Thomas Witkowski's avatar
Thomas Witkowski committed
332
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
333

334

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

337
    setRankDofs();
Thomas Witkowski's avatar
Thomas Witkowski committed
338

339

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

342
    removePeriodicBoundaryConditions();
343 344

    initialized = true;
345 346
  }

347

348
  void MeshDistributor::addProblemStat(ProblemStatSeq *probStat)
349
  {
350
    FUNCNAME("MeshDistributor::addProblemStat()");
351 352

    if (feSpace != NULL) {
353
      vector<FiniteElemSpace*> feSpaces = probStat->getFeSpaces();
354
      for (unsigned int i = 0; i < feSpaces.size(); i++) {
355 356 357 358 359
	MSG("MESH %p <-> %p   BF %p <-> %p\n",
	    feSpace->getMesh(),
	    feSpaces[i]->getMesh(),
	    feSpace->getBasisFcts(),
	    feSpaces[i]->getBasisFcts());
360 361 362 363
	TEST_EXIT(feSpace == feSpaces[i])
	  ("Parallelizaton is not supported for multiple FE spaces!\n");
      }
    } else {
364
      feSpace = probStat->getFeSpace(0);
365
      mesh = feSpace->getMesh();
366
      info = probStat->getInfo();
367 368 369
      
      TEST_EXIT(mesh->getNumberOfDOFAdmin() == 1)
	("Only meshes with one DOFAdmin are supported!\n");
370
      TEST_EXIT(mesh->getDofAdmin(0).getNumberOfPreDofs(VERTEX) == 0)
371 372 373 374 375 376 377 378 379 380 381 382 383
	("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());
      }

384
      partitioner->setMesh(mesh);
385 386 387 388
    }

    // Create parallel serialization file writer, if needed.
    int writeSerialization = 0;
389
    Parameters::get(probStat->getName() + "->output->write serialization",  
390
		    writeSerialization);
391
    if (writeSerialization && !writeSerializationFile) {
392
      string filename = "";
393
      Parameters::get(name + "->output->serialization filename", filename);
394 395 396
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel serialization file!\n");
397 398

      int tsModulo = -1;
399
      Parameters::get(probStat->getName() + "->output->write every i-th timestep", 
400
		      tsModulo);
401
      
402
      probStat->getFileWriterList().push_back(new Serializer<MeshDistributor>(this, filename, tsModulo));
403 404
      writeSerializationFile = true;
    }    
405 406

    int readSerialization = 0;
407
    Parameters::get(probStat->getName() + "->input->read serialization", 
408
		    readSerialization);
409
    if (readSerialization) {
410
      string filename = "";
411
      Parameters::get(probStat->getName() + "->input->serialization filename", 
412
		      filename);
413
      filename += ".p" + lexical_cast<string>(mpiRank);
414
      MSG("Start deserialization with %s\n", filename.c_str());
415
      ifstream in(filename.c_str());
416 417 418 419

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

420 421 422 423 424
      // Read the revision number of the AMDiS version which was used to create 
      // the serialization file.
      int revNumber = -1;
      SerUtil::deserialize(in, revNumber);

425
      probStat->deserialize(in);
426
      in.close();
427 428
      MSG("Deserialization from file: %s\n", filename.c_str());

429
      filename = "";
430
      Parameters::get(name + "->input->serialization filename", filename);
431 432 433 434
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel deserialization file!\n");
      
435
      string rankFilename = filename + ".p" + lexical_cast<string>(mpiRank);
436 437 438 439
      in.open(rankFilename.c_str());
      
      TEST_EXIT(!in.fail())("Could not open parallel deserialization file: %s\n",
			    filename.c_str());
440 441 442 443 444

      // Read the revision number of the AMDiS version which was used to create 
      // the serialization file.
      revNumber = -1;
      SerUtil::deserialize(in, revNumber);
445 446 447 448 449
      
      deserialize(in);
      in.close();
      MSG("Deserializtion of mesh distributor from file: %s\n", rankFilename.c_str());
      deserialized = true;
450 451
    }

452
    problemStat.push_back(probStat);
453 454 455 456 457

    // If the mesh distributor is already initialized, don't forgett to set rank
    // DOFs object to the matrices and vectors of the added stationary problem.

    if (initialized)
458
      setRankDofs(probStat);
459 460 461
  }


462 463 464 465 466 467 468 469 470 471 472
  void MeshDistributor::addProblemStatGlobal(ProblemStatSeq *probStat)
  {
    FUNCNAME("MeshDistributor::addProblemStatGlobal()");

    if (globalMeshDistributor == NULL)
      globalMeshDistributor = new MeshDistributor();

    globalMeshDistributor->addProblemStat(probStat);
  }


473
  void MeshDistributor::exitParallelization()
474
  {}
475

476
  
477
  void MeshDistributor::testForMacroMesh()
478
  {
479
    FUNCNAME("MeshDistributor::testForMacroMesh()");
480 481 482 483 484 485 486

    int nMacroElements = 0;

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

      TEST_EXIT(elInfo->getType() == 0)
	("Only macro elements with level 0 are supported!\n");
491 492 493 494 495 496 497 498 499 500
      
      nMacroElements++;

      elInfo = stack.traverseNext(elInfo);
    }

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

501

502
  void MeshDistributor::synchVector(SystemVector &vec)
Thomas Witkowski's avatar
Thomas Witkowski committed
503
  {
504
    int nComponents = vec.getSize();
505
    StdMpi<vector<double> > stdMpi(mpiComm);
Thomas Witkowski's avatar
Thomas Witkowski committed
506 507 508

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); ++sendIt) {
509
      vector<double> dofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
510 511 512 513 514 515 516
      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])]);
517 518
      }

Thomas Witkowski's avatar
Thomas Witkowski committed
519
      stdMpi.send(sendIt->first, dofs);
520 521 522
    }

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

526
    stdMpi.startCommunication();
527 528

    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
529 530
	 recvIt != recvDofs.end(); ++recvIt) {
      int nRecvDofs = recvIt->second.size();
531 532

      int counter = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
533 534 535 536 537
      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++];
538 539 540 541
      }
    }
  }

542

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
  void MeshDistributor::check3dValidMesh()
  {
    FUNCNAME("MeshDistributor::check3dValidMesh()");

    if (mesh->getDim() != 3)
      return;

    std::set<DofEdge> allEdges;
    std::set<int> rankMacroEls;

    TraverseStack stack;
    ElInfo *elInfo = stack.traverseFirst(mesh, 0, Mesh::CALL_EL_LEVEL);
    while (elInfo) {
      for (int i = 0; i < 4; i++) {
	ElementObjectData elData(elInfo->getElement()->getIndex(), i);
	allEdges.insert(elObjects.getEdgeLocalMap(elData));
      }

      rankMacroEls.insert(elInfo->getElement()->getIndex());

      elInfo = stack.traverseNext(elInfo);
    }

566 567

    FixRefinementPatch::connectedEdges.clear();
568
    bool valid3dMesh = true;
569 570 571 572 573 574 575 576

    for (std::set<DofEdge>::iterator it = allEdges.begin(); it != allEdges.end(); ++it) {
      vector<ElementObjectData>& edgeEls = elObjects.getElements(*it);

      TEST_EXIT_DBG(edgeEls.size() > 0)
	("No edge %d/%d in elObjDB!\n", it->first, it->second);

      std::set<int> el0, el1;
577
      map<int, int> edgeNoInEl;
578 579 580

      for (unsigned int i = 0; i < edgeEls.size(); i++) {
	if (rankMacroEls.count(edgeEls[i].elIndex)) {
581 582 583 584
	  if (el0.empty())
	    el0.insert(edgeEls[i].elIndex);
	  else
	    el1.insert(edgeEls[i].elIndex);
585 586 587 588

	  edgeNoInEl[edgeEls[i].elIndex] = edgeEls[i].ithObject;
	}
      }
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
            
      TEST_EXIT_DBG(!el0.empty())("Should not happen!\n");

      if (el1.empty())
	continue;
      
      bool found = false;      
      do {
	found = false;
	for (std::set<int>::iterator elIt = el0.begin(); elIt != el0.end(); ++elIt) {
	  for (int i = 0; i < 4; i++) {
	    int neighEl = macroElementNeighbours[*elIt][i];
	    if (neighEl != -1 && el1.count(neighEl)) {
	      el0.insert(neighEl);
	      el1.erase(neighEl);
	      found = true;
	    }
	  }
	  
	  if (found)
	    break;
	}
      } while (found);
      
      if (!el1.empty()) {
614 615 616 617
	valid3dMesh = false;

	MSG_DBG("Unvalid 3D mesh with %d (%d - %d) elements on this edge!\n", 
		edgeEls.size(), el0.size(), el1.size());
618

619 620 621 622 623 624 625
	for (std::set<int>::iterator elIt0 = el0.begin(); elIt0 != el0.end(); ++elIt0) {
	  for (std::set<int>::iterator elIt1 = el1.begin(); elIt1 != el1.end(); ++elIt1) {

	    TEST_EXIT_DBG(macroElIndexMap.count(*elIt0))("Should not happen!\n");
	    TEST_EXIT_DBG(macroElIndexMap.count(*elIt1))("Should not happen!\n");
	    TEST_EXIT_DBG(edgeNoInEl.count(*elIt0))("Should not happen!\n");
	    TEST_EXIT_DBG(edgeNoInEl.count(*elIt1))("Should not happen!\n");
626

627 628 629 630 631 632 633 634 635 636 637 638
	    pair<Element*, int> edge0 = 
	      make_pair(macroElIndexMap[*elIt0], edgeNoInEl[*elIt0]);
	    pair<Element*, int> edge1 = 
	      make_pair(macroElIndexMap[*elIt1], edgeNoInEl[*elIt1]);

	    DofEdge dofEdge0 = edge0.first->getEdge(edge0.second);
	    DofEdge dofEdge1 = edge1.first->getEdge(edge1.second);

	    WorldVector<double> c0, c1;
	    mesh->getDofIndexCoords(dofEdge0.first, feSpace, c0);
	    mesh->getDofIndexCoords(dofEdge0.second, feSpace, c1);

639 640 641 642
	    MSG_DBG("FOUND EDGE: %d %d with coords %f %f %f   %f %f %f\n",
		    dofEdge0.first, dofEdge0.second, 
		    c0[0], c0[1], c0[2],
		    c1[0], c1[1], c1[2]);
643 644 645 646 647 648 649 650 651

	    TEST_EXIT_DBG(dofEdge0 == dofEdge1)("Should noth happen!\n");

	    FixRefinementPatch::connectedEdges.push_back(make_pair(edge0, edge1));
	    FixRefinementPatch::connectedEdges.push_back(make_pair(edge1, edge0));
	  }
	}
      }
    }
652 653

    MSG_DBG("Mesh is 3d valid mesh: %d\n", valid3dMesh);
654 655 656
  }


657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
  void MeshDistributor::getAllBoundaryDofs(DofContainer& dofs)
  {
    FUNCNAME("MeshDistributor::getAllBoundaryDofs()");

    DofContainerSet dofSet;

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); ++sendIt)
      for (DofContainer::iterator dofIt = sendIt->second.begin();
	   dofIt != sendIt->second.end(); ++dofIt)
	dofSet.insert(*dofIt);

    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt)
      for (DofContainer::iterator dofIt = recvIt->second.begin();
	   dofIt != recvIt->second.end(); ++dofIt)
	dofSet.insert(*dofIt);
    
    dofs.clear();
    dofs.insert(dofs.begin(), dofSet.begin(), dofSet.end());
  }


680
  void MeshDistributor::setRankDofs(ProblemStatSeq *probStat)
681
  {
682
    int nComponents = probStat->getNumComponents();
683 684
    for (int i = 0; i < nComponents; i++) {
      for (int j = 0; j < nComponents; j++)
685 686
	if (probStat->getSystemMatrix(i, j))
	  probStat->getSystemMatrix(i, j)->setRankDofs(isRankDof);
687

688
      TEST_EXIT_DBG(probStat->getRhs()->getDOFVector(i))("No RHS vector!\n");
689 690
      TEST_EXIT_DBG(probStat->getSolution()->getDOFVector(i))
	("No solution vector!\n");
691
      
692 693
      probStat->getRhs()->getDOFVector(i)->setRankDofs(isRankDof);
      probStat->getSolution()->getDOFVector(i)->setRankDofs(isRankDof);
694 695 696 697
    }    
  }


698 699
  void MeshDistributor::setRankDofs()
  {
700 701
    for (unsigned int i = 0; i < problemStat.size(); i++) 
      setRankDofs(problemStat[i]);
702 703 704
  }


705 706
  void MeshDistributor::removePeriodicBoundaryConditions()
  {
707 708
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

709
    // Remove periodic boundaries in boundary manager on matrices and vectors.
710 711
    for (unsigned int i = 0; i < problemStat.size(); i++) {
      int nComponents = problemStat[i]->getNumComponents();
712 713 714

      for (int j = 0; j < nComponents; j++) {
	for (int k = 0; k < nComponents; k++) {
715
	  DOFMatrix* mat = problemStat[i]->getSystemMatrix(j, k);
716
	  if (mat && mat->getBoundaryManager())
717
	    removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(mat->getBoundaryManager()->getBoundaryConditionMap()));
718 719
	}
	
720 721
	if (problemStat[i]->getSolution()->getDOFVector(j)->getBoundaryManager())
	  removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(problemStat[i]->getSolution()->getDOFVector(j)->getBoundaryManager()->getBoundaryConditionMap()));
722
	
723 724
	if (problemStat[i]->getRhs()->getDOFVector(j)->getBoundaryManager())
	  removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(problemStat[i]->getRhs()->getDOFVector(j)->getBoundaryManager()->getBoundaryConditionMap()));
725 726 727 728 729 730 731 732 733 734
      }
    }

    // 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);
    }    
735 736 737

    // Remove periodic vertex associations
    mesh->getPeriodicAssociations().clear();
738 739 740 741
  }


  void MeshDistributor::removePeriodicBoundaryConditions(BoundaryIndexMap& boundaryMap)
Thomas Witkowski's avatar
Thomas Witkowski committed
742 743 744 745 746 747 748 749 750 751 752
  {
    BoundaryIndexMap::iterator it = boundaryMap.begin();
    while (it != boundaryMap.end()) {
      if (it->second->isPeriodic())
	boundaryMap.erase(it++);
      else
	++it;      
    }    
  }


753
  void MeshDistributor::checkMeshChange(bool tryRepartition)
754
  {
755
    FUNCNAME("MeshDistributor::checkMeshChange()");
756

757 758
    double first = MPI::Wtime();

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

765
    if (recvAllValues == 0)
766 767
      return;

768 769
    // === At least one rank mesh has been changed, so the boundaries must be ===
    // === adapted to the new mesh structure.                                 ===
770
   
771
    do {
772 773
      bool meshChanged = false;

774 775
      // To check the interior boundaries, the ownership of the boundaries is not 
      // important. Therefore, we add all boundaries to one boundary container.
776
      RankToBoundMap allBound;
Thomas Witkowski's avatar
Thomas Witkowski committed
777 778

      for (InteriorBoundary::iterator it(myIntBoundary); !it.end(); ++it)
779 780
	if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	    (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
781
 	  allBound[it.getRank()].push_back(*it);
Thomas Witkowski's avatar
Thomas Witkowski committed
782 783

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

788 789
      for (InteriorBoundary::iterator it(periodicBoundary); !it.end(); ++it) {
	if (it.getRank() == mpiRank) {
790 791 792 793 794
	  if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	      (mesh->getDim() == 3 && it->rankObj.subObj == FACE)) {
	    MeshStructure elCode;
	    elCode.init(it->rankObj);
	    
795
	    MeshManipulation mm(feSpace);
796
	    meshChanged |= mm.fitElementToMeshCode(elCode, it->neighObj);
797
	  }
798 799 800 801 802 803
	} else {
	  if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	      (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
	    allBound[it.getRank()].push_back(*it);	
	}
      }
804

805

806
      // === Check the boundaries and adapt mesh if necessary. ===
807
      MSG_DBG("Run checkAndAdaptBoundary ...\n");
808

809
      meshChanged |= checkAndAdaptBoundary(allBound);
810 811 812

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

813
      int sendValue = static_cast<int>(meshChanged);
814 815
      recvAllValues = 0;
      mpiComm.Allreduce(&sendValue, &recvAllValues, 1, MPI_INT, MPI_SUM);
816 817

      MSG("Mesh changed on %d ranks!\n", recvAllValues);
818
    } while (recvAllValues != 0);
819

820
#if (DEBUG != 0)
821
    debug::writeMesh(feSpace, -1, debugOutputDir + "mesh");
822 823
#endif

824

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

827 828
    updateLocalGlobalNumbering();

829

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

Thomas Witkowski's avatar
Thomas Witkowski committed
832
    createPeriodicMap();
833

834 835 836
#if (DEBUG != 0)
    ParallelDebug::testPeriodicBoundary(*this);
#endif
837 838


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

841
    nMeshChangesAfterLastRepartitioning++;
842

843 844 845 846

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

847 848
    if (tryRepartition &&
	repartitioningAllowed && 
849 850 851
	nMeshChangesAfterLastRepartitioning >= repartitionIthChange) {
      repartitionMesh();
      nMeshChangesAfterLastRepartitioning = 0;
852 853 854 855
    } else {
      MSG_DBG("Repartitioning not tried because tryRepartitioning = %d   reparttitioningAllowed = %d   nMeshChange =%d    repartitionIthChange = %d\n",
	      tryRepartition, repartitioningAllowed, 
	      nMeshChangesAfterLastRepartitioning, repartitionIthChange);
856
    }
857 858 859

    // === Print imbalance factor. ===

860 861 862 863 864 865 866 867
    printImbalanceFactor();
  }

  
  void MeshDistributor::printImbalanceFactor()
  {
    FUNCNAME("MeshDistributor::printImbalanceFactor()");