Liebe Gitlab-Nutzerin, lieber Gitlab-Nutzer,
es ist nun möglich sich mittels des ZIH-Logins/LDAP an unserem Dienst anzumelden. Die Konten der externen Nutzer:innen sind über den Reiter "Standard" erreichbar.
Die Administratoren


Dear Gitlab user,
it is now possible to log in to our service using the ZIH login/LDAP. The accounts of external users can be accessed via the "Standard" tab.
The administrators

MeshDistributor.cc 60.9 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 74
      nMeshChangesAfterLastRepartitioning(0),
      repartitioningCounter(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
	debug::writeElementIndexMesh(mesh, debugOutputDir + "elementIndex.vtu");
171
	ParallelDebug::writePartitioning(*this, debugOutputDir + "part.vtu");
172
      }
173
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
174
#endif
175

176

177
    // === Create interior boundary information. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
178

179
    createInteriorBoundaryInfo();
Thomas Witkowski's avatar
Thomas Witkowski committed
180

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

185 186 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
    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;
	}
      }
    }
212

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

    removeMacroElements();
216

Thomas Witkowski's avatar
n  
Thomas Witkowski committed
217

218 219
    // === Create new global and local DOF numbering. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
220

221 222 223
    // 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.
224
    for (map<BoundaryType, VertexVector*>::iterator it = mesh->getPeriodicAssociations().begin();
225 226
	 it != mesh->getPeriodicAssociations().end(); ++it)
      const_cast<DOFAdmin&>(mesh->getDofAdmin(0)).removeDOFContainer(dynamic_cast<DOFContainer*>(it->second));
227

228
    updateLocalGlobalNumbering();
229

230

231 232
    // === If in debug mode, make some tests. ===

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

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

242
    debug::writeMesh(feSpace, -1, debugOutputDir + "macro_mesh");   
243 244

    MSG("Debug mode tests finished!\n");
245
#endif
246

247

248 249
    // === Create periodic dof mapping, if there are periodic boundaries. ===

250
    createPeriodicMap();
251

252

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

261
      updateLocalGlobalNumbering();
262 263

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

266
      createPeriodicMap();
Thomas Witkowski's avatar
Thomas Witkowski committed
267
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
268

269

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

272
    setRankDofs();
Thomas Witkowski's avatar
Thomas Witkowski committed
273

274

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

277
    removePeriodicBoundaryConditions();
278 279
  }

280

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

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

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

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

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

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

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

    probStat.push_back(probVec);
  }


373
  void MeshDistributor::exitParallelization()
374
  {}
375

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

    int nMacroElements = 0;

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

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

      elInfo = stack.traverseNext(elInfo);
    }

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

401

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

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

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

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

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

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


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

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

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

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

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

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

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

471

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


491 492
  void MeshDistributor::removePeriodicBoundaryConditions()
  {
493 494
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

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

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


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


539
  void MeshDistributor::checkMeshChange()
540
  {
541
    FUNCNAME("MeshDistributor::checkMeshChange()");
542

543 544
    double first = MPI::Wtime();

545

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

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

555 556
    // === At least one rank mesh has been changed, so the boundaries must be ===
    // === adapted to the new mesh structure.                                 ===
557
   
558
    do {
559 560
      bool meshChanged = false;

561 562
      // To check the interior boundaries, the ownership of the boundaries is not 
      // important. Therefore, we add all boundaries to one boundary container.
563
      RankToBoundMap allBound;
Thomas Witkowski's avatar
Thomas Witkowski committed
564 565

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

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

575 576
      for (InteriorBoundary::iterator it(periodicBoundary); !it.end(); ++it) {
	if (it.getRank() == mpiRank) {
577 578 579 580 581 582 583 584 585 586 587 588 589 590
	  if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	      (mesh->getDim() == 3 && it->rankObj.subObj == FACE)) {
	    MeshStructure elCode;
	    elCode.init(it->rankObj);
	    
	    MeshManipulation meshManipulation(feSpace);
	    meshChanged |= 
	      !(meshManipulation.startFitElementToMeshCode(elCode, 
							   it->neighObj.el,
							   it->neighObj.subObj,
							   it->neighObj.ithObj, 
							   it->neighObj.elType,
							   it->neighObj.reverseMode));
	  }
591 592 593 594 595 596
	} else {
	  if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	      (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
	    allBound[it.getRank()].push_back(*it);	
	}
      }
597

598

599
      // === Check the boundaries and adapt mesh if necessary. ===
600 601 602 603
#if (DEBUG != 0)
      MSG("Run checkAndAdaptBoundary ...\n");
#endif

604
      meshChanged |= checkAndAdaptBoundary(allBound);
605 606 607

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

608
      int sendValue = static_cast<int>(meshChanged);
609 610
      recvAllValues = 0;
      mpiComm.Allreduce(&sendValue, &recvAllValues, 1, MPI_INT, MPI_SUM);
611 612 613 614

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

617
#if (DEBUG != 0)
618
    debug::writeMesh(feSpace, -1, debugOutputDir + "mesh");
619 620 621
#endif

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

623 624
    updateLocalGlobalNumbering();

625 626 627

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

Thomas Witkowski's avatar
Thomas Witkowski committed
628
    createPeriodicMap();
629 630 631 632 633

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


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

636
    nMeshChangesAfterLastRepartitioning++;
637

638 639 640 641
    if (repartitioningAllowed && 
	nMeshChangesAfterLastRepartitioning >= repartitionIthChange) {
      repartitionMesh();
      nMeshChangesAfterLastRepartitioning = 0;
642
    }
643 644 645
  }

  
646
  bool MeshDistributor::checkAndAdaptBoundary(RankToBoundMap &allBound)
647
  {
648
    FUNCNAME("MeshDistributor::checkAndAdaptBoundary()");
649 650 651

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

656
      for (vector<AtomicBoundary>::iterator boundIt = it->second.begin();
657 658
	   boundIt != it->second.end(); ++boundIt) {
	MeshStructure elCode;
659
	elCode.init(boundIt->rankObj);
660 661 662 663
	sendCodes[it->first].push_back(elCode);
      }
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
664
    StdMpi<MeshCodeVec> stdMpi(mpiComm, true);
665
    stdMpi.send(sendCodes);
666
    stdMpi.recv(allBound);
667
    stdMpi.startCommunication<uint64_t>(MPI_UNSIGNED_LONG);
668
 
669
    // === Compare received mesh structure codes. ===
670
    
671
    bool meshChanged = false;
672

673
    for (RankToBoundMap::iterator it = allBound.begin(); it != allBound.end(); ++it) {
674
     
675 676
      MeshCodeVec &recvCodes = stdMpi.getRecvData()[it->first];
      int i = 0;
677
      
678
      for (vector<AtomicBoundary>::iterator boundIt = it->second.begin();
679
	   boundIt != it->second.end(); ++boundIt, i++) {
680

681 682
	MeshStructure elCode;	
	elCode.init(boundIt->rankObj);
683

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

687
	  MeshManipulation meshManipulation(feSpace);
688
	  meshChanged |=
689 690 691 692 693 694
	    meshManipulation.startFitElementToMeshCode(recvCodes[i], 
						       boundIt->rankObj.el,
						       boundIt->rankObj.subObj,
						       boundIt->rankObj.ithObj, 
						       boundIt->rankObj.elType,
						       boundIt->rankObj.reverseMode);
695
 	}
696 697 698
      }
    }

699
    return meshChanged;
700
  }
701 702


703
  void MeshDistributor::serialize(ostream &out, DofContainer &data)
Thomas Witkowski's avatar
Thomas Witkowski committed
704
  {    
705
    int vecSize = data.size();
706
    SerUtil::serialize(out, vecSize);
707
    for (int i = 0; i < vecSize; i++) {
708
      int dofIndex = *(data[i]);
709
      SerUtil::serialize(out, dofIndex);
710 711 712 713
    }
  }


714 715
  void MeshDistributor::deserialize(istream &in, DofContainer &data,
				    map<int, const DegreeOfFreedom*> &dofMap)
716
  {
717
    FUNCNAME("MeshDistributor::deserialize()");
718 719

    int vecSize = 0;
720
    SerUtil::deserialize(in, vecSize);
721
    data.clear();
722 723 724
    data.resize(vecSize);
    for (int i = 0; i < vecSize; i++) {
      int dofIndex = 0;
725
      SerUtil::deserialize(in, dofIndex);
726 727 728 729 730 731 732 733 734

      TEST_EXIT_DBG(dofMap.count(dofIndex) != 0)
	("Dof index could not be deserialized correctly!\n");

      data[i] = dofMap[dofIndex];
    }
  }


735
  void MeshDistributor::serialize(ostream &out, RankToDofContainer &data)
736 737
  {
    int mapSize = data.size();
738
    SerUtil::serialize(out, mapSize);
739 740
    for (RankToDofContainer::iterator it = data.begin(); it != data.end(); ++it) {
      int rank = it->first;
741
      SerUtil::serialize(out, rank);
742 743 744 745 746
      serialize(out, it->second);
    }
  }

  
747 748
  void MeshDistributor::deserialize(istream &in, RankToDofContainer &data,
				    map<int, const DegreeOfFreedom*> &dofMap)
749
  {
750 751
    data.clear();

752
    int mapSize = 0;
753
    SerUtil::deserialize(in, mapSize);
754 755
    for (int i = 0; i < mapSize; i++) {
      int rank = 0;
756
      SerUtil::deserialize(in, rank);
757 758 759 760
      deserialize(in, data[rank], dofMap);      
    }
  }

761

762
  void MeshDistributor::setInitialElementWeights() 
763
  {
764
    FUNCNAME("MeshDistributor::setInitialElementWeights()");
765 766

    elemWeights.clear();
767
      
768
    string filename = "";
769 770 771 772
    GET_PARAMETER(0, mesh->getName() + "->macro weights", &filename);
    if (filename != "") {
      MSG("Read macro weights from %s\n", filename.c_str());

773 774
      ifstream infile;
      infile.open(filename.c_str(), ifstream::in);
775 776 777 778 779 780
      while (!infile.eof()) {
	int elNum, elWeight;
	infile >> elNum;
	if (infile.eof())
	  break;
	infile >> elWeight;
781

782 783
	elemWeights[elNum] = elWeight;
      }
784

785
      infile.close();
786
    } else {           
787
      TraverseStack stack;
788
      ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
789
      while (elInfo) {
790
	elemWeights[elInfo->getElement()->getIndex()] = 1.0;
791
	elInfo = stack.traverseNext(elInfo);
792 793 794 795
      }
    }
  }

796

797 798 799 800 801 802 803
  void MeshDistributor::repartitionMesh()
  {
    FUNCNAME("MeshDistributor::repartitionMesh()");

    TEST_EXIT(mesh->getNumberOfDOFAdmin() == 1)
      ("Only meshes with one DOFAdmin are supported!\n");