PetscSolverGlobalMatrix.cc 22.5 KB
Newer Older
Thomas Witkowski's avatar
Thomas Witkowski committed
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.


13
#include "AMDiS.h"
Thomas Witkowski's avatar
Thomas Witkowski committed
14
15
16
17
18
19
#include "parallel/PetscSolverGlobalMatrix.h"
#include "parallel/StdMpi.h"
#include "parallel/MpiHelper.h"

namespace AMDiS {

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
20
  void PetscSolverGlobalMatrix::fillPetscMatrix(Matrix<DOFMatrix*> *seqMat)
Thomas Witkowski's avatar
Thomas Witkowski committed
21
22
23
  {
    FUNCNAME("PetscSolverGlobalMatrix::fillPetscMatrix()");

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
24
25
26
27
28
29
    TEST_EXIT_DBG(meshDistributor)("No mesh distributor object defined!\n");
    TEST_EXIT_DBG(interiorMap)("No parallel mapping object defined!\n");
    TEST_EXIT_DBG(seqMat)("No DOF matrix defined!\n");
    
    double wtime = MPI::Wtime();

30
    createMatVec(*seqMat);
31

Thomas Witkowski's avatar
Thomas Witkowski committed
32
    if (coarseSpaceMap.size()) {
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
33
      fillPetscMatrixWithCoarseSpace(seqMat);
34
35
36
      return;
    }

37
38
    // === Create PETSc vector (solution and a temporary vector). ===

Thomas Witkowski's avatar
Thomas Witkowski committed
39
40
41
42
43
44
#if (DEBUG != 0)
    MSG("Fill petsc matrix 1 needed %.5f seconds\n", MPI::Wtime() - wtime);
#endif

    // === Transfer values from DOF matrices to the PETSc matrix. === 

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
45
    int nComponents = seqMat->getNumRows();
Thomas Witkowski's avatar
Thomas Witkowski committed
46
47
    for (int i = 0; i < nComponents; i++)
      for (int j = 0; j < nComponents; j++)
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
48
49
	if ((*seqMat)[i][j])
	  setDofMatrix((*seqMat)[i][j], i, j);
Thomas Witkowski's avatar
Thomas Witkowski committed
50
51
52
53
54

#if (DEBUG != 0)
    MSG("Fill petsc matrix 2 needed %.5f seconds\n", MPI::Wtime() - wtime);
#endif

55
    matAssembly();
56
57
58
    
    if (printMatInfo) {
      MatInfo matInfo;
59
      MatGetInfo(getMatInterior(), MAT_GLOBAL_SUM, &matInfo);
60
61
62
63
64
65
66
      MSG("Matrix info:\n");
      MSG("  memory usage: %e MB\n", matInfo.memory / (1024.0 * 1024.0));
      MSG("  mallocs: %d\n", static_cast<int>(matInfo.mallocs));
      MSG("  nz allocated: %d\n", static_cast<int>(matInfo.nz_allocated));
      MSG("  nz used: %d\n", static_cast<int>(matInfo.nz_used));
      MSG("  nz unneeded: %d\n", static_cast<int>(matInfo.nz_unneeded));
    }
67

68
    // === Init PETSc solver. ===
69

70
71
    KSPCreate(mpiCommGlobal, &kspInterior);
    KSPGetPC(kspInterior, &pcInterior);
72
    KSPSetOperators(kspInterior, getMatInterior(), getMatInterior(), 
73
		    SAME_NONZERO_PATTERN); 
74
75
76
77
    KSPSetTolerances(kspInterior, 0.0, 1e-8, PETSC_DEFAULT, PETSC_DEFAULT);
    KSPSetType(kspInterior, KSPBCGS);
    KSPSetOptionsPrefix(kspInterior, kspPrefix.c_str());
    KSPSetFromOptions(kspInterior);
78

79
    initPreconditioner(pcInterior);
80

81
82
    // Do not delete the solution vector, use it for the initial guess.
    if (!zeroStartVector)
83
      KSPSetInitialGuessNonzero(kspInterior, PETSC_TRUE);
84

Thomas Witkowski's avatar
Thomas Witkowski committed
85
86
87
#if (DEBUG != 0)
    MSG("Fill petsc matrix 3 needed %.5f seconds\n", MPI::Wtime() - wtime);
#endif
88
89
90
  }


91
92
93
94
95
96
97
98
  void PetscSolverGlobalMatrix::fillPetscMatrix(DOFMatrix *mat)
  {
    Matrix<DOFMatrix*> m(1, 1);
    m[0][0] = mat;
    fillPetscMatrix(&m);
  }


Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
99
  void PetscSolverGlobalMatrix::fillPetscMatrixWithCoarseSpace(Matrix<DOFMatrix*> *seqMat)
100
101
  {
    FUNCNAME("PetscSolverGlobalMatrix::fillPetscMatrixWithCoarseSpace()");
102
103

    TEST_EXIT_DBG(interiorMap)("Should not happen!\n");
104
105
    TEST_EXIT_DBG(coarseSpaceMap.size() == seqMat->getSize())
      ("Wrong sizes %d %d\n", coarseSpaceMap.size(), seqMat->getSize());
106

107
    vector<const FiniteElemSpace*> feSpaces = AMDiS::getComponentFeSpaces(*seqMat);
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
108

109
110
    int nRowsRankInterior = interiorMap->getRankDofs();
    int nRowsOverallInterior = interiorMap->getOverallDofs();
111

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    // === Prepare traverse of sequentially created matrices. ===

    using mtl::tag::row; using mtl::tag::nz; using mtl::begin; using mtl::end;
    namespace traits = mtl::traits;
    typedef DOFMatrix::base_matrix_type Matrix;

    typedef traits::range_generator<row, Matrix>::type cursor_type;
    typedef traits::range_generator<nz, cursor_type>::type icursor_type;

    vector<int> cols, colsOther;
    vector<double> values, valuesOther;
    cols.reserve(300);
    colsOther.reserve(300);
    values.reserve(300);
    valuesOther.reserve(300);

    // === Traverse all sequentially created matrices and add the values to ===
    // === the global PETSc matrices.                                       ===

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
131
    int nComponents = seqMat->getSize();
Thomas Witkowski's avatar
Thomas Witkowski committed
132
133
134
135
136
    for (int rowComponent = 0; rowComponent < nComponents; rowComponent++) {
      for (int colComponent = 0; colComponent < nComponents; colComponent++) {
	DOFMatrix* dofMat = (*seqMat)[rowComponent][colComponent];

	if (!dofMat)
137
138
	  continue;

Thomas Witkowski's avatar
Thomas Witkowski committed
139
140
	ParallelDofMapping *rowCoarseSpace = coarseSpaceMap[rowComponent];
	ParallelDofMapping *colCoarseSpace = coarseSpaceMap[colComponent];
Thomas Witkowski's avatar
Thomas Witkowski committed
141

Thomas Witkowski's avatar
Thomas Witkowski committed
142
143
	traits::col<Matrix>::type col(dofMat->getBaseMatrix());
	traits::const_value<Matrix>::type value(dofMat->getBaseMatrix());
144
145
	
	// Traverse all rows.
Thomas Witkowski's avatar
Thomas Witkowski committed
146
147
	for (cursor_type cursor = begin<row>(dofMat->getBaseMatrix()), 
	       cend = end<row>(dofMat->getBaseMatrix()); cursor != cend; ++cursor) {
148

Thomas Witkowski's avatar
Thomas Witkowski committed
149
	  bool isRowCoarse = 
Thomas Witkowski's avatar
Thomas Witkowski committed
150
	    isCoarseSpace(rowComponent, feSpaces[rowComponent], *cursor);
151
152
153
154
155
156
157
158
159
160
  
	  cols.clear();
	  colsOther.clear();
	  values.clear();	  
	  valuesOther.clear();

	  // Traverse all columns.
	  for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); 
	       icursor != icend; ++icursor) {

Thomas Witkowski's avatar
Thomas Witkowski committed
161
162
	    bool isColCoarse = 
	      isCoarseSpace(colComponent, feSpaces[colComponent], col(*icursor));
163

Thomas Witkowski's avatar
Thomas Witkowski committed
164
165
166
	    if (isColCoarse == isRowCoarse) {
	      cols.push_back(col(*icursor));
	      values.push_back(value(*icursor));
167
	    } else {
Thomas Witkowski's avatar
Thomas Witkowski committed
168
169
	      colsOther.push_back(col(*icursor));
	      valuesOther.push_back(value(*icursor));
170
171
172
173
174
175
	    }
	  }  // for each nnz in row


	  // === Set matrix values. ===

Thomas Witkowski's avatar
Thomas Witkowski committed
176
	  if (isRowCoarse) {
Thomas Witkowski's avatar
Thomas Witkowski committed
177
178
179
	    int rowIndex = rowCoarseSpace->getMatIndex(rowComponent, *cursor);
	    for (unsigned int i = 0; i < cols.size(); i++)
	      cols[i] = colCoarseSpace->getMatIndex(colComponent, cols[i]);
180

Thomas Witkowski's avatar
Thomas Witkowski committed
181
	    MatSetValues(getMatCoarseByComponent(rowComponent, colComponent),
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
182
			 1, &rowIndex, cols.size(),
183
184
185
186
			 &(cols[0]), &(values[0]), ADD_VALUES);

	    if (colsOther.size()) {
	      if (subdomainLevel == 0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
187
188
189
		for (unsigned int i = 0; i < colsOther.size(); i++)
		  colsOther[i] = 
		    interiorMap->getMatIndex(colComponent, colsOther[i]);
190
	      } else {
Thomas Witkowski's avatar
Thomas Witkowski committed
191
192
193
194
		for (unsigned int i = 0; i < colsOther.size(); i++)
		  colsOther[i] = 
		    interiorMap->getMatIndex(colComponent, colsOther[i]) + 
		    rStartInterior;
195
	      }
196

Thomas Witkowski's avatar
Thomas Witkowski committed
197
	      MatSetValues(getMatCoarseInteriorByComponent(rowComponent), 
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
198
			   1, &rowIndex, colsOther.size(),
199
200
201
202
 			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
	    }
	  } else {
	    int localRowIndex = 
Thomas Witkowski's avatar
Thomas Witkowski committed
203
204
205
	      (subdomainLevel == 0 ? 
	       interiorMap->getLocalMatIndex(rowComponent, *cursor) :
	       interiorMap->getMatIndex(rowComponent, *cursor));
206

Thomas Witkowski's avatar
Thomas Witkowski committed
207
	    for (unsigned int i = 0; i < cols.size(); i++) {
208
	      if (subdomainLevel == 0)
Thomas Witkowski's avatar
Thomas Witkowski committed
209
		cols[i] = interiorMap->getLocalMatIndex(colComponent, cols[i]);
210
	      else
Thomas Witkowski's avatar
Thomas Witkowski committed
211
		cols[i] = interiorMap->getMatIndex(colComponent, cols[i]);
212
213
	    }
	    
214
  	    MatSetValues(getMatInterior(), 1, &localRowIndex, cols.size(),
215
  			 &(cols[0]), &(values[0]), ADD_VALUES);
Thomas Witkowski's avatar
Thomas Witkowski committed
216
	    
217
	    if (colsOther.size()) {
Thomas Witkowski's avatar
Thomas Witkowski committed
218
	      int globalRowIndex = interiorMap->getMatIndex(rowComponent, *cursor);
219
220
221

	      if (subdomainLevel != 0)
		globalRowIndex += rStartInterior;
Thomas Witkowski's avatar
Thomas Witkowski committed
222
	      
Thomas Witkowski's avatar
Thomas Witkowski committed
223
224
225
	      for (unsigned int i = 0; i < colsOther.size(); i++)
		colsOther[i] = 
		  colCoarseSpace->getMatIndex(colComponent, colsOther[i]);
226

Thomas Witkowski's avatar
Thomas Witkowski committed
227
  	      MatSetValues(getMatInteriorCoarseByComponent(colComponent), 
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
228
			   1, &globalRowIndex, colsOther.size(),
229
230
231
232
233
234
235
  			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
	    }
	  }
	} 
      }
    }

236
    matAssembly();
237

238
239
240
    // === Create solver for the non primal (thus local) variables. ===

    KSPCreate(mpiCommLocal, &kspInterior);
241
    KSPSetOperators(kspInterior, getMatInterior(), getMatInterior(),
242
		    SAME_NONZERO_PATTERN);
243
244
245
246
247
248
249
250
251
252
253
254
    KSPSetOptionsPrefix(kspInterior, "interior_");
    KSPSetType(kspInterior, KSPPREONLY);
    KSPGetPC(kspInterior, &pcInterior);
    PCSetType(pcInterior, PCLU);
    if (subdomainLevel == 0)
      PCFactorSetMatSolverPackage(pcInterior, MATSOLVERUMFPACK);
    else
      PCFactorSetMatSolverPackage(pcInterior, MATSOLVERMUMPS);
    KSPSetFromOptions(kspInterior);  
  }


255
256
257
  void PetscSolverGlobalMatrix::fillPetscRhs(SystemVector *vec)
  {
    FUNCNAME("PetscSolverGlobalMatrix::fillPetscRhs()");
Thomas Witkowski's avatar
Thomas Witkowski committed
258

259
    TEST_EXIT_DBG(vec)("No DOF vector defined!\n");
260
    TEST_EXIT_DBG(interiorMap)("No parallel DOF map defined!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
261
    
Thomas Witkowski's avatar
Thomas Witkowski committed
262
    // === Transfer values from DOF vector to the PETSc vector. === 
Thomas Witkowski's avatar
Thomas Witkowski committed
263
    if (coarseSpaceMap.size()) {
Thomas Witkowski's avatar
Thomas Witkowski committed
264
      for (int i = 0; i < vec->getSize(); i++)
265
266
	setDofVector(getVecRhsInterior(), 
		     getVecSolCoarseByComponent(i), vec->getDOFVector(i), i);
Thomas Witkowski's avatar
Thomas Witkowski committed
267
268
    } else {
      for (int i = 0; i < vec->getSize(); i++)
269
	setDofVector(getVecRhsInterior(), vec->getDOFVector(i), i);
Thomas Witkowski's avatar
Thomas Witkowski committed
270
271
    }

272
    vecRhsAssembly();
Thomas Witkowski's avatar
Thomas Witkowski committed
273
274
275
  }


276
277
  void PetscSolverGlobalMatrix::solvePetscMatrix(SystemVector &vec, 
						 AdaptInfo *adaptInfo)
Thomas Witkowski's avatar
Thomas Witkowski committed
278
279
280
281
282
283
284
  {
    FUNCNAME("PetscSolverGlobalMatrix::solvePetscMatrix()");

    int nComponents = vec.getSize();

    // === Set old solution to be initiual guess for PETSc solver. ===
    if (!zeroStartVector) {
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
285
286
      TEST_EXIT(coarseSpaceMap.size() == 0)("Not yet supported!\n");

287
      VecSet(getVecSolInterior(), 0.0);
Thomas Witkowski's avatar
Thomas Witkowski committed
288
289
      
      for (int i = 0; i < nComponents; i++)
290
	setDofVector(getVecSolInterior(), vec.getDOFVector(i), i, true);
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
291

292
      vecSolAssembly();
Thomas Witkowski's avatar
Thomas Witkowski committed
293
294
    }

295

Thomas Witkowski's avatar
Thomas Witkowski committed
296
297
    MatNullSpace matNullspace;
    Vec nullspaceBasis;
298
299
300
    if (nullspace.size() > 0 || 
	hasConstantNullspace ||
	constNullspaceComponent.size() > 0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
301
      TEST_EXIT_DBG(nullspace.size() <= 1)("Not yet implemented!\n");
302

303
304
305
306
307
308
309
310
311
312
      if (constNullspaceComponent.size() > 0) {
	nullspace.clear();
	SystemVector *basisVec = new SystemVector(vec);
	basisVec->set(0.0);
	for (unsigned int i = 0; i < constNullspaceComponent.size(); i++)
	  basisVec->getDOFVector(constNullspaceComponent[i])->set(1.0);

	nullspace.push_back(basisVec);
      } 

Thomas Witkowski's avatar
Thomas Witkowski committed
313
      if (nullspace.size() > 0) {
314
	VecDuplicate(getVecSolInterior(), &nullspaceBasis);
Thomas Witkowski's avatar
Thomas Witkowski committed
315
316
317
318
319
	for (int i = 0; i < nComponents; i++)
	  setDofVector(nullspaceBasis, nullspace[0]->getDOFVector(i), i, true);
	
	VecAssemblyBegin(nullspaceBasis);
	VecAssemblyEnd(nullspaceBasis);
320
321

	VecNormalize(nullspaceBasis, PETSC_NULL);
Thomas Witkowski's avatar
Thomas Witkowski committed
322
323
324
325
	
	MatNullSpaceCreate(mpiCommGlobal, (hasConstantNullspace ? PETSC_TRUE : PETSC_FALSE), 
			   1, &nullspaceBasis, &matNullspace);

326
	MatMult(getMatInterior(), nullspaceBasis, getVecSolInterior());
Thomas Witkowski's avatar
Thomas Witkowski committed
327
	PetscReal n;
328
	VecNorm(getVecSolInterior(), NORM_2, &n);
Thomas Witkowski's avatar
Thomas Witkowski committed
329
330
331
332
	MSG("NORM IS: %e\n", n);
      } else {
	MatNullSpaceCreate(mpiCommGlobal, PETSC_TRUE, 0, PETSC_NULL, &matNullspace);
      }
333

Thomas Witkowski's avatar
Thomas Witkowski committed
334
335
336
      MSG("NULLSPACE IS NOT REMOVED!\n");
      // MatSetNullSpace(getMatInterior(), matNullspace);
      // KSPSetNullSpace(kspInterior, matNullspace);
337

Thomas Witkowski's avatar
Thomas Witkowski committed
338
      // === Remove null space, if requested. ===
339

Thomas Witkowski's avatar
Thomas Witkowski committed
340
      if (removeRhsNullspace) {
Thomas Witkowski's avatar
Thomas Witkowski committed
341
	TEST_EXIT_DBG(coarseSpaceMap.empty())("Not supported!\n");
342
343

	MSG("Remove nullspace from rhs vector.\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
344
	
345
	MatNullSpaceRemove(matNullspace, getVecRhsInterior(), PETSC_NULL);
Thomas Witkowski's avatar
Thomas Witkowski committed
346
347
348
349
      }
    } else {
      TEST_EXIT(removeRhsNullspace == false)
	("No nullspace provided that should be removed from rhs!\n");
350
351
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
352
    // PETSc.
353
    solve(getVecRhsInterior(), getVecSolInterior());
Thomas Witkowski's avatar
Thomas Witkowski committed
354

355
356

    if (nullspace.size() > 0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
357
      MatNullSpaceDestroy(&matNullspace);
358
359
360
361
      VecDestroy(&nullspaceBasis);
    }


Thomas Witkowski's avatar
Thomas Witkowski committed
362
363
    // === Transfere values from PETSc's solution vectors to the DOF vectors. ===
    PetscScalar *vecPointer;
364
    VecGetArray(getVecSolInterior(), &vecPointer);    
Thomas Witkowski's avatar
Thomas Witkowski committed
365

366
    int c = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
367
    for (int i = 0; i < nComponents; i++) {
368
      DOFVector<double> &dv = *(vec.getDOFVector(i));
369

370
      DofMap& d = (*interiorMap)[dv.getFeSpace()].getMap();
371
372
373
      for (DofMap::iterator it = d.begin(); it != d.end(); ++it)
	if (it->second.local != -1)
	  dv[it->first] = vecPointer[c++];
Thomas Witkowski's avatar
Thomas Witkowski committed
374
375
    }

376
    VecRestoreArray(getVecSolInterior(), &vecPointer);
Thomas Witkowski's avatar
Thomas Witkowski committed
377
378
379
380

    // === Synchronize DOFs at common DOFs, i.e., DOFs that correspond to ===  
    // === more than one partition.                                       ===  
    meshDistributor->synchVector(vec);
381
382
383
  }


384
385
386
387
  void PetscSolverGlobalMatrix::solveGlobal(Vec &rhs, Vec &sol)
  {
    FUNCNAME("PetscSolverGlobalMatrix::solveGlobal()");

388
389
390
    double wtime = MPI::Wtime();
    double t0 = 0.0, t1 = 0.0;

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    Vec tmp;
    if (mpiCommLocal.Get_size() == 1)
      VecCreateSeq(mpiCommLocal, interiorMap->getRankDofs(), &tmp);
    else
      VecCreateMPI(mpiCommLocal,
		   interiorMap->getRankDofs(),
		   interiorMap->getOverallDofs(),
		   &tmp);

    PetscScalar *tmpValues, *rhsValues;
    VecGetArray(tmp, &tmpValues);
    VecGetArray(rhs, &rhsValues);

    for (int i = 0; i < interiorMap->getRankDofs(); i++)
      tmpValues[i] = rhsValues[i];

    VecRestoreArray(rhs, &rhsValues);
    VecRestoreArray(tmp, &tmpValues);

410
411
412
    t0 = MPI::Wtime() - wtime;

    wtime = MPI::Wtime();
413
    KSPSolve(kspInterior, tmp, tmp);
414
415
416
    t1 = MPI::Wtime() - wtime;

    wtime = MPI::Wtime();
417
418
419
420
421
422
423
424
425
426
427

    VecGetArray(tmp, &tmpValues);
    VecGetArray(sol, &rhsValues);

    for (int i = 0; i < interiorMap->getRankDofs(); i++) 
      rhsValues[i] = tmpValues[i];

    VecRestoreArray(sol, &rhsValues);
    VecRestoreArray(tmp, &tmpValues);

    VecDestroy(&tmp);
428
429
    t0 += MPI::Wtime() - wtime;

430
    //    MSG("TIMEING: %.5f %.5f\n", t0, t1);
431
432
433
  }


434
435
436
437
  void PetscSolverGlobalMatrix::destroyMatrixData()
  {
    FUNCNAME("PetscSolverGlobalMatrix::destroyMatrixData()");

438
439
    exitPreconditioner(pcInterior);

440
    matDestroy();
Thomas Witkowski's avatar
Thomas Witkowski committed
441

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
442
    KSPDestroy(&kspInterior);
Thomas Witkowski's avatar
Thomas Witkowski committed
443
444
445
  }


446
447
448
449
  void PetscSolverGlobalMatrix::destroyVectorData()
  {
    FUNCNAME("PetscSolverGlobalMatrix::destroyVectorData()");

450
    vecDestroy();
451
452
453
  }


454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  void PetscSolverGlobalMatrix::createFieldSplit(PC pc)
  {
    FUNCNAME("PetscSolverGlobalMatrix::createFieldSplit()");

    vector<string> isNames;
    Parameters::get("parallel->solver->is blocks", isNames);

    int nBlocks = isNames.size();
    if (nBlocks == 0)
      return;

    for (int i = 0; i < nBlocks; i++) {
      MSG("Create for block %s\n", isNames[i].c_str());

      vector<int> blockComponents;
      Parameters::get("parallel->solver->is block " + lexical_cast<string>(i),
		      blockComponents);
      int nComponents = static_cast<int>(blockComponents.size());

473
      TEST_EXIT(nComponents > 0)("No IS block for block %d defined!\n", i);
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489

      // Check if blocks are continous
      for (int j = 0; j < nComponents; j++) {
	TEST_EXIT(blockComponents[j] == blockComponents[0] + j)
	  ("Does not yet support not continous IS blocks! Block %s\n", 
	   isNames[i].c_str());
      }

      IS is;
      interiorMap->createIndexSet(is, blockComponents[0], nComponents);
      PCFieldSplitSetIS(pc, isNames[i].c_str(), is);
      ISDestroy(&is);
    }
  }


490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
  void PetscSolverGlobalMatrix::initPreconditioner(PC pc)
  {
    FUNCNAME("PetscSolverGlobalMatrix::initPreconditioner()");

    PCSetFromOptions(pc);
    createFieldSplit(pc);
  }

 
  void PetscSolverGlobalMatrix::exitPreconditioner(PC pc)
  {
    FUNCNAME("PetscSolverGlobalMatrix::exitPreconditioner()");
  }


Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
505
  void PetscSolverGlobalMatrix::setDofMatrix(DOFMatrix* seqMat,
506
					     int nRowMat, int nColMat)
Thomas Witkowski's avatar
Thomas Witkowski committed
507
508
509
  {
    FUNCNAME("PetscSolverGlobalMatrix::setDofMatrix()");

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
510
    TEST_EXIT(seqMat)("No DOFMatrix!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
511
512

    using mtl::tag::row; using mtl::tag::nz; using mtl::begin; using mtl::end;
513
    namespace traits = mtl::traits;
Thomas Witkowski's avatar
Thomas Witkowski committed
514
515
    typedef DOFMatrix::base_matrix_type Matrix;

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
516
517
    traits::col<Matrix>::type col(seqMat->getBaseMatrix());
    traits::const_value<Matrix>::type value(seqMat->getBaseMatrix());
Thomas Witkowski's avatar
Thomas Witkowski committed
518
519
520
521
522
523
524
525
526
527
528

    typedef traits::range_generator<row, Matrix>::type cursor_type;
    typedef traits::range_generator<nz, cursor_type>::type icursor_type;

    vector<int> cols;
    vector<double> values;
    cols.reserve(300);
    values.reserve(300);
    
    vector<int> globalCols;

529
530
531
    // Get periodic mapping object
    PeriodicMap &perMap = meshDistributor->getPeriodicMap();

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
532
533
    const FiniteElemSpace *rowFe = seqMat->getRowFeSpace();
    const FiniteElemSpace *colFe = seqMat->getColFeSpace();
Thomas Witkowski's avatar
Thomas Witkowski committed
534
535
536
537
    DofMap& rowMap = (*interiorMap)[rowFe].getMap();
    DofMap& colMap = (*interiorMap)[colFe].getMap();

    // === Traverse all rows of the DOF matrix and insert row wise the values ===
Thomas Witkowski's avatar
Thomas Witkowski committed
538
539
    // === to the PETSc matrix.                                               ===

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
540
541
    for (cursor_type cursor = begin<row>(seqMat->getBaseMatrix()), 
	   cend = end<row>(seqMat->getBaseMatrix()); cursor != cend; ++cursor) {
Thomas Witkowski's avatar
Thomas Witkowski committed
542
      // Global index of the current row DOF.
Thomas Witkowski's avatar
Thomas Witkowski committed
543
      int globalRowDof = rowMap[*cursor].global;
544

Thomas Witkowski's avatar
Thomas Witkowski committed
545
      // Test if the current row DOF is a periodic DOF.
546
      bool periodicRow = perMap.isPeriodic(rowFe, globalRowDof);
547

Thomas Witkowski's avatar
Thomas Witkowski committed
548
549
550
      if (!periodicRow) {
	// === Row DOF index is not periodic. ===

551
	// Get PETSc's mat row index.
552
	int rowIndex = interiorMap->getMatIndex(nRowMat, globalRowDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
553
554
555
556
557
558
559
560

	cols.clear();
	values.clear();

	for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); 
	     icursor != icend; ++icursor) {

	  // Global index of the current column index.
Thomas Witkowski's avatar
Thomas Witkowski committed
561
	  int globalColDof = colMap[col(*icursor)].global;
Thomas Witkowski's avatar
Thomas Witkowski committed
562
	  // Test if the current col dof is a periodic dof.
563
	  bool periodicCol = perMap.isPeriodic(colFe, globalColDof);
564
	  // Get PETSc's mat col index.
565
	  int colIndex = interiorMap->getMatIndex(nColMat, globalColDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
566
567
568
569
570
571
572

	  // Ignore all zero entries, expect it is a diagonal entry.
 	  if (value(*icursor) == 0.0 && rowIndex != colIndex)
 	    continue;

	  if (!periodicCol) {
	    // Calculate the exact position of the column index in the PETSc matrix.
Thomas Witkowski's avatar
Thomas Witkowski committed
573
574
 	    cols.push_back(colIndex);
 	    values.push_back(value(*icursor));
Thomas Witkowski's avatar
Thomas Witkowski committed
575
576
577
578
579
	  } else {
	    // === Row index is not periodic, but column index is. ===

	    // Create set of all periodic associations of the column index.
	    std::set<int> perAsc;
580
581
582
	    perMap.fillAssociations(colFe, globalColDof, 
				    meshDistributor->getElementObjectDb(), perAsc);

Thomas Witkowski's avatar
Thomas Witkowski committed
583
584
585
586
587
588
589
590
591
	    // Scale value to the number of periodic associations of the column index.
	    double scaledValue = 
	      value(*icursor) * pow(0.5, static_cast<double>(perAsc.size()));

	    
	    // === Create set of all matrix column indices due to the periodic ===
	    // === associations of the column DOF index.                       ===

	    vector<int> newCols;
592
	    perMap.mapDof(colFe, globalColDof, perAsc, newCols);
Thomas Witkowski's avatar
Thomas Witkowski committed
593
	    for (unsigned int i = 0; i < newCols.size(); i++) {
594
	      cols.push_back(interiorMap->getMatIndex(nColMat, newCols[i]));
Thomas Witkowski's avatar
Thomas Witkowski committed
595
596
597
598
599
	      values.push_back(scaledValue);	      
	    }
	  }
	}

600
  	MatSetValues(getMatInterior(), 1, &rowIndex, cols.size(), 
Thomas Witkowski's avatar
Thomas Witkowski committed
601
  		     &(cols[0]), &(values[0]), ADD_VALUES);	
Thomas Witkowski's avatar
Thomas Witkowski committed
602
603
604
605
606
607
608
609
610
611
612
613
614
615
      } else {
	// === Row DOF index is periodic. ===

	// Because this row is periodic, we will have to add the entries of this 
	// matrix row to multiple rows. The following maps store to each row an
	// array of column indices and values of the entries that must be added to
	// the PETSc matrix.
	map<int, vector<int> > colsMap;
	map<int, vector<double> > valsMap;

	// Traverse all column entries.
	for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); 
	     icursor != icend; ++icursor) {
	  // Global index of the current column index.
616
	  int globalColDof = (*interiorMap)[colFe][col(*icursor)].global;
Thomas Witkowski's avatar
Thomas Witkowski committed
617
618
619
620
621
622
623
624
625

	  // Ignore all zero entries, expect it is a diagonal entry.
 	  if (value(*icursor) == 0.0 && globalRowDof != globalColDof)
 	    continue;

	  // === Add all periodic associations of both, the row and the column ===
	  // === indices to the set perAsc.                                    ===

	  std::set<int> perAsc;
626
627
628
629
	  perMap.fillAssociations(colFe, globalColDof, 
				  meshDistributor->getElementObjectDb(), perAsc);
	  perMap.fillAssociations(rowFe, globalRowDof, 
				  meshDistributor->getElementObjectDb(), perAsc);
Thomas Witkowski's avatar
Thomas Witkowski committed
630
631
632
633
634
635
636
637
638
639

	  // Scale the value with respect to the number of periodic associations.
	  double scaledValue = 
	    value(*icursor) * pow(0.5, static_cast<double>(perAsc.size()));


	  // === Create all matrix entries with respect to the periodic  ===
	  // === associations of the row and column indices.             ===

	  vector<pair<int, int> > entry;
Thomas Witkowski's avatar
Blbu  
Thomas Witkowski committed
640
641
	  perMap.mapDof(rowFe, colFe, make_pair(globalRowDof, globalColDof),
			perAsc, entry);
Thomas Witkowski's avatar
Thomas Witkowski committed
642
643
644

	  // === Translate the matrix entries to PETSc's matrix.

645
	  for (unsigned int i = 0; i < entry.size(); i++) {
646
647
	    int rowIdx = interiorMap->getMatIndex(nRowMat, entry[i].first);
	    int colIdx = interiorMap->getMatIndex(nColMat, entry[i].second);
Thomas Witkowski's avatar
Thomas Witkowski committed
648

649
650
	    colsMap[rowIdx].push_back(colIdx);
	    valsMap[rowIdx].push_back(scaledValue);
Thomas Witkowski's avatar
Thomas Witkowski committed
651
652
653
654
655
656
657
658
659
660
661
662
	  }
	}


	// === Finally, add all periodic rows to the PETSc matrix. ===

	for (map<int, vector<int> >::iterator rowIt = colsMap.begin();
	     rowIt != colsMap.end(); ++rowIt) {
	  TEST_EXIT_DBG(rowIt->second.size() == valsMap[rowIt->first].size())
	    ("Should not happen!\n");

	  int rowIndex = rowIt->first;
663

664
	  MatSetValues(getMatInterior(), 1, &rowIndex, rowIt->second.size(),
Thomas Witkowski's avatar
Thomas Witkowski committed
665
666
667
668
669
670
671
		       &(rowIt->second[0]), &(valsMap[rowIt->first][0]), ADD_VALUES);
	}
      }
    }
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
672
673
  void PetscSolverGlobalMatrix::setDofVector(Vec vecInterior, 
					     Vec vecCoarse,
674
					     DOFVector<double>* vec, 
675
					     int nRowVec, 
676
					     bool rankOnly)
Thomas Witkowski's avatar
Thomas Witkowski committed
677
678
679
  {
    FUNCNAME("PetscSolverGlobalMatrix::setDofVector()");

680
    const FiniteElemSpace *feSpace = vec->getFeSpace();
681
    PeriodicMap &perMap = meshDistributor->getPeriodicMap();
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
682

683
684
    ParallelDofMapping *rowCoarseSpace = 
      (coarseSpaceMap.size() ? coarseSpaceMap[nRowVec] : NULL);
685

Thomas Witkowski's avatar
Thomas Witkowski committed
686
687
688
    // Traverse all used DOFs in the dof vector.
    DOFVector<double>::Iterator dofIt(vec, USED_DOFS);
    for (dofIt.reset(); !dofIt.end(); ++dofIt) {
689

690
      if (rankOnly && !(*interiorMap)[feSpace].isRankDof(dofIt.getDOFIndex()))
Thomas Witkowski's avatar
Thomas Witkowski committed
691
692
	continue;

Thomas Witkowski's avatar
Thomas Witkowski committed
693
      if (isCoarseSpace(nRowVec, feSpace, dofIt.getDOFIndex())) {
694
695
	TEST_EXIT_DBG(vecCoarse != PETSC_NULL)("Should not happen!\n");

Thomas Witkowski's avatar
Thomas Witkowski committed
696
	int index = rowCoarseSpace->getMatIndex(nRowVec, dofIt.getDOFIndex());
697
698
699
700
701
702
703
704
705
706
707
708
709
710
	VecSetValue(vecCoarse, index, *dofIt, ADD_VALUES);
      } else {
	// Calculate global row index of the DOF.
	DegreeOfFreedom globalRowDof = 
	  (*interiorMap)[feSpace][dofIt.getDOFIndex()].global;
	
	// Get PETSc's mat index of the row DOF.
	int index = 0;
	if (interiorMap->isMatIndexFromGlobal())
	  index = 
	    interiorMap->getMatIndex(nRowVec, globalRowDof) + rStartInterior;
	else
	  index =
	    interiorMap->getMatIndex(nRowVec, dofIt.getDOFIndex()) + rStartInterior;
711

712
	if (perMap.isPeriodic(feSpace, globalRowDof)) {
Thomas Witkowski's avatar
Thomas Witkowski committed
713
714
715
	  std::set<int>& perAsc = perMap.getAssociations(feSpace, globalRowDof);
	  double value = *dofIt / (perAsc.size() + 1.0);
	  VecSetValue(vecInterior, index, value, ADD_VALUES);
716

Thomas Witkowski's avatar
Thomas Witkowski committed
717
718
719
720
	  for (std::set<int>::iterator perIt = perAsc.begin(); 
	       perIt != perAsc.end(); ++perIt) {
	    int mappedDof = perMap.map(feSpace, *perIt, globalRowDof);
	    int mappedIndex = interiorMap->getMatIndex(nRowVec, mappedDof);
721

Thomas Witkowski's avatar
Thomas Witkowski committed
722
	    VecSetValue(vecInterior, mappedIndex, value, ADD_VALUES);
723
724
725
726
	  }	  
	} else {	  
	  // The DOF index is not periodic.
	  
Thomas Witkowski's avatar
Thomas Witkowski committed
727
728
	  VecSetValue(vecInterior, index, *dofIt, ADD_VALUES);
	}
Thomas Witkowski's avatar
Thomas Witkowski committed
729
730
731
732
733
      }
    }
  }

}