PetscSolverGlobalMatrix.cc 46.7 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 {

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

24
    if (coarseSpaceMap != NULL) {
Thomas Witkowski's avatar
Thomas Witkowski committed
25
      updateSubdomainData();
26 27 28 29
      fillPetscMatrixWithCoarseSpace(mat);
      return;
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
30
    TEST_EXIT_DBG(meshDistributor)("No mesh distributor object defined!\n");
31
    TEST_EXIT_DBG(interiorMap)("No parallel mapping object defined!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
32
    TEST_EXIT_DBG(mat)("No DOF matrix defined!\n");
33
    
Thomas Witkowski's avatar
Thomas Witkowski committed
34
    double wtime = MPI::Wtime();
35

36
    // === If required, recompute non zero structure of the matrix. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
37

38
    if (checkMeshChange(mat))
Thomas Witkowski's avatar
Thomas Witkowski committed
39 40 41
      createPetscNnzStructure(mat);


42 43
    // === Create PETSc vector (solution and a temporary vector). ===

44 45
    int nRankRows = interiorMap->getRankDofs();
    int nOverallRows = interiorMap->getOverallDofs();
46

47
    VecCreateMPI(mpiCommGlobal, nRankRows, nOverallRows, &petscSolVec);
48 49


Thomas Witkowski's avatar
Thomas Witkowski committed
50 51
    // === Create PETSc matrix with the computed nnz data structure. ===

52
    MatCreateAIJ(mpiCommGlobal, nRankRows, nRankRows, 
53
		 nOverallRows, nOverallRows,
54 55 56
		 0, nnzInterior.dnnz, 
		 0, nnzInterior.onnz, 
		 &matIntInt);
57 58

    MatSetOption(matIntInt, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
59

Thomas Witkowski's avatar
Thomas Witkowski committed
60 61 62 63 64 65
#if (DEBUG != 0)
    MSG("Fill petsc matrix 1 needed %.5f seconds\n", MPI::Wtime() - wtime);
#endif

#if (DEBUG != 0)
    int a, b;
66 67 68
    MatGetOwnershipRange(matIntInt, &a, &b);
    TEST_EXIT(a == interiorMap->getStartDofs())("Wrong matrix ownership range!\n");
    TEST_EXIT(b == interiorMap->getStartDofs() + nRankRows)
Thomas Witkowski's avatar
Thomas Witkowski committed
69 70 71 72 73 74
      ("Wrong matrix ownership range!\n");
#endif


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

75
    int nComponents = mat->getNumRows();
Thomas Witkowski's avatar
Thomas Witkowski committed
76 77 78
    for (int i = 0; i < nComponents; i++)
      for (int j = 0; j < nComponents; j++)
	if ((*mat)[i][j])
79
	  setDofMatrix((*mat)[i][j], i, j);
Thomas Witkowski's avatar
Thomas Witkowski committed
80 81 82 83 84

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

85 86
    MatAssemblyBegin(matIntInt, MAT_FINAL_ASSEMBLY);
    MatAssemblyEnd(matIntInt, MAT_FINAL_ASSEMBLY);
Thomas Witkowski's avatar
Thomas Witkowski committed
87

88 89 90

    // === Remove Dirichlet BC DOFs. ===

91
    //    removeDirichletBcDofs(mat);
92 93
    

94
    // === Init PETSc solver. ===
95

96 97 98 99 100 101 102
    KSPCreate(mpiCommGlobal, &kspInterior);
    KSPGetPC(kspInterior, &pcInterior);
    KSPSetOperators(kspInterior, matIntInt, matIntInt, SAME_NONZERO_PATTERN); 
    KSPSetTolerances(kspInterior, 0.0, 1e-8, PETSC_DEFAULT, PETSC_DEFAULT);
    KSPSetType(kspInterior, KSPBCGS);
    KSPSetOptionsPrefix(kspInterior, kspPrefix.c_str());
    KSPSetFromOptions(kspInterior);
103

104
    initPreconditioner(pcInterior);
105

106 107
    // Do not delete the solution vector, use it for the initial guess.
    if (!zeroStartVector)
108
      KSPSetInitialGuessNonzero(kspInterior, PETSC_TRUE);
109

Thomas Witkowski's avatar
Thomas Witkowski committed
110 111 112
#if (DEBUG != 0)
    MSG("Fill petsc matrix 3 needed %.5f seconds\n", MPI::Wtime() - wtime);
#endif
113 114 115
  }


116 117 118 119 120 121 122 123
  void PetscSolverGlobalMatrix::fillPetscMatrix(DOFMatrix *mat)
  {
    Matrix<DOFMatrix*> m(1, 1);
    m[0][0] = mat;
    fillPetscMatrix(&m);
  }


124 125 126 127 128 129 130 131 132
  void PetscSolverGlobalMatrix::fillPetscMatrixWithCoarseSpace(Matrix<DOFMatrix*> *mat)
  {
    FUNCNAME("PetscSolverGlobalMatrix::fillPetscMatrixWithCoarseSpace()");
    
    vector<const FiniteElemSpace*> feSpaces = getFeSpaces(mat);

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

133 134 135 136
    // === If required, recompute non zero structure of the matrix. ===

    bool localMatrix = (subdomainLevel == 0);
    if (checkMeshChange(mat, localMatrix)) {
137 138 139 140 141 142 143 144 145 146 147
       createPetscNnzStructureWithCoarseSpace(mat, 
					      *interiorMap,
					      *interiorMap,
					      nnzInterior,
					      localMatrix);

      if (coarseSpaceMap) {
 	createPetscNnzStructureWithCoarseSpace(mat, 
 					       *coarseSpaceMap,
 					       *coarseSpaceMap,
 					       nnzCoarse);
148
	createPetscNnzStructureWithCoarseSpace(mat, 
149 150 151 152 153 154 155 156
					       *coarseSpaceMap,
					       *interiorMap,
					       nnzCoarseInt);
 	createPetscNnzStructureWithCoarseSpace(mat, 
 					       *interiorMap,
 					       *coarseSpaceMap,
 					       nnzIntCoarse);
      }
157 158 159
    }

    if (localMatrix) {
160
      MatCreateSeqAIJ(mpiCommLocal, nRowsRankInterior, nRowsRankInterior,
161 162 163
		      0, nnzInterior.dnnz, 
		      &matIntInt);
      //      MatSetOption(matIntInt, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
164
    } else {
165 166 167
      MatCreateAIJ(mpiCommLocal, 
		   nRowsRankInterior, nRowsRankInterior,
		   nRowsOverallInterior, nRowsOverallInterior,
168
		   0, nnzInterior.dnnz, 0, nnzInterior.onnz, 
169
		   &matIntInt);
170
      //      MatSetOption(matIntInt, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
171
    }
172
    
173 174 175 176
    if (coarseSpaceMap) {
      int nRowsRankCoarse = coarseSpaceMap->getRankDofs();
      int nRowsOverallCoarse = coarseSpaceMap->getOverallDofs();

177 178 179
      MatCreateAIJ(mpiCommGlobal,
		   nRowsRankCoarse, nRowsRankCoarse,
		   nRowsOverallCoarse, nRowsOverallCoarse,
180 181
		   0, nnzCoarse.dnnz, 0, nnzCoarse.onnz, 
		   //	   100, PETSC_NULL, 100, PETSC_NULL,
182
		   &matCoarseCoarse);
183
      //      MatSetOption(matCoarseCoarse, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
184

185 186 187
      MatCreateAIJ(mpiCommGlobal,
		   nRowsRankCoarse, nRowsRankInterior,
		   nRowsOverallCoarse, nGlobalOverallInterior,
188
		   100, PETSC_NULL, 100, PETSC_NULL,
189
		   //	   0, nnzCoarseInt.dnnz, 0, nnzCoarseInt.onnz,
190 191 192
		   &matCoarseInt);
      MatSetOption(matCoarseInt, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);

193 194 195
      MatCreateAIJ(mpiCommGlobal,
		   nRowsRankInterior, nRowsRankCoarse,
		   nGlobalOverallInterior, nRowsOverallCoarse,
196
		   100, PETSC_NULL, 100, PETSC_NULL,
197
		   //	   0, nnzIntCoarse.dnnz, 0, nnzIntCoarse.onnz,
198 199
		   &matIntCoarse);
      MatSetOption(matIntCoarse, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
    }

    // === 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.                                       ===

    int nComponents = mat->getSize();
    for (int i = 0; i < nComponents; i++) {
      for (int j = 0; j < nComponents; j++) {
	if (!(*mat)[i][j])
	  continue;

	traits::col<Matrix>::type col((*mat)[i][j]->getBaseMatrix());
	traits::const_value<Matrix>::type value((*mat)[i][j]->getBaseMatrix());
	
	// Traverse all rows.
	for (cursor_type cursor = begin<row>((*mat)[i][j]->getBaseMatrix()), 
	       cend = end<row>((*mat)[i][j]->getBaseMatrix()); cursor != cend; ++cursor) {

	  bool rowPrimal = isCoarseSpace(feSpaces[i], *cursor);
  
	  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) {

	    bool colPrimal = isCoarseSpace(feSpaces[j], col(*icursor));

	    if (colPrimal) {
	      if (rowPrimal) {
		cols.push_back(col(*icursor));
		values.push_back(value(*icursor));
	      } else {
		colsOther.push_back(col(*icursor));
		valuesOther.push_back(value(*icursor));
	      }
	    } else {
	      if (rowPrimal) {
		colsOther.push_back(col(*icursor));
		valuesOther.push_back(value(*icursor));
	      } else {
		cols.push_back(col(*icursor));
		values.push_back(value(*icursor));
	      }
	    }
	  }  // for each nnz in row


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

	  if (rowPrimal) {
	    int rowIndex = coarseSpaceMap->getMatIndex(i, *cursor);
	    for (unsigned int k = 0; k < cols.size(); k++)
	      cols[k] = coarseSpaceMap->getMatIndex(j, cols[k]);

	    MatSetValues(matCoarseCoarse, 1, &rowIndex, cols.size(),
			 &(cols[0]), &(values[0]), ADD_VALUES);

	    if (colsOther.size()) {
	      if (subdomainLevel == 0) {
279 280 281 282 283
		for (unsigned int k = 0; k < colsOther.size(); k++) {
		  int local = interiorMap->getMatIndex(j, colsOther[k]) - interiorMap->getStartDofs();
		  if (rowIndex == 0 && local == 9297)
		    MSG("FOUND: %d %d %d\n", colsOther[k], j, interiorMap->getMatIndex(j, colsOther[k]));

284
		  colsOther[k] = interiorMap->getMatIndex(j, colsOther[k]);
285
		}
286 287 288 289 290
	      } else {
		for (unsigned int k = 0; k < colsOther.size(); k++)
		  colsOther[k] = 
		    interiorMap->getMatIndex(j, colsOther[k]) + rStartInterior;
	      }
291

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
	      MatSetValues(matCoarseInt, 1, &rowIndex, colsOther.size(),
 			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
	    }
	  } else {
	    int localRowIndex = 
	      (subdomainLevel == 0 ? interiorMap->getLocalMatIndex(i, *cursor) :
	       interiorMap->getMatIndex(i, *cursor));

	    for (unsigned int k = 0; k < cols.size(); k++) {
	      if (subdomainLevel == 0)
		cols[k] = interiorMap->getLocalMatIndex(j, cols[k]);
	      else
		cols[k] = interiorMap->getMatIndex(j, cols[k]);
	    }
	    
  	    MatSetValues(matIntInt, 1, &localRowIndex, cols.size(),
  			 &(cols[0]), &(values[0]), ADD_VALUES);

	    if (colsOther.size()) {
	      int globalRowIndex = interiorMap->getMatIndex(i, *cursor);

	      if (subdomainLevel != 0)
		globalRowIndex += rStartInterior;

	      for (unsigned int k = 0; k < colsOther.size(); k++)
		colsOther[k] = coarseSpaceMap->getMatIndex(j, colsOther[k]);

  	      MatSetValues(matIntCoarse, 1, &globalRowIndex, colsOther.size(),
  			   &(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
	    }
	  }
	} 
      }
    }

    // === Start global assembly procedure. ===

    MatAssemblyBegin(matIntInt, MAT_FINAL_ASSEMBLY);
    MatAssemblyEnd(matIntInt, MAT_FINAL_ASSEMBLY);

    if (coarseSpaceMap) {
      MatAssemblyBegin(matCoarseCoarse, MAT_FINAL_ASSEMBLY);
      MatAssemblyEnd(matCoarseCoarse, MAT_FINAL_ASSEMBLY);
      
      MatAssemblyBegin(matIntCoarse, MAT_FINAL_ASSEMBLY);
      MatAssemblyEnd(matIntCoarse, MAT_FINAL_ASSEMBLY);
      
      MatAssemblyBegin(matCoarseInt, MAT_FINAL_ASSEMBLY);
      MatAssemblyEnd(matCoarseInt, MAT_FINAL_ASSEMBLY);
    }

343 344
    AMDiS::finalize();
    exit(0);
345

346 347
    // === Remove Dirichlet BC DOFs. ===

348
    //    removeDirichletBcDofs(mat);
349

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    // === Create solver for the non primal (thus local) variables. ===

    KSPCreate(mpiCommLocal, &kspInterior);
    KSPSetOperators(kspInterior, matIntInt, matIntInt, SAME_NONZERO_PATTERN);
    KSPSetOptionsPrefix(kspInterior, "interior_");
    KSPSetType(kspInterior, KSPPREONLY);
    KSPGetPC(kspInterior, &pcInterior);
    PCSetType(pcInterior, PCLU);
    if (subdomainLevel == 0)
      PCFactorSetMatSolverPackage(pcInterior, MATSOLVERUMFPACK);
    else
      PCFactorSetMatSolverPackage(pcInterior, MATSOLVERMUMPS);
    KSPSetFromOptions(kspInterior);  
  }


366 367 368
  void PetscSolverGlobalMatrix::fillPetscRhs(SystemVector *vec)
  {
    FUNCNAME("PetscSolverGlobalMatrix::fillPetscRhs()");
Thomas Witkowski's avatar
Thomas Witkowski committed
369

Thomas Witkowski's avatar
Thomas Witkowski committed
370 371 372 373
    VecCreateMPI(mpiCommGlobal, 
		 interiorMap->getRankDofs(), 
		 nGlobalOverallInterior,
		 &rhsInterior);
374

Thomas Witkowski's avatar
Thomas Witkowski committed
375 376 377 378 379 380
    if (coarseSpaceMap) 
      VecCreateMPI(mpiCommGlobal, 
		   coarseSpaceMap->getRankDofs(), 
		   coarseSpaceMap->getOverallDofs(),
		   &rhsCoarseSpace);
    
381
    TEST_EXIT_DBG(vec)("No DOF vector defined!\n");
382
    TEST_EXIT_DBG(interiorMap)("No parallel DOF map defined!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
383
    
384

Thomas Witkowski's avatar
Thomas Witkowski committed
385
    // === Transfer values from DOF vector to the PETSc vector. === 
Thomas Witkowski's avatar
Thomas Witkowski committed
386
    if (coarseSpaceMap) {
Thomas Witkowski's avatar
Thomas Witkowski committed
387 388
      for (int i = 0; i < vec->getSize(); i++)
	setDofVector(rhsInterior, rhsCoarseSpace, vec->getDOFVector(i), i);
Thomas Witkowski's avatar
Thomas Witkowski committed
389 390 391 392
    } else {
      for (int i = 0; i < vec->getSize(); i++)
	setDofVector(rhsInterior, vec->getDOFVector(i), i);
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
393

394 395
    VecAssemblyBegin(rhsInterior);
    VecAssemblyEnd(rhsInterior);
396

Thomas Witkowski's avatar
Thomas Witkowski committed
397 398 399 400 401
    if (coarseSpaceMap) {
      VecAssemblyBegin(rhsCoarseSpace);
      VecAssemblyEnd(rhsCoarseSpace);
    }

402 403 404

    // === Remove Dirichlet BC DOFs. ===
    //    removeDirichletBcDofs(vec);
Thomas Witkowski's avatar
Thomas Witkowski committed
405
 
Thomas Witkowski's avatar
Thomas Witkowski committed
406 407 408
  }


409 410
  void PetscSolverGlobalMatrix::solvePetscMatrix(SystemVector &vec, 
						 AdaptInfo *adaptInfo)
Thomas Witkowski's avatar
Thomas Witkowski committed
411 412 413 414 415 416 417 418 419 420
  {
    FUNCNAME("PetscSolverGlobalMatrix::solvePetscMatrix()");

    int nComponents = vec.getSize();

    // === Set old solution to be initiual guess for PETSc solver. ===
    if (!zeroStartVector) {
      VecSet(petscSolVec, 0.0);
      
      for (int i = 0; i < nComponents; i++)
421
	setDofVector(petscSolVec, vec.getDOFVector(i), i, true);
Thomas Witkowski's avatar
Thomas Witkowski committed
422 423 424 425 426
      
      VecAssemblyBegin(petscSolVec);
      VecAssemblyEnd(petscSolVec);
    }

427

Thomas Witkowski's avatar
Thomas Witkowski committed
428 429
    MatNullSpace matNullspace;
    Vec nullspaceBasis;
430

431 432 433
    if (nullspace.size() > 0 || 
	hasConstantNullspace ||
	constNullspaceComponent.size() > 0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
434
      TEST_EXIT_DBG(nullspace.size() <= 1)("Not yet implemented!\n");
435

436 437 438 439 440 441 442 443 444 445
      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
446 447 448 449 450 451 452
      if (nullspace.size() > 0) {
	VecDuplicate(petscSolVec, &nullspaceBasis);
	for (int i = 0; i < nComponents; i++)
	  setDofVector(nullspaceBasis, nullspace[0]->getDOFVector(i), i, true);
	
	VecAssemblyBegin(nullspaceBasis);
	VecAssemblyEnd(nullspaceBasis);
453 454

	VecNormalize(nullspaceBasis, PETSC_NULL);
Thomas Witkowski's avatar
Thomas Witkowski committed
455 456 457 458 459 460 461 462 463 464 465
	
	MatNullSpaceCreate(mpiCommGlobal, (hasConstantNullspace ? PETSC_TRUE : PETSC_FALSE), 
			   1, &nullspaceBasis, &matNullspace);

	MatMult(matIntInt, nullspaceBasis, petscSolVec);
	PetscReal n;
	VecNorm(petscSolVec, NORM_2, &n);
	MSG("NORM IS: %e\n", n);
      } else {
	MatNullSpaceCreate(mpiCommGlobal, PETSC_TRUE, 0, PETSC_NULL, &matNullspace);
      }
466

467
      MatSetNullSpace(matIntInt, matNullspace);
Thomas Witkowski's avatar
Thomas Witkowski committed
468
      KSPSetNullSpace(kspInterior, matNullspace);
469

Thomas Witkowski's avatar
Thomas Witkowski committed
470
      // === Remove null space, if requested. ===
471

Thomas Witkowski's avatar
Thomas Witkowski committed
472 473 474 475 476 477 478 479
      if (removeRhsNullspace) {
	TEST_EXIT_DBG(coarseSpaceMap == NULL)("Not supported!\n");
	
	MatNullSpaceRemove(matNullspace, rhsInterior, PETSC_NULL);
      }
    } else {
      TEST_EXIT(removeRhsNullspace == false)
	("No nullspace provided that should be removed from rhs!\n");
480 481
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
482

Thomas Witkowski's avatar
Thomas Witkowski committed
483
    // PETSc.
484
    solve(rhsInterior, petscSolVec);
Thomas Witkowski's avatar
Thomas Witkowski committed
485

486 487

    if (nullspace.size() > 0) {
Thomas Witkowski's avatar
Thomas Witkowski committed
488
      MatNullSpaceDestroy(&matNullspace);
489 490 491 492
      VecDestroy(&nullspaceBasis);
    }


Thomas Witkowski's avatar
Thomas Witkowski committed
493 494
    // === Transfere values from PETSc's solution vectors to the DOF vectors. ===
    PetscScalar *vecPointer;
495
    VecGetArray(petscSolVec, &vecPointer);    
Thomas Witkowski's avatar
Thomas Witkowski committed
496

497
    int c = 0;
Thomas Witkowski's avatar
Thomas Witkowski committed
498
    for (int i = 0; i < nComponents; i++) {
499
      DOFVector<double> &dv = *(vec.getDOFVector(i));
500

501
      DofMap& d = (*interiorMap)[dv.getFeSpace()].getMap();
502 503 504
      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
505 506 507
    }

    VecRestoreArray(petscSolVec, &vecPointer);
508 509 510
  }


511 512 513 514
  void PetscSolverGlobalMatrix::solveGlobal(Vec &rhs, Vec &sol)
  {
    FUNCNAME("PetscSolverGlobalMatrix::solveGlobal()");

515 516 517
    double wtime = MPI::Wtime();
    double t0 = 0.0, t1 = 0.0;

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
    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);

537 538 539
    t0 = MPI::Wtime() - wtime;

    wtime = MPI::Wtime();
540
    KSPSolve(kspInterior, tmp, tmp);
541 542 543
    t1 = MPI::Wtime() - wtime;

    wtime = MPI::Wtime();
544 545 546 547 548 549 550 551 552 553 554

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

557
    //    MSG("TIMEING: %.5f %.5f\n", t0, t1);
558 559 560
  }


561 562 563 564
  void PetscSolverGlobalMatrix::destroyMatrixData()
  {
    FUNCNAME("PetscSolverGlobalMatrix::destroyMatrixData()");

565 566
    exitPreconditioner(pcInterior);

567 568
    MatDestroy(&matIntInt);
    KSPDestroy(&kspInterior);
Thomas Witkowski's avatar
Thomas Witkowski committed
569

570 571 572 573 574 575 576
    if (coarseSpaceMap) {
      MatDestroy(&matCoarseCoarse);
      MatDestroy(&matCoarseInt);
      MatDestroy(&matIntCoarse);
    }

    if (petscSolVec != PETSC_NULL) {
Thomas Witkowski's avatar
Thomas Witkowski committed
577
      VecDestroy(&petscSolVec);
578 579
      petscSolVec = PETSC_NULL;
    }
Thomas Witkowski's avatar
Thomas Witkowski committed
580 581 582
  }


583 584 585 586
  void PetscSolverGlobalMatrix::destroyVectorData()
  {
    FUNCNAME("PetscSolverGlobalMatrix::destroyVectorData()");

587
    VecDestroy(&rhsInterior);
588 589 590

    if (coarseSpaceMap)
      VecDestroy(&rhsCoarseSpace);
591 592 593
  }


594 595 596 597 598 599 600 601 602 603
  bool PetscSolverGlobalMatrix::checkMeshChange(Matrix<DOFMatrix*> *mat,
						bool localMatrix)
  {
    FUNCNAME("PetscSolverGlobalMatrix::checkMeshChange()");

    int recvAllValues = 0;
    int sendValue = 
      static_cast<int>(meshDistributor->getLastMeshChangeIndex() != lastMeshNnz);
    mpiCommGlobal.Allreduce(&sendValue, &recvAllValues, 1, MPI_INT, MPI_SUM);

604
    if (!nnzInterior.dnnz || recvAllValues != 0 || alwaysCreateNnzStructure) {
605 606 607 608 609
      vector<const FiniteElemSpace*> feSpaces = getFeSpaces(mat);
      
      interiorMap->setComputeMatIndex(true, !localMatrix);
      interiorMap->update(feSpaces);

610
      nnzInterior.clear();
611

612 613 614 615
      if (coarseSpaceMap) {
	nnzCoarse.clear();
	nnzCoarseInt.clear();
	nnzIntCoarse.clear();
616 617 618 619 620 621 622 623 624 625 626 627
      }

      updateSubdomainData();
      lastMeshNnz = meshDistributor->getLastMeshChangeIndex();

      return true;
    }

    return false;
  }


628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
  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());

      TEST_EXIT(nComponents > 0)("No is block for block %d defined!\n", i);

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


664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
  void PetscSolverGlobalMatrix::initPreconditioner(PC pc)
  {
    FUNCNAME("PetscSolverGlobalMatrix::initPreconditioner()");

    PCSetFromOptions(pc);
    createFieldSplit(pc);
  }

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


679 680
  void PetscSolverGlobalMatrix::setDofMatrix(DOFMatrix* mat,
					     int nRowMat, int nColMat)
Thomas Witkowski's avatar
Thomas Witkowski committed
681 682 683 684 685 686
  {
    FUNCNAME("PetscSolverGlobalMatrix::setDofMatrix()");

    TEST_EXIT(mat)("No DOFMatrix!\n");

    using mtl::tag::row; using mtl::tag::nz; using mtl::begin; using mtl::end;
687
    namespace traits = mtl::traits;
Thomas Witkowski's avatar
Thomas Witkowski committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
    typedef DOFMatrix::base_matrix_type Matrix;

    traits::col<Matrix>::type col(mat->getBaseMatrix());
    traits::const_value<Matrix>::type value(mat->getBaseMatrix());

    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;

703 704 705
    // Get periodic mapping object
    PeriodicMap &perMap = meshDistributor->getPeriodicMap();

Thomas Witkowski's avatar
Thomas Witkowski committed
706 707 708 709 710 711
    const FiniteElemSpace *rowFe = mat->getRowFeSpace();
    const FiniteElemSpace *colFe = mat->getColFeSpace();
    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
712 713 714 715 716
    // === to the PETSc matrix.                                               ===

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

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

Thomas Witkowski's avatar
Thomas Witkowski committed
722 723 724
      if (!periodicRow) {
	// === Row DOF index is not periodic. ===

725
	// Get PETSc's mat row index.
726
	int rowIndex = interiorMap->getMatIndex(nRowMat, globalRowDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
727 728 729 730 731 732 733 734

	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
735
	  int globalColDof = colMap[col(*icursor)].global;
Thomas Witkowski's avatar
Thomas Witkowski committed
736
	  // Test if the current col dof is a periodic dof.
737
	  bool periodicCol = perMap.isPeriodic(colFe, globalColDof);
738
	  // Get PETSc's mat col index.
739
	  int colIndex = interiorMap->getMatIndex(nColMat, globalColDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
740 741 742 743 744 745 746

	  // 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
747 748
 	    cols.push_back(colIndex);
 	    values.push_back(value(*icursor));
Thomas Witkowski's avatar
Thomas Witkowski committed
749 750 751 752 753
	  } else {
	    // === Row index is not periodic, but column index is. ===

	    // Create set of all periodic associations of the column index.
	    std::set<int> perAsc;
754
	    std::set<int>& perColAsc = perMap.getAssociations(colFe, globalColDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
755 756
	    for (std::set<int>::iterator it = perColAsc.begin(); 
		 it != perColAsc.end(); ++it)
757
	      if (meshDistributor->getElementObjectDb().isValidPeriodicType(*it))
Thomas Witkowski's avatar
Thomas Witkowski committed
758 759 760 761 762 763 764 765 766 767 768 769 770 771
		perAsc.insert(*it);
    
	    // 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;

	    // First, add the original matrix index.
	    newCols.push_back(globalColDof);
772

Thomas Witkowski's avatar
Thomas Witkowski committed
773 774 775 776 777 778
	    // And add all periodic matrix indices.
	    for (std::set<int>::iterator it = perAsc.begin(); 
		 it != perAsc.end(); ++it) {
	      int nCols = static_cast<int>(newCols.size());

	      for (int i = 0; i < nCols; i++) {
779
 		TEST_EXIT_DBG(perMap.isPeriodic(colFe, *it, newCols[i]))
Thomas Witkowski's avatar
Thomas Witkowski committed
780 781 782
 		  ("Wrong periodic DOF associations at boundary %d with DOF %d!\n",
		   *it, newCols[i]);

783
		newCols.push_back(perMap.map(colFe, *it, newCols[i]));
Thomas Witkowski's avatar
Thomas Witkowski committed
784 785 786 787
	      }
	    }

	    for (unsigned int i = 0; i < newCols.size(); i++) {
788
	      cols.push_back(interiorMap->getMatIndex(nColMat, newCols[i]));
Thomas Witkowski's avatar
Thomas Witkowski committed
789 790 791 792 793
	      values.push_back(scaledValue);	      
	    }
	  }
	}

Thomas Witkowski's avatar
Thomas Witkowski committed
794 795
  	MatSetValues(matIntInt, 1, &rowIndex, cols.size(), 
  		     &(cols[0]), &(values[0]), ADD_VALUES);	
Thomas Witkowski's avatar
Thomas Witkowski committed
796 797 798 799 800 801 802 803 804 805 806 807 808 809
      } 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.
810
	  int globalColDof = (*interiorMap)[colFe][col(*icursor)].global;
Thomas Witkowski's avatar
Thomas Witkowski committed
811 812 813 814 815 816 817 818 819 820

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

821 822
	  if (perMap.isPeriodic(colFe, globalColDof)) {
	    std::set<int>& perColAsc = perMap.getAssociations(colFe, globalColDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
823 824
	    for (std::set<int>::iterator it = perColAsc.begin(); 
		 it != perColAsc.end(); ++it)
825
	      if (meshDistributor->getElementObjectDb().isValidPeriodicType(*it))
Thomas Witkowski's avatar
Thomas Witkowski committed
826 827 828
		perAsc.insert(*it);
	  }

829
	  std::set<int>& perRowAsc = perMap.getAssociations(rowFe, globalRowDof);
Thomas Witkowski's avatar
Thomas Witkowski committed
830 831
	  for (std::set<int>::iterator it = perRowAsc.begin(); 
	       it != perRowAsc.end(); ++it)
832
	    if (meshDistributor->getElementObjectDb().isValidPeriodicType(*it))
Thomas Witkowski's avatar
Thomas Witkowski committed
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
	      perAsc.insert(*it);

	  // 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;
	  
	  // First, add the original entry.
	  entry.push_back(make_pair(globalRowDof, globalColDof));

848 849
	  // Then, traverse the periodic associations of the row and column
	  // indices and create the corresponding entries.
Thomas Witkowski's avatar
Thomas Witkowski committed
850 851 852 853
	  for (std::set<int>::iterator it = perAsc.begin(); it != perAsc.end(); ++it) {
	    int nEntry = static_cast<int>(entry.size());
	    for (int i = 0; i < nEntry; i++) {
	      int perRowDof = 0;
854

855 856
	      if (perMap.isPeriodic(rowFe, *it, entry[i].first))
		perRowDof = perMap.map(rowFe, *it, entry[i].first);
Thomas Witkowski's avatar
Thomas Witkowski committed
857 858 859 860
	      else
		perRowDof = entry[i].first;

	      int perColDof;
861 862
	      if (perMap.isPeriodic(colFe, *it, entry[i].second))
		perColDof = perMap.map(colFe, *it, entry[i].second);
Thomas Witkowski's avatar
Thomas Witkowski committed
863 864 865 866 867 868 869 870 871 872
	      else
		perColDof = entry[i].second;	      	      
	      
	      entry.push_back(make_pair(perRowDof, perColDof));
	    }
	  }


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

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

877 878
	    colsMap[rowIdx].push_back(colIdx);
	    valsMap[rowIdx].push_back(scaledValue);
Thomas Witkowski's avatar
Thomas Witkowski committed
879 880 881 882 883 884 885 886 887 888 889 890
	  }
	}


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

892
	  MatSetValues(matIntInt, 1, &rowIndex, rowIt->second.size(),
Thomas Witkowski's avatar
Thomas Witkowski committed
893 894 895 896 897 898 899
		       &(rowIt->second[0]), &(valsMap[rowIt->first][0]), ADD_VALUES);
	}
      }
    }
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
900 901
  void PetscSolverGlobalMatrix::setDofVector(Vec vecInterior, 
					     Vec vecCoarse,
902
					     DOFVector<double>* vec, 
903
					     int nRowVec, 
904
					     bool rankOnly)
Thomas Witkowski's avatar
Thomas Witkowski committed
905 906 907
  {
    FUNCNAME("PetscSolverGlobalMatrix::setDofVector()");

908
    const FiniteElemSpace *feSpace = vec->getFeSpace();
909
    PeriodicMap &perMap = meshDistributor->getPeriodicMap();
910

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

915
      if (rankOnly && !(*interiorMap)[feSpace].isRankDof(dofIt.getDOFIndex()))
Thomas Witkowski's avatar
Thomas Witkowski committed
916 917
	continue;

918
      if (isCoarseSpace(feSpace, dofIt.getDOFIndex())) {
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
	TEST_EXIT_DBG(vecCoarse != PETSC_NULL)("Should not happen!\n");

	int index = coarseSpaceMap->getMatIndex(nRowVec, dofIt.getDOFIndex());
	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;
936

937
	if (perMap.isPeriodic(feSpace, globalRowDof)) {
Thomas Witkowski's avatar
Thomas Witkowski committed
938 939 940
	  std::set<int>& perAsc = perMap.getAssociations(feSpace, globalRowDof);
	  double value = *dofIt / (perAsc.size() + 1.0);
	  VecSetValue(vecInterior, index, value, ADD_VALUES);
941

Thomas Witkowski's avatar
Thomas Witkowski committed
942 943 944 945
	  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);
946

Thomas Witkowski's avatar
Thomas Witkowski committed
947
	    VecSetValue(vecInterior, mappedIndex, value, ADD_VALUES);
948 949 950 951
	  }	  
	} else {	  
	  // The DOF index is not periodic.
	  
Thomas Witkowski's avatar
Thomas Witkowski committed
952 953
	  VecSetValue(vecInterior, index, *dofIt, ADD_VALUES);
	}
Thomas Witkowski's avatar
Thomas Witkowski committed
954 955 956 957 958
      }
    }
  }


959 960 961 962
  void PetscSolverGlobalMatrix::removeDirichletBcDofs(Matrix<DOFMatrix*> *mat)
  {
    FUNCNAME("PetscSolverGlobalMatrix::removeDirichletBcDofs()");

Thomas Witkowski's avatar
Thomas Witkowski committed
963
#if 0
964 965 966 967
    vector<int> dofsInterior, dofsCoarse;

    int nComponents = mat->getNumRows();
    for (int i = 0; i < nComponents; i++) {
Thomas Witkowski's avatar
Thomas Witkowski committed
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
      for (int j = 0; j < nComponents; j++) {
	if ((*mat)[i][j]) {
	  const FiniteElemSpace *feSpace = (*mat)[i][j]->getRowFeSpace();
	    
	  std::set<DegreeOfFreedom> &dirichletDofs = *((*mat)[i][j]->getApplyDBCs());

	  MSG("DIRICHLET DOFS: %d %d -> %d\n", i, j, dirichletDofs.size());
	  
	  for (std::set<DegreeOfFreedom>::iterator it = dirichletDofs.begin();
	       it != dirichletDofs.end(); ++it) {
	    if (isCoarseSpace(feSpace, *it)) {
	      if ((*coarseSpaceMap)[feSpace].isRankDof(*it)) {
		int globalDof = (*coarseSpaceMap)[feSpace][*it].global;
		dofsCoarse.push_back(coarseSpaceMap->getMatIndex(i, globalDof));
	      }
	    } else {
	      if ((*interiorMap)[feSpace].isRankDof(*it)) {
		int globalDof = (*interiorMap)[feSpace][*it].global;
		dofsInterior.push_back(interiorMap->getMatIndex(i, globalDof));
	      }
988
	    }
989
	  }
Thomas Witkowski's avatar
Thomas Witkowski committed
990 991
	} else {
	  MSG("NO MAT DIAG in %d\n", i);
992 993 994 995 996 997 998 999 1000 1001
	}
      }
    }

    MatZeroRows(matIntInt, dofsInterior.size(), &(dofsInterior[0]), 1.0, 
		PETSC_NULL, PETSC_NULL);

    if (coarseSpaceMap != NULL)
      MatZeroRows(matCoarseCoarse, dofsCoarse.size(), &(dofsCoarse[0]), 1.0, 
		  PETSC_NULL, PETSC_NULL);
Thomas Witkowski's avatar
Thomas Witkowski committed
1002
#endif
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
  }


  void PetscSolverGlobalMatrix::removeDirichletBcDofs(SystemVector *vec)
  {
    FUNCNAME("PetscSolverGlobalMatrix::removeDirichletBcDofs()");

    int nComponents = vec->getSize();
    for (int i = 0; i < nComponents; i++) {
      const FiniteElemSpace *feSpace = vec->getDOFVector(i)->getFeSpace();

      map<DegreeOfFreedom, double> &dirichletValues = 
	vec->getDOFVector(i)->getDirichletValues();

      for (map<DegreeOfFreedom, double>::iterator it = dirichletValues.begin();
	   it != dirichletValues.end(); ++it) {
	if (isCoarseSpace(feSpace, it->first)) {
1020 1021 1022
	  if ((*coarseSpaceMap)[feSpace].isRankDof(it->first)) {
	    int globalDof = (*coarseSpaceMap)[feSpace][it->first].global;
	    VecSetValue(rhsCoarseSpace, coarseSpaceMap->getMatIndex(i, globalDof), 
1023
			it->second, INSERT_VALUES);
1024
	  }
1025 1026
	} else {
	  if ((*interiorMap)[feSpace].isRankDof(it->first)) {
1027 1028
	    int globalDof = (*interiorMap)[feSpace][it->first].global;
	    VecSetValue(rhsInterior, interiorMap->getMatIndex(i, globalDof),
1029 1030 1031 1032 1033
			it->second, INSERT_VALUES);	    
	  }
	}
      }
    }
1034 1035 1036 1037 1038 1039 1040 1041

    VecAssemblyBegin(rhsInterior);
    VecAssemblyEnd(rhsInterior);

    if (coarseSpaceMap) {
      VecAssemblyBegin(rhsCoarseSpace);
      VecAssemblyEnd(rhsCoarseSpace);
    }
1042 1043 1044
  }


Thomas Witkowski's avatar
Thomas Witkowski committed
1045 1046 1047 1048
  void PetscSolverGlobalMatrix::createPetscNnzStructure(Matrix<DOFMatrix*> *mat)
  {
    FUNCNAME("PetscSolverGlobalMatrix::createPetscNnzStructure()");

1049
    vector<const FiniteElemSpace*> feSpaces = getFeSpaces(mat);
1050 1051
    int nRankRows = interiorMap->getRankDofs();
    int rankStartIndex = interiorMap->getStartDofs();
1052

1053
    nnzInterior.create(nRankRows, nRankRows);
Thomas Witkowski's avatar
Thomas Witkowski committed
1054 1055 1056 1057 1058 1059 1060

    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 vector<pair<int, int> > MatrixNnzEntry;
    typedef map<int, DofContainer> RankToDofContainer;

1061 1062 1063 1064
    // Stores to each rank a list of nnz entries (i.e. pairs of row and column
    // index) that this rank will send to. These nnz entries will be assembled
    // on this rank, but because the row DOFs are not DOFs of this rank they 
    // will be send to the owner of the row DOFs.
Thomas Witkowski's avatar
Thomas Witkowski committed
1065 1066 1067 1068
    map<int, MatrixNnzEntry> sendMatrixEntry;

    // Maps to each DOF that must be send to another rank the rank number of the
    // receiving rank.
1069
    map<pair<DegreeOfFreedom, int>, int> sendDofToRank;
Thomas Witkowski's avatar
Thomas Witkowski committed
1070

1071

1072 1073 1074
    // First, create for all ranks, to which we send data to, MatrixNnzEntry 
    // object with 0 entries.
    for (unsigned int i = 0; i < feSpaces.size(); i++) {
1075
      for (DofComm::Iterator it(meshDistributor->getDofComm().getRecvDofs(), feSpaces[i]);
1076 1077 1078 1079 1080 1081
	   !it.end(); it.nextRank()) {
	sendMatrixEntry[it.getRank()].resize(0);
	
	for (; !it.endDofIter(); it.nextDof())
	  sendDofToRank[make_pair(it.getDofIndex(), i)] = it.getRank();
      }
Thomas Witkowski's avatar
Thomas Witkowski committed
1082 1083
    }

1084
    // Create list of ranks from which we receive data from.
Thomas Witkowski's avatar
Thomas Witkowski committed
1085
    std::set<int> recvFromRank;
1086
    for (unsigned int i = 0; i < feSpaces.size(); i++) 
1087
      for (DofComm::Iterator it(meshDistributor->getDofComm().getSendDofs(), feSpaces[i]);
1088 1089 1090 1091 1092
	   !it.end(); it.nextRank())
	recvFromRank.insert(it.getRank());


    // === Traverse matrices to create nnz data. ===
Thomas Witkowski's avatar
Thomas Witkowski committed
1093

1094
    int nComponents = mat->getNumRows();
Thomas Witkowski's avatar
Thomas Witkowski committed
1095 1096 1097 1098 1099
    for (int i = 0; i < nComponents; i++) {
      for (int j = 0; j < nComponents; j++) {
 	if (!(*mat)[i][j])
	  continue;

1100 1101 1102 1103 1104
	TEST_EXIT_DBG((*mat)[i][j]->getRowFeSpace() == feSpaces[i])
	  ("Should not happen!\n");
	TEST_EXIT_DBG((*mat)[i][j]->getColFeSpace() == feSpaces[j])
	  ("Should not happen!\n");

Thomas Witkowski's avatar
Thomas Witkowski committed
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
	Matrix bmat = (*mat)[i][j]->getBaseMatrix();

	traits::col<Matrix>::type col(bmat);
	traits::const_value<Matrix>::type value(bmat);
	  
	typedef traits::range_generator<row, Matrix>::type cursor_type;
	typedef traits::range_generator<nz, cursor_type>::type icursor_type;
	
	for (cursor_type cursor = begin<row>(bmat), 
	       cend = end<row>(bmat); cursor != cend; ++cursor) {
1115
	  int globalRowDof = (*interiorMap)[feSpaces[i]][*cursor].global;
1116

1117
	  // The corresponding global matrix row index of the current row DOF.
1118 1119
	  int petscRowIdx = interiorMap->getMatIndex(i, globalRowDof);
	  if ((*interiorMap)[feSpaces[i]].isRankDof(*cursor)) {