MeshDistributor.cc 67.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/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"
Thomas Witkowski's avatar
Thomas Witkowski committed
47
48
#include "ProblemVec.h"
#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

Thomas Witkowski's avatar
Thomas Witkowski committed
58
59
60
  const Flag MeshDistributor::BOUNDARY_SUBOBJ_SORTED     = 0X01L;
  const Flag MeshDistributor::BOUNDARY_EDGE_SCHUR        = 0X02L;

61
62
63
64
65
  inline bool cmpDofsByValue(const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2)
  {
    return (*dof1 < *dof2);
  }

66

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

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

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

99
100
    GET_PARAMETER(0, name + "->debug output dir", &debugOutputDir);
    GET_PARAMETER(0, name + "->repartition ith change", "%d", &repartitionIthChange);
101
102
103
104

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

106
107
108
109
110
111
    string partStr = "parmetis";
    GET_PARAMETER(0, name + "->partitioner", &partStr);

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

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

120
121
122
    if (partStr == "checker")
      partitioner = new CheckerPartitioner(&mpiComm);

Thomas Witkowski's avatar
Thomas Witkowski committed
123
124
125
    if (partStr == "simple")
      partitioner = new SimplePartitioner(&mpiComm);

Thomas Witkowski's avatar
Thomas Witkowski committed
126
127
128
129
    tmp = 0;
    GET_PARAMETER(0, name + "->box partitioning", "%d", &tmp);
    partitioner->setBoxPartitioning(static_cast<bool>(tmp));

130
    TEST_EXIT(partitioner)("Could not create partitioner \"%s\"!\n", partStr.c_str());
131
132
  }

Thomas Witkowski's avatar
Thomas Witkowski committed
133

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

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

141
142
    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");
143

Thomas Witkowski's avatar
Thomas Witkowski committed
144
#ifdef HAVE_ZOLTAN
145
146
147
    int a = 0;
    char *b = NULL;
    float zoltanVersion = 0.0;
148
    Zoltan_Initialize(a, &b, &zoltanVersion);
Thomas Witkowski's avatar
Thomas Witkowski committed
149
#endif
150

151
152
    elObjects.setFeSpace(feSpace);

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

159
      setRankDofs();
160

161
      removePeriodicBoundaryConditions();
162

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

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

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

      initialized = true;
177
      return;
178
    }
179

180

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

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

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

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

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

201

202
#if (DEBUG != 0)    
203
204
    debug::ElementIdxToDofs elMap;
    debug::createSortedDofs(mesh, elMap);
205
206
207
    if (mpiRank == 0) {
      int writePartMesh = 1;
      GET_PARAMETER(0, "dbg->write part mesh", "%d", &writePartMesh);
208

209
      if (writePartMesh > 0) {
210
	debug::writeElementIndexMesh(mesh, debugOutputDir + "elementIndex.vtu");
211
	ParallelDebug::writePartitioning(*this, debugOutputDir + "part.vtu");
212
      }
213
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
214
#endif
215

216

217
    // === Create interior boundary information. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
218

219
    createInteriorBoundaryInfo();
Thomas Witkowski's avatar
Thomas Witkowski committed
220

221
#if (DEBUG != 0)
222
    ParallelDebug::printBoundaryInfo(*this);
223
224
#endif

225
226
227
228
229
    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))) {
230
231
232

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

233
234
235
236
237
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

	  macroElementNeighbours[(*it)->getIndex()][i] = -1;
238
	  macroElementNeighbours[neighIndex][(*it)->getOppVertex(i)] = -1;
239
240
241
242
243
244
245
246
247
	}
      }
    }

    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))) {
248
249
250

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

251
252
253
254
255
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

	  macroElementNeighbours[(*it)->getIndex()][i] = -1;
256
	  macroElementNeighbours[neighIndex][(*it)->getOppVertex(i)] = -1;
257
258
259
	}
      }
    }
260

Thomas Witkowski's avatar
n  
Thomas Witkowski committed
261
262
263
    // === Remove all macro elements that are not part of the rank partition. ===

    removeMacroElements();
264

265
266
    // === Create new global and local DOF numbering. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
267

268
269
270
    // 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.
271
    for (map<BoundaryType, VertexVector*>::iterator it = mesh->getPeriodicAssociations().begin();
272
273
	 it != mesh->getPeriodicAssociations().end(); ++it)
      const_cast<DOFAdmin&>(mesh->getDofAdmin(0)).removeDOFContainer(dynamic_cast<DOFContainer*>(it->second));
274

275
    updateLocalGlobalNumbering();
276

277
278
279
280
281
282
    // === 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();

283
284
    // === If in debug mode, make some tests. ===

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

288
    ParallelDebug::testAllElements(*this);
289
    debug::testSortedDofs(mesh, elMap);
290
    ParallelDebug::testInteriorBoundary(*this);
Thomas Witkowski's avatar
Thomas Witkowski committed
291

292
    debug::writeMesh(feSpace, -1, debugOutputDir + "macro_mesh");   
293
294

    MSG("Debug mode tests finished!\n");
295
#endif
296

297
    // === Create periodic DOF mapping, if there are periodic boundaries. ===
298

299
    createPeriodicMap();
300

301
302
303
#if (DEBUG != 0)
    ParallelDebug::testPeriodicBoundary(*this);
#endif
304

305
    // === Global refinements. ===
306
    
Thomas Witkowski's avatar
Thomas Witkowski committed
307
    int globalRefinement = 0;
308
    GET_PARAMETER(0, mesh->getName() + "->global refinements", "%d", &globalRefinement);
309
    
Thomas Witkowski's avatar
Thomas Witkowski committed
310
    if (globalRefinement > 0) {
311
      refineManager->globalRefine(mesh, globalRefinement);
312

313
      updateLocalGlobalNumbering();
314
315

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

318
      createPeriodicMap();
319
320
321
322

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

325

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

328
    setRankDofs();
Thomas Witkowski's avatar
Thomas Witkowski committed
329

330

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

333
    removePeriodicBoundaryConditions();
334
335

    initialized = true;
336
337
  }

338

339
340
341
342
343
  void MeshDistributor::addProblemStat(ProblemVec *probVec)
  {
    FUNCNAME("MeshDistributor::addProblemVec()");

    if (feSpace != NULL) {
344
      vector<FiniteElemSpace*> feSpaces = probVec->getFeSpaces();
345
346
347
348
349
350
351
352
353
354
355
      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");
356
      TEST_EXIT(mesh->getDofAdmin(0).getNumberOfPreDofs(VERTEX) == 0)
357
358
359
360
361
362
363
364
365
366
367
368
369
	("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());
      }

370
      partitioner->setMesh(mesh);
371
372
373
374
    }

    // Create parallel serialization file writer, if needed.
    int writeSerialization = 0;
375
376
377
    GET_PARAMETER(0, probVec->getName() + "->output->write serialization", "%d", 
		  &writeSerialization);
    if (writeSerialization && !writeSerializationFile) {
378
      string filename = "";
379
380
381
382
      GET_PARAMETER(0, name + "->output->serialization filename", &filename);
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel serialization file!\n");
383
384
385
386
387

      int tsModulo = -1;
      GET_PARAMETER(0, probVec->getName() + "->output->write every i-th timestep", 
		    "%d", &tsModulo);
      
388
      probVec->getFileWriterList().push_back(new Serializer<MeshDistributor>(this, filename, tsModulo));
389
390
      writeSerializationFile = true;
    }    
391
392

    int readSerialization = 0;
393
394
    GET_PARAMETER(0, probVec->getName() + "->input->read serialization", "%d", 
		  &readSerialization);
395
    if (readSerialization) {
396
      string filename = "";
397
      GET_PARAMETER(0, probVec->getName() + "->input->serialization filename", &filename);
398
      filename += ".p" + lexical_cast<string>(mpiRank);
399
      MSG("Start deserialization with %s\n", filename.c_str());
400
      ifstream in(filename.c_str());
401
402
403
404

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

405
      probVec->deserialize(in);
406
      in.close();
407
408
      MSG("Deserialization from file: %s\n", filename.c_str());

409
410
411
412
413
414
      filename = "";
      GET_PARAMETER(0, name + "->input->serialization filename", &filename);
      
      TEST_EXIT(filename != "")
	("No filename defined for parallel deserialization file!\n");
      
415
      string rankFilename = filename + ".p" + lexical_cast<string>(mpiRank);
416
417
418
419
420
421
422
423
424
      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;
425
426
427
    }

    probStat.push_back(probVec);
428
429
430
431
432
433

    // 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)
      setRankDofs(probVec);
434
435
436
  }


437
  void MeshDistributor::exitParallelization()
438
  {}
439

440
  
441
  void MeshDistributor::testForMacroMesh()
442
  {
443
    FUNCNAME("MeshDistributor::testForMacroMesh()");
444
445
446
447
448
449
450

    int nMacroElements = 0;

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

      TEST_EXIT(elInfo->getType() == 0)
	("Only macro elements with level 0 are supported!\n");
455
456
457
458
459
460
461
462
463
464
      
      nMacroElements++;

      elInfo = stack.traverseNext(elInfo);
    }

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

465

466
  void MeshDistributor::synchVector(DOFVector<double> &vec)
467
  {
468
    StdMpi<vector<double> > stdMpi(mpiComm);
469
470

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
471
	 sendIt != sendDofs.end(); ++sendIt) {
472
      vector<double> dofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
473
474
      int nSendDofs = sendIt->second.size();
      dofs.reserve(nSendDofs);
475
      
Thomas Witkowski's avatar
Thomas Witkowski committed
476
477
      for (int i = 0; i < nSendDofs; i++)
	dofs.push_back(vec[*((sendIt->second)[i])]);
478
479
480
481

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

Thomas Witkowski's avatar
Thomas Witkowski committed
482
483
484
    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
	 recvIt != recvDofs.end(); ++recvIt)
      stdMpi.recv(recvIt->first, recvIt->second.size());
485

486
    stdMpi.startCommunication();
487

Thomas Witkowski's avatar
Thomas Witkowski committed
488
489
490
491
492
    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];
  }
493
494


495
  void MeshDistributor::synchVector(SystemVector &vec)
Thomas Witkowski's avatar
Thomas Witkowski committed
496
  {
497
    int nComponents = vec.getSize();
498
    StdMpi<vector<double> > stdMpi(mpiComm);
Thomas Witkowski's avatar
Thomas Witkowski committed
499
500
501

    for (RankToDofContainer::iterator sendIt = sendDofs.begin();
	 sendIt != sendDofs.end(); ++sendIt) {
502
      vector<double> dofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
503
504
505
506
507
508
509
      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])]);
510
511
      }

Thomas Witkowski's avatar
Thomas Witkowski committed
512
      stdMpi.send(sendIt->first, dofs);
513
514
515
    }

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

519
    stdMpi.startCommunication();
520
521

    for (RankToDofContainer::iterator recvIt = recvDofs.begin();
Thomas Witkowski's avatar
Thomas Witkowski committed
522
523
	 recvIt != recvDofs.end(); ++recvIt) {
      int nRecvDofs = recvIt->second.size();
524
525

      int counter = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
526
527
528
529
530
      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++];
531
532
533
534
      }
    }
  }

535

536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  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);
    }

559
560

    FixRefinementPatch::connectedEdges.clear();
561
    bool valid3dMesh = true;
562
563
564
565
566
567
568
569

    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;
570
571
572
573
      std::map<int, int> edgeNoInEl;

      for (unsigned int i = 0; i < edgeEls.size(); i++) {
	if (rankMacroEls.count(edgeEls[i].elIndex)) {
574
575
576
577
	  if (el0.empty())
	    el0.insert(edgeEls[i].elIndex);
	  else
	    el1.insert(edgeEls[i].elIndex);
578
579
580
581

	  edgeNoInEl[edgeEls[i].elIndex] = edgeEls[i].ithObject;
	}
      }
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
            
      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()) {
607
608
609
610
	valid3dMesh = false;

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

612
613
614
615
616
617
618
	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");
619

620
621
622
623
624
625
626
627
628
629
630
631
	    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);

632
633
634
635
	    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]);
636
637
638
639
640
641
642
643
644

	    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));
	  }
	}
      }
    }
645
646

    MSG_DBG("Mesh is 3d valid mesh: %d\n", valid3dMesh);
647
648
649
  }


650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
  void MeshDistributor::setRankDofs(ProblemVec *probVec)
  {
    int nComponents = probVec->getNumComponents();
    for (int i = 0; i < nComponents; i++) {
      for (int j = 0; j < nComponents; j++)
	if (probVec->getSystemMatrix(i, j))
	  probVec->getSystemMatrix(i, j)->setRankDofs(isRankDof);

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


667
668
  void MeshDistributor::setRankDofs()
  {
669
670
    for (unsigned int i = 0; i < probStat.size(); i++) 
      setRankDofs(probStat[i]);
671
672
673
  }


674
675
  void MeshDistributor::removePeriodicBoundaryConditions()
  {
676
677
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

678
679
680
681
682
683
684
685
    // 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())
686
	    removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(mat->getBoundaryManager()->getBoundaryConditionMap()));
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
	}
	
	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);
    }    
704
705
706

    // Remove periodic vertex associations
    mesh->getPeriodicAssociations().clear();
707
708
709
710
  }


  void MeshDistributor::removePeriodicBoundaryConditions(BoundaryIndexMap& boundaryMap)
Thomas Witkowski's avatar
Thomas Witkowski committed
711
712
713
714
715
716
717
718
719
720
721
  {
    BoundaryIndexMap::iterator it = boundaryMap.begin();
    while (it != boundaryMap.end()) {
      if (it->second->isPeriodic())
	boundaryMap.erase(it++);
      else
	++it;      
    }    
  }


722
  void MeshDistributor::checkMeshChange(bool tryRepartition)
723
  {
724
    FUNCNAME("MeshDistributor::checkMeshChange()");
725

726
727
    double first = MPI::Wtime();

728
729
730
731
732
    // === 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);
733

734
    if (recvAllValues == 0)
735
736
      return;

737
738
    // === At least one rank mesh has been changed, so the boundaries must be ===
    // === adapted to the new mesh structure.                                 ===
739
   
740
    do {
741
742
      bool meshChanged = false;

743
744
      // To check the interior boundaries, the ownership of the boundaries is not 
      // important. Therefore, we add all boundaries to one boundary container.
745
      RankToBoundMap allBound;
Thomas Witkowski's avatar
Thomas Witkowski committed
746
747

      for (InteriorBoundary::iterator it(myIntBoundary); !it.end(); ++it)
748
749
	if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	    (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
750
 	  allBound[it.getRank()].push_back(*it);
Thomas Witkowski's avatar
Thomas Witkowski committed
751
752

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

757
758
      for (InteriorBoundary::iterator it(periodicBoundary); !it.end(); ++it) {
	if (it.getRank() == mpiRank) {
759
760
761
762
763
	  if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	      (mesh->getDim() == 3 && it->rankObj.subObj == FACE)) {
	    MeshStructure elCode;
	    elCode.init(it->rankObj);
	    
764
	    MeshManipulation mm(feSpace);
765
	    meshChanged |= mm.fitElementToMeshCode(elCode, it->neighObj);
766
	  }
767
768
769
770
771
772
	} else {
	  if ((mesh->getDim() == 2 && it->rankObj.subObj == EDGE) || 
	      (mesh->getDim() == 3 && it->rankObj.subObj == FACE))
	    allBound[it.getRank()].push_back(*it);	
	}
      }
773

774

775
      // === Check the boundaries and adapt mesh if necessary. ===
776
      MSG_DBG("Run checkAndAdaptBoundary ...\n");
777

778
      meshChanged |= checkAndAdaptBoundary(allBound);
779
780
781

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

782
      int sendValue = static_cast<int>(meshChanged);
783
784
      recvAllValues = 0;
      mpiComm.Allreduce(&sendValue, &recvAllValues, 1, MPI_INT, MPI_SUM);
785
786

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

789
#if (DEBUG != 0)
790
    debug::writeMesh(feSpace, -1, debugOutputDir + "mesh");
791
792
#endif

793

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

796
797
    updateLocalGlobalNumbering();

798

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

Thomas Witkowski's avatar
Thomas Witkowski committed
801
    createPeriodicMap();
802

803
804
805
#if (DEBUG != 0)
    ParallelDebug::testPeriodicBoundary(*this);
#endif
806
807


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

810
    nMeshChangesAfterLastRepartitioning++;
811

812
813
814
815

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

816
817
    if (tryRepartition &&
	repartitioningAllowed && 
818
819
820
	nMeshChangesAfterLastRepartitioning >= repartitionIthChange) {
      repartitionMesh();
      nMeshChangesAfterLastRepartitioning = 0;
821
    }
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840

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

    vector<int> nDofsInRank(mpiSize);
    int nDofs = mesh->getDofAdmin(0).getUsedDofs();
    mpiComm.Gather(&nDofs, 1, MPI_INT, &(nDofsInRank[0]), 1, MPI_INT, 0);

    if (mpiRank == 0) {
      int nOverallDofs = 0;
      int maxDofs = numeric_limits<int>::min();
      for (int i = 0; i < mpiSize; i++) {
	nOverallDofs += nDofsInRank[i];
	maxDofs = std::max(maxDofs, nDofsInRank[i]);
      }      
      int avrgDofs = nOverallDofs / mpiSize;
      double imbalance = (static_cast<double>(maxDofs - avrgDofs) /  avrgDofs) * 100.0;

      MSG("Imbalancing factor: %.1f\%\n", imbalance);
    }
841
842
843
  }

  
844
  bool MeshDistributor::checkAndAdaptBoundary(RankToBoundMap &allBound)
845
  {
846
    FUNCNAME("MeshDistributor::checkAndAdaptBoundary()");
847
848
849

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

854
      for (vector<AtomicBoundary>::iterator boundIt = it->second.begin();
855
856
	   boundIt != it->second.end(); ++boundIt) {
	MeshStructure elCode;
857
	elCode.init(boundIt->rankObj);
858
859
860
861
	sendCodes[it->first].push_back(elCode);
      }
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
862
    StdMpi<MeshCodeVec> stdMpi(mpiComm, true);
863
    stdMpi.send(sendCodes);
864
865
866
    for (RankToBoundMap::iterator it = allBound.begin(); it != allBound.end(); ++it)
      stdMpi.recv(it->first);
    stdMpi.startCommunication();
867
 
868
    // === Compare received mesh structure codes. ===
869
    
870
    bool meshChanged = false;
871

872
    for (RankToBoundMap::iterator it = allBound.begin(); it != allBound.end(); ++it) {
873
     
874
875
      MeshCodeVec &recvCodes = stdMpi.getRecvData()[it->first];
      int i = 0;
876
      
877
      for (vector<AtomicBoundary>::iterator boundIt = it->second.begin();
878
	   boundIt != it->second.end(); ++boundIt, i++) {
879

880
881
	MeshStructure elCode;	
	elCode.init(boundIt->rankObj);
882

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

886
887
	  MeshManipulation mm(feSpace);
	  meshChanged |= mm.fitElementToMeshCode(recvCodes[i], boundIt->rankObj);
888
 	}
889
890
891
      }
    }