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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    // === 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
128
    int nComponents = seqMat->getSize();
Thomas Witkowski's avatar
Thomas Witkowski committed
129 130 131 132 133
    for (int rowComponent = 0; rowComponent < nComponents; rowComponent++) {
      for (int colComponent = 0; colComponent < nComponents; colComponent++) {
	DOFMatrix* dofMat = (*seqMat)[rowComponent][colComponent];

	if (!dofMat)
134 135
	  continue;

Thomas Witkowski's avatar
Thomas Witkowski committed
136 137
	ParallelDofMapping *rowCoarseSpace = coarseSpaceMap[rowComponent];
	ParallelDofMapping *colCoarseSpace = coarseSpaceMap[colComponent];
Thomas Witkowski's avatar
Thomas Witkowski committed
138

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

Thomas Witkowski's avatar
Thomas Witkowski committed
146
	  bool isRowCoarse = 
Thomas Witkowski's avatar
Thomas Witkowski committed
147
	    isCoarseSpace(rowComponent, feSpaces[rowComponent], *cursor);
148 149 150 151 152 153 154 155 156 157
  
	  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
158 159
	    bool isColCoarse = 
	      isCoarseSpace(colComponent, feSpaces[colComponent], col(*icursor));
160

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
161 162 163 164
	    if (isColCoarse == false)
	      if ((*interiorMap)[dofMat->getColFeSpace()].isSet(col(*icursor)) == false)
		continue;

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


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

Thomas Witkowski's avatar
Thomas Witkowski committed
177
	  if (isRowCoarse) {
Thomas Witkowski's avatar
Thomas Witkowski committed
178 179
	    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
	    int rowIndex = rowCoarseSpace->getMatIndex(rowComponent, *cursor);
Thomas Witkowski's avatar
Thomas Witkowski committed
182
	    MatSetValues(getMatCoarseByComponent(rowComponent, colComponent),
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
183
			 1, &rowIndex, cols.size(),
184 185 186
			 &(cols[0]), &(values[0]), ADD_VALUES);

	    if (colsOther.size()) {
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]) + 
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
190
		  rStartInterior;	      
191

Thomas Witkowski's avatar
Thomas Witkowski committed
192
	      MatSetValues(getMatCoarseInteriorByComponent(rowComponent), 
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
193
			   1, &rowIndex, colsOther.size(),
194 195 196
 			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
	    }
	  } else {
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
197 198 199
	    if ((*interiorMap)[dofMat->getRowFeSpace()].isSet(*cursor) == false)
	      continue;

200
	    int localRowIndex = 
Thomas Witkowski's avatar
Thomas Witkowski committed
201 202 203
	      (subdomainLevel == 0 ? 
	       interiorMap->getLocalMatIndex(rowComponent, *cursor) :
	       interiorMap->getMatIndex(rowComponent, *cursor));
204

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

Thomas Witkowski's avatar
Thomas Witkowski committed
223
  	      MatSetValues(getMatInteriorCoarseByComponent(colComponent), 
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
224
			   1, &globalRowIndex, colsOther.size(),
225 226 227 228 229 230 231
  			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
	    }
	  }
	} 
      }
    }

232
    matAssembly();
233

234 235 236
    // === Create solver for the non primal (thus local) variables. ===

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


251 252 253
  void PetscSolverGlobalMatrix::fillPetscRhs(SystemVector *vec)
  {
    FUNCNAME("PetscSolverGlobalMatrix::fillPetscRhs()");
Thomas Witkowski's avatar
Thomas Witkowski committed
254

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

268
    vecRhsAssembly();
Thomas Witkowski's avatar
Thomas Witkowski committed
269 270 271
  }


272 273
  void PetscSolverGlobalMatrix::solvePetscMatrix(SystemVector &vec, 
						 AdaptInfo *adaptInfo)
Thomas Witkowski's avatar
Thomas Witkowski committed
274 275 276 277 278 279 280
  {
    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
281 282
      TEST_EXIT(coarseSpaceMap.size() == 0)("Not yet supported!\n");

283
      VecSet(getVecSolInterior(), 0.0);
Thomas Witkowski's avatar
Thomas Witkowski committed
284 285
      
      for (int i = 0; i < nComponents; i++)
286
	setDofVector(getVecSolInterior(), vec.getDOFVector(i), i, true);
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
287

288
      vecSolAssembly();
Thomas Witkowski's avatar
Thomas Witkowski committed
289 290
    }

291

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

299 300 301 302 303 304 305 306 307 308
      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
309
      if (nullspace.size() > 0) {
310
	VecDuplicate(getVecSolInterior(), &nullspaceBasis);
Thomas Witkowski's avatar
Thomas Witkowski committed
311 312 313 314 315
	for (int i = 0; i < nComponents; i++)
	  setDofVector(nullspaceBasis, nullspace[0]->getDOFVector(i), i, true);
	
	VecAssemblyBegin(nullspaceBasis);
	VecAssemblyEnd(nullspaceBasis);
316 317

	VecNormalize(nullspaceBasis, PETSC_NULL);
Thomas Witkowski's avatar
Thomas Witkowski committed
318 319 320 321
	
	MatNullSpaceCreate(mpiCommGlobal, (hasConstantNullspace ? PETSC_TRUE : PETSC_FALSE), 
			   1, &nullspaceBasis, &matNullspace);

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

Thomas Witkowski's avatar
Thomas Witkowski committed
330 331 332
      MSG("NULLSPACE IS NOT REMOVED!\n");
      // MatSetNullSpace(getMatInterior(), matNullspace);
      // KSPSetNullSpace(kspInterior, matNullspace);
333

Thomas Witkowski's avatar
Thomas Witkowski committed
334
      // === Remove null space, if requested. ===
335

Thomas Witkowski's avatar
Thomas Witkowski committed
336
      if (removeRhsNullspace) {
Thomas Witkowski's avatar
Thomas Witkowski committed
337
	TEST_EXIT_DBG(coarseSpaceMap.empty())("Not supported!\n");
338 339

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

Thomas Witkowski's avatar
Thomas Witkowski committed
348
    // PETSc.
349
    solve(getVecRhsInterior(), getVecSolInterior());
Thomas Witkowski's avatar
Thomas Witkowski committed
350

351 352

    if (nullspace.size() > 0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
353
      MatNullSpaceDestroy(&matNullspace);
354 355 356 357
      VecDestroy(&nullspaceBasis);
    }


Thomas Witkowski's avatar
Thomas Witkowski committed
358 359
    // === Transfere values from PETSc's solution vectors to the DOF vectors. ===
    PetscScalar *vecPointer;
360
    VecGetArray(getVecSolInterior(), &vecPointer);    
Thomas Witkowski's avatar
Thomas Witkowski committed
361

362
    int c = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
363
    for (int i = 0; i < nComponents; i++) {
364
      DOFVector<double> &dv = *(vec.getDOFVector(i));
365

366
      DofMap& d = (*interiorMap)[dv.getFeSpace()].getMap();
367 368 369
      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
370 371
    }

372
    VecRestoreArray(getVecSolInterior(), &vecPointer);
Thomas Witkowski's avatar
Thomas Witkowski committed
373 374 375 376

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


380 381 382 383
  void PetscSolverGlobalMatrix::solveGlobal(Vec &rhs, Vec &sol)
  {
    FUNCNAME("PetscSolverGlobalMatrix::solveGlobal()");

384 385 386
    double wtime = MPI::Wtime();
    double t0 = 0.0, t1 = 0.0;

387 388
    Vec tmp;
    if (mpiCommLocal.Get_size() == 1)
Thomas Witkowski's avatar
Thomas Witkowski committed
389
      interiorMap->createLocalVec(tmp);
390
    else
Thomas Witkowski's avatar
Thomas Witkowski committed
391
      interiorMap->createVec(tmp);
392 393 394 395 396 397 398 399 400 401 402

    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);

403 404 405
    t0 = MPI::Wtime() - wtime;

    wtime = MPI::Wtime();
406
    KSPSolve(kspInterior, tmp, tmp);
407 408 409
    t1 = MPI::Wtime() - wtime;

    wtime = MPI::Wtime();
410 411 412 413 414 415 416 417 418 419 420

    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);
421 422
    t0 += MPI::Wtime() - wtime;

423
    //    MSG("TIMEING: %.5f %.5f\n", t0, t1);
424 425 426
  }


427 428 429 430
  void PetscSolverGlobalMatrix::destroyMatrixData()
  {
    FUNCNAME("PetscSolverGlobalMatrix::destroyMatrixData()");

431 432
    exitPreconditioner(pcInterior);

433
    matDestroy();
Thomas Witkowski's avatar
Thomas Witkowski committed
434

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
435
    KSPDestroy(&kspInterior);
Thomas Witkowski's avatar
Thomas Witkowski committed
436 437 438
  }


439 440 441 442
  void PetscSolverGlobalMatrix::destroyVectorData()
  {
    FUNCNAME("PetscSolverGlobalMatrix::destroyVectorData()");

443
    vecDestroy();
444 445 446
  }


447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
  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());

466
      TEST_EXIT(nComponents > 0)("No IS block for block %d defined!\n", i);
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482

      // 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);
    }
  }


483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
  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
498
  void PetscSolverGlobalMatrix::setDofMatrix(DOFMatrix* seqMat,
499
					     int nRowMat, int nColMat)
Thomas Witkowski's avatar
Thomas Witkowski committed
500 501 502
  {
    FUNCNAME("PetscSolverGlobalMatrix::setDofMatrix()");

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
503
    TEST_EXIT(seqMat)("No DOFMatrix!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
504 505

    using mtl::tag::row; using mtl::tag::nz; using mtl::begin; using mtl::end;
506
    namespace traits = mtl::traits;
Thomas Witkowski's avatar
Thomas Witkowski committed
507 508
    typedef DOFMatrix::base_matrix_type Matrix;

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
509 510
    traits::col<Matrix>::type col(seqMat->getBaseMatrix());
    traits::const_value<Matrix>::type value(seqMat->getBaseMatrix());
Thomas Witkowski's avatar
Thomas Witkowski committed
511 512 513 514 515 516 517 518 519 520 521

    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;

522 523 524
    // Get periodic mapping object
    PeriodicMap &perMap = meshDistributor->getPeriodicMap();

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
525 526
    const FiniteElemSpace *rowFe = seqMat->getRowFeSpace();
    const FiniteElemSpace *colFe = seqMat->getColFeSpace();
Thomas Witkowski's avatar
Thomas Witkowski committed
527 528

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

Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
531 532
    for (cursor_type cursor = begin<row>(seqMat->getBaseMatrix()), 
	   cend = end<row>(seqMat->getBaseMatrix()); cursor != cend; ++cursor) {
Thomas Witkowski's avatar
Thomas Witkowski committed
533
      // Global index of the current row DOF.
534 535 536 537 538
      MultiIndex rowMultiIndex;
      if ((*interiorMap)[rowFe].find(*cursor, rowMultiIndex) == false)
	continue;

      int globalRowDof = rowMultiIndex.global;
539

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

Thomas Witkowski's avatar
Thomas Witkowski committed
543 544 545
      if (!periodicRow) {
	// === Row DOF index is not periodic. ===

546
	// Get PETSc's mat row index.
547
	int rowIndex = interiorMap->getMatIndex(nRowMat, globalRowDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
548 549 550 551 552 553 554 555

	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.
556 557 558 559 560
	  MultiIndex colMultiIndex;
	  if ((*interiorMap)[colFe].find(col(*icursor), colMultiIndex) == false)
	    continue;

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

	  // 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
572 573
 	    cols.push_back(colIndex);
 	    values.push_back(value(*icursor));
Thomas Witkowski's avatar
Thomas Witkowski committed
574 575 576 577 578
	  } else {
	    // === Row index is not periodic, but column index is. ===

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

Thomas Witkowski's avatar
Thomas Witkowski committed
582 583 584 585 586 587 588 589 590
	    // 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;
591
	    perMap.mapDof(colFe, globalColDof, perAsc, newCols);
Thomas Witkowski's avatar
Thomas Witkowski committed
592
	    for (unsigned int i = 0; i < newCols.size(); i++) {
593
	      cols.push_back(interiorMap->getMatIndex(nColMat, newCols[i]));
Thomas Witkowski's avatar
Thomas Witkowski committed
594 595 596 597 598
	      values.push_back(scaledValue);	      
	    }
	  }
	}

599
  	MatSetValues(getMatInterior(), 1, &rowIndex, cols.size(), 
Thomas Witkowski's avatar
Thomas Witkowski committed
600
  		     &(cols[0]), &(values[0]), ADD_VALUES);	
Thomas Witkowski's avatar
Thomas Witkowski committed
601 602 603 604 605 606 607 608 609 610 611 612 613 614
      } 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.
615
	  int globalColDof = (*interiorMap)[colFe][col(*icursor)].global;
Thomas Witkowski's avatar
Thomas Witkowski committed
616 617 618 619 620 621 622 623 624

	  // 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;
625 626 627 628
	  perMap.fillAssociations(colFe, globalColDof, 
				  meshDistributor->getElementObjectDb(), perAsc);
	  perMap.fillAssociations(rowFe, globalRowDof, 
				  meshDistributor->getElementObjectDb(), perAsc);
Thomas Witkowski's avatar
Thomas Witkowski committed
629 630 631 632 633 634 635 636 637 638

	  // 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
639 640
	  perMap.mapDof(rowFe, colFe, make_pair(globalRowDof, globalColDof),
			perAsc, entry);
Thomas Witkowski's avatar
Thomas Witkowski committed
641 642 643

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

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

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


	// === 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;
662

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


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

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

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

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

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

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

Thomas Witkowski's avatar
Thomas Witkowski committed
695
	int index = rowCoarseSpace->getMatIndex(nRowVec, dofIt.getDOFIndex());
696 697
	VecSetValue(vecCoarse, index, *dofIt, ADD_VALUES);
      } else {
Thomas Witkowski's avatar
Blub  
Thomas Witkowski committed
698 699 700
	if ((*interiorMap)[feSpace].isSet(dofIt.getDOFIndex()) == false)
	  continue;

701 702 703 704 705 706 707 708 709 710 711 712
	// 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;
713

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

Thomas Witkowski's avatar
Thomas Witkowski committed
719 720 721 722
	  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);
723

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

}