MeshDistributor.cc 62.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
#include "parallel/DofComm.h"
32
33
#include "io/ElementFileWriter.h"
#include "io/MacroInfo.h"
Thomas Witkowski's avatar
Thomas Witkowski committed
34
#include "io/MacroWriter.h"
35
#include "io/VtkWriter.h"
36
37
38
39
40
#include "Mesh.h"
#include "Traverse.h"
#include "ElInfo.h"
#include "Element.h"
#include "MacroElement.h"
41
42
#include "DOFMatrix.h"
#include "DOFVector.h"
43
#include "SystemVector.h"
44
#include "ElementDofIterator.h"
45
46
#include "ProblemStatBase.h"
#include "StandardProblemIteration.h"
47
#include "VertexVector.h"
48
#include "MeshStructure.h"
49
#include "ProblemStat.h"
Thomas Witkowski's avatar
Thomas Witkowski committed
50
#include "ProblemInstat.h"
51
#include "RefinementManager3d.h"
52
#include "Debug.h"
53

54
55
namespace AMDiS {

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

60
61
  MeshDistributor* MeshDistributor::globalMeshDistributor = NULL;

62
63
64
  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
65

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

71
  bool MeshDistributor::sebastianMode = false;
72

73
  MeshDistributor::MeshDistributor()
74
    : problemStat(0),
75
      initialized(false),
76
      name("parallel"),
77
      feSpaces(0),
78
79
80
81
      mesh(NULL),
      refineManager(NULL),
      info(10),
      partitioner(NULL),
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
      lastMeshChangeIndex(0),
90
      createBoundaryDofFlag(0),
91
      boundaryDofInfo(1)
92
  {
93
    FUNCNAME("MeshDistributor::ParalleDomainBase()");
Thomas Witkowski's avatar
Thomas Witkowski committed
94

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

99
    Parameters::get(name + "->repartitioning", repartitioningAllowed);
100
101
    Parameters::get(name + "->debug output dir", debugOutputDir);
    Parameters::get(name + "->repartition ith change", repartitionIthChange);
102
    Parameters::get(name + "->log main rank", Msg::outputMainRank);
103

104
    string partStr = "parmetis";
105
    Parameters::get(name + "->partitioner", partStr);
106
107
108
109

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

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

118
119
120
    if (partStr == "checker")
      partitioner = new CheckerPartitioner(&mpiComm);

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

124
    int tmp = 0;
125
    Parameters::get(name + "->box partitioning", tmp);
Thomas Witkowski's avatar
Thomas Witkowski committed
126
127
    partitioner->setBoxPartitioning(static_cast<bool>(tmp));

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

Thomas Witkowski's avatar
Thomas Witkowski committed
131

132
  void MeshDistributor::initParallelization()
133
  {
134
    FUNCNAME("MeshDistributor::initParallelization()");
135

136
137
138
    if (initialized)
      return;

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

142
143
    TEST_EXIT(feSpaces.size() > 0)
      ("No FE space has been defined for the mesh distributor!\n");
144
    TEST_EXIT(mesh)("No mesh has been defined for the mesh distributor!\n");
145

146
147
148
149
150
    // === Sort FE spaces with respect to the degree of the basis ===
    // === functions. Use stuiped bubble sort for this.           ===

    bool doNext = false;
    do {
151
152
      doNext = false;
      for (unsigned int i = 0; i < feSpaces.size() - 1; i++) {
153
154
155
156
157
158
159
	if (feSpaces[i]->getBasisFcts()->getDegree() >
	    feSpaces[i + 1]->getBasisFcts()->getDegree()) {
	  const FiniteElemSpace *tmp = feSpaces[i + 1];
	  feSpaces[i + 1] = feSpaces[i];
	  feSpaces[i] = tmp;
	  doNext = true;
	}
160
      }
161
162
    } while (doNext);

163
    elObjDb.setFeSpace(feSpaces[0]);
164

165
166
167
    // 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).
168
    if (deserialized) {
169
170
      updateMacroElementInfo();

171
      setRankDofs();
172

173
      removePeriodicBoundaryConditions();
174

175
      elObjDb.createMacroElementInfo(allMacroElements);
176

177
178
      createBoundaryDofs();

Thomas Witkowski's avatar
Thomas Witkowski committed
179
#if (DEBUG != 0)
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
180
181
      ParallelDebug::writeDebugFile(feSpaces[feSpaces.size() - 1], dofMap, 
				    debugOutputDir + "mpi-dbg", "dat");
Thomas Witkowski's avatar
Thomas Witkowski committed
182
#endif    
183
184

      initialized = true;
185
      return;
186
    }
187

188

189
190
191
    // 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.
192
193
    testForMacroMesh();

194
195
    // For later mesh repartitioning, we need to store some information about
    // the macro mesh.
196
197
    createMacroElementInfo();

198
    // create an initial partitioning of the mesh
199
    partitioner->createInitialPartitioning();
200

201
    // set the element weights, which are 1 at the very first begin
202
    setInitialElementWeights();
203
204

    // and now partition the mesh    
205
206
    bool partitioningSucceed = partitioner->partition(elemWeights, INITIAL);
    TEST_EXIT(partitioningSucceed)("Initial partitioning does not work!\n");
207
    partitioner->createPartitionMap(partitionMap);
208

209

210
#if (DEBUG != 0)    
211
212
    debug::ElementIdxToDofs elMap;
    debug::createSortedDofs(mesh, elMap);
213
214
#endif

215
    if (mpiRank == 0) {
216
#if (DEBUG != 0)    
217
      int writePartMesh = 1;
218
219
220
#else
      int writePartMesh = 0;
#endif
221
      Parameters::get("dbg->write part mesh", writePartMesh);
222

223
      if (writePartMesh > 0) {
224
	debug::writeElementIndexMesh(mesh, debugOutputDir + "elementIndex.vtu");
225
	ParallelDebug::writePartitioning(*this, debugOutputDir + "part.vtu");
226
      }
227
    }
228

229
230
    // If required, create hierarchical mesh level structure.
    createMeshLevelStructure();
231

232
    // Create interior boundary information.
233
    createInteriorBoundary(true);
Thomas Witkowski's avatar
Thomas Witkowski committed
234

235
236
    // === Remove neighbourhood relations due to periodic bounday conditions. ===

237
238
239
240
241
    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))) {
242
243
244

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

245
246
247
248
249
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

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

    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))) {
260
261
262

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

263
264
265
266
267
	  (*it)->getNeighbour(i)->setNeighbour((*it)->getOppVertex(i), NULL);
	  (*it)->setNeighbour(i, NULL);
	  (*it)->setBoundary(i, 0);

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

270
271
272
	}
      }
    }
273

Thomas Witkowski's avatar
n    
Thomas Witkowski committed
274
275
276
    // === Remove all macro elements that are not part of the rank partition. ===

    removeMacroElements();
277

278
279
    // === Create new global and local DOF numbering. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
280

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

288
    updateLocalGlobalNumbering();
289

290
291
292
    // === 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.                         ===
293
294
295
    
    check3dValidMesh();

296
297
    // === If in debug mode, make some tests. ===

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

301
    ParallelDebug::testAllElements(*this);
302
    debug::testSortedDofs(mesh, elMap);
303
    ParallelDebug::testInteriorBoundary(*this);
Thomas Witkowski's avatar
Thomas Witkowski committed
304
    ParallelDebug::followBoundary(*this);
Thomas Witkowski's avatar
Thomas Witkowski committed
305

306
    debug::writeMesh(feSpaces[0], -1, debugOutputDir + "macro_mesh");   
307
308

    MSG("Debug mode tests finished!\n");
309
#endif
310

311
    // Create periodic DOF mapping, if there are periodic boundaries.
312
    createPeriodicMap();
313

314
315
316
    // Remove periodic boundary conditions in sequential problem definition. 
    removePeriodicBoundaryConditions();

317
318
319
#if (DEBUG != 0)
    ParallelDebug::testPeriodicBoundary(*this);
#endif
320

321
    // === Global refinements. ===
322
    
Thomas Witkowski's avatar
Thomas Witkowski committed
323
    int globalRefinement = 0;
324
    Parameters::get(mesh->getName() + "->global refinements", globalRefinement);
325
    
Thomas Witkowski's avatar
Thomas Witkowski committed
326
    if (globalRefinement > 0) {
327
      refineManager->globalRefine(mesh, globalRefinement);
328

329
      updateLocalGlobalNumbering();
330

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

333
      createPeriodicMap();
334
335
336
#if (DEBUG != 0)
    ParallelDebug::testPeriodicBoundary(*this);
#endif
Thomas Witkowski's avatar
Thomas Witkowski committed
337
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
338

339
    // Set DOF rank information to all matrices and vectors.
340
    setRankDofs();
Thomas Witkowski's avatar
Thomas Witkowski committed
341

342
    initialized = true;
343
344
  }

345

346
  void MeshDistributor::addProblemStat(ProblemStatSeq *probStat)
347
  {
348
    FUNCNAME("MeshDistributor::addProblemStat()");
349

350
351
352
    TEST_EXIT_DBG(probStat->getFeSpaces().size())
      ("No FE spaces in stationary problem!\n");

353
354
355
356
357
358
359
360
361
362
    // === Add FE spaces from stationary problem to mesh distributor. ===

    for (unsigned int i = 0; i < probStat->getFeSpaces().size(); i++) {
      bool foundFeSpace = false;
      for (unsigned int j = 0; j < feSpaces.size(); j++) {
	if (feSpaces[j] == probStat->getFeSpaces()[i])
	  foundFeSpace = true;

	TEST_EXIT(feSpaces[j]->getMesh() == probStat->getFeSpaces()[i]->getMesh())
	  ("MeshDistributor does not yet support usage of different meshes!\n");
363
364
      }

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
      if (!foundFeSpace)
	feSpaces.push_back(probStat->getFeSpaces()[i]);
    }

    TEST_EXIT(feSpaces.size() > 0)("Should not happen!\n");

    mesh = feSpaces[0]->getMesh();
    info = probStat->getInfo();
    
    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());
383
    }
384
385
386
    
    partitioner->setMesh(mesh);
    
387
388
389

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

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

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

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

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

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

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

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

453
    problemStat.push_back(probStat);
454

455
456
457
    // If the mesh distributor is already initialized, don't forget to set rank
    // DOFs object to the matrices and vectors of the added stationary problem,
    // and to remove the periodic boundary conditions on these objects.
458

459
    if (initialized) {
460
      setRankDofs(probStat);
461
462
      removePeriodicBoundaryConditions(probStat);
    }
463
464
465
  }


466
467
468
469
470
471
472
473
474
475
476
  void MeshDistributor::addProblemStatGlobal(ProblemStatSeq *probStat)
  {
    FUNCNAME("MeshDistributor::addProblemStatGlobal()");

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

    globalMeshDistributor->addProblemStat(probStat);
  }


477
  void MeshDistributor::exitParallelization()
478
  {}
479

480
  
481
  void MeshDistributor::testForMacroMesh()
482
  {
483
    FUNCNAME("MeshDistributor::testForMacroMesh()");
484
485
486
487
488
489
490

    int nMacroElements = 0;

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

      TEST_EXIT(elInfo->getType() == 0)
	("Only macro elements with level 0 are supported!\n");
495
496
497
498
499
500
501
502
503
504
      
      nMacroElements++;

      elInfo = stack.traverseNext(elInfo);
    }

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

505

Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
506
  void MeshDistributor::synchVector(SystemVector &vec, int level)
Thomas Witkowski's avatar
Thomas Witkowski committed
507
  {
508
509
    FUNCNAME("MeshDistributor::synchVector()");

Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
510
    TEST_EXIT_DBG(level >= 0 && level <= 1)("Wrong level number!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
511

Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
512
513
514
515
516
517
    MPI::Intracomm &levelComm = levelData.getMpiComm(level);
    DofComm &dc = (level == 0 ? dofComm : dofCommSd);

    StdMpi<vector<double> > stdMpi(levelComm);

    for (DofComm::Iterator it(dc.getSendDofs()); 
518
	 !it.end(); it.nextRank()) {
519
      vector<double> dofs;
520

521
522
      for (int i = 0; i < vec.getSize(); i++) {
	DOFVector<double> &dofVec = *(vec.getDOFVector(i));
523

Thomas Witkowski's avatar
Thomas Witkowski committed
524
	for (it.beginDofIter(vec.getFeSpace(i)); !it.endDofIter(); it.nextDof())
525
526
	  dofs.push_back(dofVec[it.getDofIndex()]);
      }
527

Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
528
529
530
531
      int rank = it.getRank();
      if (level > 0)
	rank = levelData.mapRank(rank, 0, level);
      stdMpi.send(rank, dofs);
532
    }
533
	   
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
534
535
536
537
538
539
    for (DofComm::Iterator it(dc.getRecvDofs()); !it.end(); it.nextRank()) {
      int rank = it.getRank();
      if (level > 0)
	rank = levelData.mapRank(rank, 0, level);
      stdMpi.recv(rank);
    }
540

541
    stdMpi.startCommunication();
542

Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
543
544
545
546
    for (DofComm::Iterator it(dc.getRecvDofs()); !it.end(); it.nextRank()) {
      int rank = it.getRank();
      if (level > 0)
	rank = levelData.mapRank(rank, 0, level);
547
548

      int counter = 0;
549
      vector<double> &recvData =  stdMpi.getRecvData(rank);
550
551
552
553

      for (int i = 0; i < vec.getSize(); i++) {
	DOFVector<double> &dofVec = *(vec.getDOFVector(i));

554
555
556
557
558
	for (it.beginDofIter(vec.getFeSpace(i)); !it.endDofIter(); it.nextDof()) {
	  TEST_EXIT_DBG(counter < recvData.size())
	    ("Recv data from rank %d has only %d entries!\n", rank, recvData.size());
	  dofVec[it.getDofIndex()] = recvData[counter++];
	}
559
560
561
562
      }
    }
  }

563

564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  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);
579
	allEdges.insert(elObjDb.getEdgeLocalMap(elData));
580
581
582
583
584
585
586
      }

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

      elInfo = stack.traverseNext(elInfo);
    }

587
588

    FixRefinementPatch::connectedEdges.clear();
589
    bool valid3dMesh = true;
590
591

    for (std::set<DofEdge>::iterator it = allEdges.begin(); it != allEdges.end(); ++it) {
592
      vector<ElementObjectData>& edgeEls = elObjDb.getElements(*it);
593
594
595
596
597

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

      std::set<int> el0, el1;
598
      map<int, int> edgeNoInEl;
599
600
601

      for (unsigned int i = 0; i < edgeEls.size(); i++) {
	if (rankMacroEls.count(edgeEls[i].elIndex)) {
602
603
604
605
	  if (el0.empty())
	    el0.insert(edgeEls[i].elIndex);
	  else
	    el1.insert(edgeEls[i].elIndex);
606
607
608
609

	  edgeNoInEl[edgeEls[i].elIndex] = edgeEls[i].ithObject;
	}
      }
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
            
      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()) {
635
636
637
638
	valid3dMesh = false;

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

640
641
642
	for (std::set<int>::iterator elIt0 = el0.begin(); elIt0 != el0.end(); ++elIt0) {
	  for (std::set<int>::iterator elIt1 = el1.begin(); elIt1 != el1.end(); ++elIt1) {
	    pair<Element*, int> edge0 = 
643
	      make_pair(elObjDb.getElementPtr(*elIt0), edgeNoInEl[*elIt0]);
644
	    pair<Element*, int> edge1 = 
645
	      make_pair(elObjDb.getElementPtr(*elIt1), edgeNoInEl[*elIt1]);
646
647
648
649
650

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

	    WorldVector<double> c0, c1;
651
652
	    mesh->getDofIndexCoords(dofEdge0.first, feSpaces[0], c0);
	    mesh->getDofIndexCoords(dofEdge0.second, feSpaces[0], c1);
653

654
	    /*
655
656
657
658
	    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]);
659
	    */
660
661
662
663
664
665
666
667
668

	    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));
	  }
	}
      }
    }
669
670

    MSG_DBG("Mesh is 3d valid mesh: %d\n", valid3dMesh);
671
672
673
  }


674
  void MeshDistributor::getAllBoundaryDofs(const FiniteElemSpace *feSpace,
675
					   int level,
676
					   DofContainer& dofs)
677
678
679
680
  {
    FUNCNAME("MeshDistributor::getAllBoundaryDofs()");

    DofContainerSet dofSet;
681
682
    for (DofComm::Iterator it(dofComm.getSendDofs(), level, feSpace); 
	 !it.end(); it.nextRank())
683
      dofSet.insert(it.getDofs().begin(), it.getDofs().end());
684
685
    for (DofComm::Iterator it(dofComm.getRecvDofs(), level, feSpace); 
	 !it.end(); it.nextRank())
686
      dofSet.insert(it.getDofs().begin(), it.getDofs().end());
687
688
689
690
691
692

    dofs.clear();
    dofs.insert(dofs.begin(), dofSet.begin(), dofSet.end());
  }


693
  void MeshDistributor::setRankDofs(ProblemStatSeq *probStat)
694
  {
695
696
    FUNCNAME("MeshDistributor::setRankDofs()");

697
    int nComponents = probStat->getNumComponents();
698
699
    for (int i = 0; i < nComponents; i++) {
      for (int j = 0; j < nComponents; j++)
700
701
702
703
704
705
706
	if (probStat->getSystemMatrix(i, j)) {
	  const FiniteElemSpace *rowFeSpace = 
	    probStat->getSystemMatrix(i, j)->getRowFeSpace();

	  TEST_EXIT(find(feSpaces.begin(), feSpaces.end(), rowFeSpace) != feSpaces.end())
	    ("Should not happen!\n");

Thomas Witkowski's avatar
Thomas Witkowski committed
707
	  probStat->getSystemMatrix(i, j)->setDofMap(dofMap[rowFeSpace]);
708
709
	}
    
710

711
      TEST_EXIT_DBG(probStat->getRhs()->getDOFVector(i))("No RHS vector!\n");
712
713
      TEST_EXIT_DBG(probStat->getSolution()->getDOFVector(i))
	("No solution vector!\n");
714
715
716
      TEST_EXIT_DBG(probStat->getRhsVector(i)->getFeSpace() ==
		    probStat->getSolution(i)->getFeSpace())
	("Should not happen!\n");
717
      
718
719
720
721
      const FiniteElemSpace *feSpace = probStat->getRhsVector(i)->getFeSpace();
      TEST_EXIT(find(feSpaces.begin(), feSpaces.end(), feSpace) != feSpaces.end())
	("Should not happen!\n");

Thomas Witkowski's avatar
Thomas Witkowski committed
722
723
      probStat->getRhsVector(i)->setDofMap(dofMap[feSpace]);
      probStat->getSolution(i)->setDofMap(dofMap[feSpace]);
724
725
726
727
    }    
  }


728
729
  void MeshDistributor::setRankDofs()
  {
730
731
    for (unsigned int i = 0; i < problemStat.size(); i++) 
      setRankDofs(problemStat[i]);
732
733
734
  }


735
736
  void MeshDistributor::removePeriodicBoundaryConditions()
  {
737
738
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

739
    // Remove periodic boundaries in boundary manager on matrices and vectors.
740
741
    for (unsigned int i = 0; i < problemStat.size(); i++)
      removePeriodicBoundaryConditions(problemStat[i]);
742
743
744

    // Remove periodic boundaries on elements in mesh.
    TraverseStack stack;
745
    ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER);
746
747
748
749
    while (elInfo) {
      elInfo->getElement()->deleteElementData(PERIODIC);
      elInfo = stack.traverseNext(elInfo);
    }    
750
751
752

    // Remove periodic vertex associations
    mesh->getPeriodicAssociations().clear();
753
754
755
  }


756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
  void MeshDistributor::removePeriodicBoundaryConditions(ProblemStatSeq *probStat)
  {
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

    int nComponents = probStat->getNumComponents();

    for (int j = 0; j < nComponents; j++) {
      for (int k = 0; k < nComponents; k++) {
	DOFMatrix* mat = probStat->getSystemMatrix(j, k);
	if (mat && mat->getBoundaryManager())
	  removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(mat->getBoundaryManager()->getBoundaryConditionMap()));
      }
      
      if (probStat->getSolution()->getDOFVector(j)->getBoundaryManager())
	removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(probStat->getSolution()->getDOFVector(j)->getBoundaryManager()->getBoundaryConditionMap()));
      
      if (probStat->getRhs()->getDOFVector(j)->getBoundaryManager())
	removePeriodicBoundaryConditions(const_cast<BoundaryIndexMap&>(probStat->getRhs()->getDOFVector(j)->getBoundaryManager()->getBoundaryConditionMap()));
    }
  }


778
  void MeshDistributor::removePeriodicBoundaryConditions(BoundaryIndexMap& boundaryMap)
Thomas Witkowski's avatar
Thomas Witkowski committed
779
  {
780
781
    FUNCNAME("MeshDistributor::removePeriodicBoundaryConditions()");

Thomas Witkowski's avatar
Thomas Witkowski committed
782
783
    BoundaryIndexMap::iterator it = boundaryMap.begin();
    while (it != boundaryMap.end()) {
784
      if (it->second->isPeriodic())
Thomas Witkowski's avatar
Thomas Witkowski committed
785
	boundaryMap.erase(it++);
786
      else
Thomas Witkowski's avatar
Thomas Witkowski committed
787
788
789
790
791
	++it;      
    }    
  }


792
793
794
795
  void MeshDistributor::createMeshLevelStructure()
  {
    FUNCNAME("MeshDistributor::createMeshLevelStructure()");

796
797
798
    if (mpiSize != 16)
      return;

799
    std::set<int> neighbours;
800
801
    switch (mpiRank) {
    case 0:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
802
      neighbours.insert(1); neighbours.insert(2); neighbours.insert(3);
803
804
      break;
    case 1:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
805
      neighbours.insert(0); neighbours.insert(4); neighbours.insert(2); neighbours.insert(3); neighbours.insert(6);
806
807
      break;
    case 2:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
808
      neighbours.insert(0); neighbours.insert(1); neighbours.insert(3); neighbours.insert(8); neighbours.insert(9);
809
810
      break;
    case 3:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
811
812
813
      neighbours.insert(0); neighbours.insert(1); neighbours.insert(4); 
      neighbours.insert(2); neighbours.insert(6);
      neighbours.insert(8); neighbours.insert(9); neighbours.insert(12); 
814
815
      break;
    case 4:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
816
      neighbours.insert(1); neighbours.insert(3); neighbours.insert(6); neighbours.insert(7); neighbours.insert(5);
817
818
      break;
    case 5:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
819
      neighbours.insert(4); neighbours.insert(6); neighbours.insert(7);
820
821
      break;
    case 6:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
822
823
824
      neighbours.insert(1); neighbours.insert(4); neighbours.insert(5); 
      neighbours.insert(3); neighbours.insert(7);
      neighbours.insert(9); neighbours.insert(12); neighbours.insert(13); 
825
826
      break;
    case 7:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
827
      neighbours.insert(4); neighbours.insert(5); neighbours.insert(6);  neighbours.insert(12); neighbours.insert(13);
828
829
      break;
    case 8:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
830
      neighbours.insert(2); neighbours.insert(3); neighbours.insert(9);  neighbours.insert(10); neighbours.insert(11);
831
832
      break;
    case 9:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
833
834
835
      neighbours.insert(2); neighbours.insert(3); neighbours.insert(6); 
      neighbours.insert(8); neighbours.insert(12);
      neighbours.insert(10); neighbours.insert(11); neighbours.insert(14); 
836
837
      break;
    case 10:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
838
      neighbours.insert(8); neighbours.insert(9); neighbours.insert(11);
839
840
      break;
    case 11:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
841
      neighbours.insert(8); neighbours.insert(9); neighbours.insert(12);  neighbours.insert(10); neighbours.insert(14);
842
843
      break;
    case 12:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
844
845
846
      neighbours.insert(3); neighbours.insert(6); neighbours.insert(7); 
      neighbours.insert(9); neighbours.insert(13);
      neighbours.insert(11); neighbours.insert(14); neighbours.insert(15); 
847
848
      break;
    case 13:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
849
      neighbours.insert(6); neighbours.insert(7); neighbours.insert(12);  neighbours.insert(14); neighbours.insert(15);
850
851
      break;
    case 14:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
852
      neighbours.insert(9); neighbours.insert(12); neighbours.insert(13);  neighbours.insert(11); neighbours.insert(15);
853
854
      break;
    case 15:
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
855
      neighbours.insert(12); neighbours.insert(13); neighbours.insert(14);
856
857
      break;
    }    
858

859
    TEST_EXIT(neighbours.size() > 0)("Should not happen!\n");
860
861
862

    levelData.init(neighbours);

863
864
    MSG("INIT MESH LEVEL %d\n", levelData.getLevelNumber());

865
866
867
868
    bool multiLevelTest = false;
    Parameters::get("parallel->multi level test", multiLevelTest);
    if (multiLevelTest) {
      switch (mpiRank) {
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
869
      case 0: case 1: case 2: case 3:
870
871
	{
	  std::set<int> m;
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
872
	  m.insert(0); m.insert(1); m.insert(2); m.insert(3);
873
	  levelData.addLevel(m, 0);
874
875
	}
	break;
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
876
      case 4: case 5: case 6: case 7:
877
878
	{
	  std::set<int> m;
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
879
	  m.insert(4); m.insert(5); m.insert(6); m.insert(7);
880
	  levelData.addLevel(m, 1);
881
882
	}
	break;
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
883
      case 8: case 9: case 10: case 11:
884
885
	{
	  std::set<int> m;
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
886
	  m.insert(8); m.insert(9); m.insert(10); m.insert(11);
887
	  levelData.addLevel(m, 2);
888
889
	}
	break;
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
890
      case 12: case 13: case 14: case 15:
891
892
	{
	  std::set<int> m;
Thomas Witkowski's avatar
Blub    
Thomas Witkowski committed
893
	  m.insert(12); m.insert(13); m.insert(14); m.insert(15);