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
      }
    }
  }

}