From 0e6691d89297aba6b7cc861987ba8b08731c6c86 Mon Sep 17 00:00:00 2001 From: Thomas Witkowski <thomas.witkowski@gmx.de> Date: Wed, 4 May 2011 11:20:12 +0000 Subject: [PATCH] FETI-DP Dirichlet preconditioner. --- AMDiS/src/parallel/PetscSolverFeti.cc | 262 ++++++++++++++++++++++++-- AMDiS/src/parallel/PetscSolverFeti.h | 35 ++++ 2 files changed, 286 insertions(+), 11 deletions(-) diff --git a/AMDiS/src/parallel/PetscSolverFeti.cc b/AMDiS/src/parallel/PetscSolverFeti.cc index e7241aaf..8aaf8d05 100644 --- a/AMDiS/src/parallel/PetscSolverFeti.cc +++ b/AMDiS/src/parallel/PetscSolverFeti.cc @@ -70,6 +70,62 @@ namespace AMDiS { } + // y = PC * x + PetscErrorCode petscApplyFetiPrecon(PC pc, Vec x, Vec y) + { + void *ctx; + PCShellGetContext(pc, &ctx); + PetscFetiPreconData* data = static_cast<PetscFetiPreconData*>(ctx); + + MatMultTranspose(*(data->mat_lagrange_scaled), x, data->tmp_vec_b); + + int sizeB; + int sizeBound; + VecGetLocalSize(data->tmp_vec_b, &sizeB); + VecGetLocalSize(data->tmp_vec_bound0, &sizeBound); + + PetscScalar *local_b; + VecGetArray(data->tmp_vec_b, &local_b); + + PetscScalar *local_bound; + VecGetArray(data->tmp_vec_bound0, &local_bound); + + for (int i = sizeB - sizeBound, j = 0; i < sizeB; i++, j++) + local_bound[j] = local_b[i]; + + VecRestoreArray(data->tmp_vec_b, &local_b); + VecRestoreArray(data->tmp_vec_bound0, &local_bound); + + + + MatMult(*(data->mat_bound_bound), data->tmp_vec_bound0, data->tmp_vec_bound1); + + MatMult(*(data->mat_interior_bound), data->tmp_vec_bound0, data->tmp_vec_interior); + KSPSolve(*(data->ksp_interior), data->tmp_vec_interior, data->tmp_vec_interior); + MatMult(*(data->mat_bound_interior), data->tmp_vec_interior, data->tmp_vec_bound0); + + VecAXPBY(data->tmp_vec_bound0, 1.0, -1.0, data->tmp_vec_bound1); + + + + VecGetArray(data->tmp_vec_b, &local_b); + VecGetArray(data->tmp_vec_bound0, &local_bound); + + for (int i = sizeB - sizeBound, j = 0; i < sizeB; i++, j++) + local_b[i] = local_bound[j]; + + VecRestoreArray(data->tmp_vec_b, &local_b); + VecRestoreArray(data->tmp_vec_bound0, &local_bound); + + + + + MatMult(*(data->mat_lagrange_scaled), data->tmp_vec_b, y); + + return 0; + } + + void PetscSolverFeti::updateDofData() { FUNCNAME("PetscSolverFeti::updateDofData()"); @@ -379,14 +435,15 @@ namespace AMDiS { // === Get correct index for all interior nodes. === - int nInterior = 0; + nLocalInterior = 0; for (DofMapping::iterator it = globalIndexB.begin(); it != globalIndexB.end(); ++it) { - it->second = nInterior + rStartB; - nInterior++; + it->second = nLocalInterior + rStartB; + nLocalInterior++; } + nLocalBound = duals.size(); - TEST_EXIT_DBG(nInterior + primals.size() + duals.size() == + TEST_EXIT_DBG(nLocalInterior + primals.size() + duals.size() == static_cast<unsigned int>(admin->getUsedDofs())) ("Should not happen!\n"); @@ -505,6 +562,8 @@ namespace AMDiS { { FUNCNAME("PetscSolverFeti::createFetiKsp()"); + // === Create FETI-DP solver object. === + petscFetiData.mat_primal_primal = &mat_primal_primal; petscFetiData.mat_primal_b = &mat_primal_b; petscFetiData.mat_b_primal = &mat_b_primal; @@ -529,6 +588,38 @@ namespace AMDiS { KSPSetOperators(ksp_feti, mat_feti, mat_feti, SAME_NONZERO_PATTERN); KSPSetOptionsPrefix(ksp_feti, "solver_feti_"); KSPSetFromOptions(ksp_feti); + + + // === Create FETI-DP Dirichlet preconditioner object. === + + KSPCreate(PETSC_COMM_SELF, &ksp_interior); + KSPSetOperators(ksp_interior, mat_interior_interior, mat_interior_interior, SAME_NONZERO_PATTERN); + KSPSetOptionsPrefix(ksp_interior, "solver_interior_"); + KSPSetFromOptions(ksp_interior); + + + MatDuplicate(mat_lagrange, MAT_COPY_VALUES, &mat_lagrange_scaled); + MatScale(mat_lagrange_scaled, 0.5); + + petscFetiPreconData.mat_lagrange_scaled = &mat_lagrange_scaled; + petscFetiPreconData.mat_interior_interior = &mat_interior_interior; + petscFetiPreconData.mat_bound_bound = &mat_bound_bound; + petscFetiPreconData.mat_interior_bound = &mat_interior_bound; + petscFetiPreconData.mat_bound_interior = &mat_bound_interior; + petscFetiPreconData.ksp_interior = &ksp_interior; + petscFetiPreconData.nInterior = nRankB - duals.size(); + + VecDuplicate(f_b, &(petscFetiPreconData.tmp_vec_b)); + + MatGetVecs(mat_bound_bound, PETSC_NULL, &(petscFetiPreconData.tmp_vec_bound0)); + MatGetVecs(mat_bound_bound, PETSC_NULL, &(petscFetiPreconData.tmp_vec_bound1)); + MatGetVecs(mat_interior_interior, PETSC_NULL, &(petscFetiPreconData.tmp_vec_interior)); + + + KSPGetPC(ksp_feti, &precon_feti); + PCSetType(precon_feti, PCSHELL); + PCShellSetContext(precon_feti, static_cast<void*>(&petscFetiPreconData)); + PCShellSetApply(precon_feti, petscApplyFetiPrecon); } @@ -536,6 +627,8 @@ namespace AMDiS { { FUNCNAME("PetscSolverFeti::destroyFetiKsp()"); + // === Destroy FETI-DP solver object. === + petscFetiData.mat_primal_primal = PETSC_NULL; petscFetiData.mat_primal_b = PETSC_NULL; petscFetiData.mat_b_primal = PETSC_NULL; @@ -549,6 +642,24 @@ namespace AMDiS { MatDestroy(mat_feti); KSPDestroy(ksp_feti); + + + // === Destroy FETI-DP Dirichlet preconditioner object. === + + KSPDestroy(ksp_interior); + + petscFetiPreconData.mat_lagrange_scaled = NULL; + petscFetiPreconData.mat_interior_interior = NULL; + petscFetiPreconData.mat_bound_bound = NULL; + petscFetiPreconData.mat_interior_bound = NULL; + petscFetiPreconData.mat_bound_interior = NULL; + petscFetiPreconData.ksp_interior = NULL; + + VecDestroy(petscFetiPreconData.tmp_vec_b); + VecDestroy(petscFetiPreconData.tmp_vec_bound0); + VecDestroy(petscFetiPreconData.tmp_vec_bound1); + VecDestroy(petscFetiPreconData.tmp_vec_interior); + MatDestroy(mat_lagrange_scaled); } @@ -658,6 +769,8 @@ namespace AMDiS { int nRowsOverallB = nOverallB * nComponents; int nRowsRankPrimal = nRankPrimals * nComponents; int nRowsOverallPrimal = nOverallPrimals * nComponents; + int nRowsInterior = nLocalInterior * nComponents; + int nRowsBound = nLocalBound * nComponents; MatCreateMPIAIJ(PETSC_COMM_WORLD, nRowsRankB, nRowsRankB, nRowsOverallB, nRowsOverallB, @@ -678,6 +791,25 @@ namespace AMDiS { nRowsOverallPrimal, nRowsOverallB, 100, PETSC_NULL, 100, PETSC_NULL, &mat_primal_b); + + // === Create matrices for Dirichlet FETI-DP preconditioner. === + + MatCreateSeqAIJ(PETSC_COMM_SELF, + nRowsInterior, nRowsInterior, 100, PETSC_NULL, + &mat_interior_interior); + + MatCreateSeqAIJ(PETSC_COMM_SELF, + nRowsBound, nRowsBound, 100, PETSC_NULL, + &mat_bound_bound); + + MatCreateSeqAIJ(PETSC_COMM_SELF, + nRowsInterior, nRowsBound, 100, PETSC_NULL, + &mat_interior_bound); + + MatCreateSeqAIJ(PETSC_COMM_SELF, + nRowsBound, nRowsInterior, 100, PETSC_NULL, + &mat_bound_interior); + // === Prepare traverse of sequentially created matrices. === @@ -695,6 +827,13 @@ namespace AMDiS { values.reserve(300); valuesOther.reserve(300); + vector<int> colsLocal, colsLocalOther; + vector<double> valuesLocal, valuesLocalOther; + colsLocal.reserve(300); + colsLocalOther.reserve(300); + valuesLocal.reserve(300); + valuesLocalOther.reserve(300); + // === Traverse all sequentially created matrices and add the values to === // === the global PETSc matrices. === @@ -710,19 +849,27 @@ namespace AMDiS { // 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 = primals.count(*cursor) != 0; - + cols.clear(); - values.clear(); - colsOther.clear(); + values.clear(); valuesOther.clear(); + + colsLocal.clear(); + colsLocalOther.clear(); + valuesLocal.clear(); + valuesLocalOther.clear(); + // Traverse all columns. for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); icursor != icend; ++icursor) { - if (primals.count(col(*icursor)) != 0) { + bool colPrimal = primals.count(col(*icursor)) != 0; + + if (colPrimal) { // Column is a primal variable. TEST_EXIT_DBG(globalPrimalIndex.count(col(*icursor))) @@ -753,6 +900,47 @@ namespace AMDiS { values.push_back(value(*icursor)); } } + + + + // === For preconditioner === + + if (!rowPrimal && !colPrimal) { + int rowIndex = globalIndexB[*cursor] - rStartB; + int colIndex = globalIndexB[col(*icursor)] - rStartB; + + if (rowIndex < nLocalInterior) { + if (colIndex < nLocalInterior) { + int colIndex2 = + (globalIndexB[col(*icursor)] - rStartB) * nComponents + j; + + colsLocal.push_back(colIndex2); + valuesLocal.push_back(value(*icursor)); + } else { + int colIndex2 = + (globalIndexB[col(*icursor)] - rStartB - nLocalInterior) * nComponents + j; + + colsLocalOther.push_back(colIndex2); + valuesLocalOther.push_back(value(*icursor)); + } + } else { + if (colIndex < nLocalInterior) { + int colIndex2 = + (globalIndexB[col(*icursor)] - rStartB) * nComponents + j; + + colsLocalOther.push_back(colIndex2); + valuesLocalOther.push_back(value(*icursor)); + } else { + int colIndex2 = + (globalIndexB[col(*icursor)] - rStartB - nLocalInterior) * nComponents + j; + + colsLocal.push_back(colIndex2); + valuesLocal.push_back(value(*icursor)); + } + } + } + + } if (rowPrimal) { @@ -778,6 +966,37 @@ namespace AMDiS { MatSetValues(mat_b_primal, 1, &rowIndex, colsOther.size(), &(colsOther[0]), &(valuesOther[0]), ADD_VALUES); } + + // === For preconditioner === + + if (!rowPrimal) { + int rowIndex = globalIndexB[*cursor] - rStartB; + + if (rowIndex < nLocalInterior) { + int rowIndex2 = + (globalIndexB[*cursor] - rStartB) * nComponents + i; + + MatSetValues(mat_interior_interior, 1, &rowIndex2, colsLocal.size(), + &(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES); + + if (colsLocalOther.size()) + MatSetValues(mat_interior_bound, 1, &rowIndex2, colsLocalOther.size(), + &(colsLocalOther[0]), &(valuesLocalOther[0]), INSERT_VALUES); + } else { + int rowIndex2 = + (globalIndexB[*cursor] - rStartB - nLocalInterior) * nComponents + i; + + MatSetValues(mat_bound_bound, 1, &rowIndex2, colsLocal.size(), + &(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES); + + if (colsLocalOther.size()) + MatSetValues(mat_bound_interior, 1, &rowIndex2, colsLocalOther.size(), + &(colsLocalOther[0]), &(valuesLocalOther[0]), INSERT_VALUES); + + } + } + + } } } @@ -798,6 +1017,19 @@ namespace AMDiS { MatAssemblyEnd(mat_primal_b, MAT_FINAL_ASSEMBLY); + MatAssemblyBegin(mat_interior_interior, MAT_FINAL_ASSEMBLY); + MatAssemblyEnd(mat_interior_interior, MAT_FINAL_ASSEMBLY); + + MatAssemblyBegin(mat_bound_bound, MAT_FINAL_ASSEMBLY); + MatAssemblyEnd(mat_bound_bound, MAT_FINAL_ASSEMBLY); + + MatAssemblyBegin(mat_interior_bound, MAT_FINAL_ASSEMBLY); + MatAssemblyEnd(mat_interior_bound, MAT_FINAL_ASSEMBLY); + + MatAssemblyBegin(mat_bound_interior, MAT_FINAL_ASSEMBLY); + MatAssemblyEnd(mat_bound_interior, MAT_FINAL_ASSEMBLY); + + // === Create and fill PETSc's right hand side vectors. === VecCreate(PETSC_COMM_WORLD, &f_b); @@ -1100,7 +1332,15 @@ namespace AMDiS { destroySchurPrimalKsp(); - destroyFetiKsp(); + destroyFetiKsp(); + + + // === Destroy preconditioner data structures. === + + MatDestroy(mat_interior_interior); + MatDestroy(mat_bound_bound); + MatDestroy(mat_interior_bound); + MatDestroy(mat_bound_interior); } @@ -1117,9 +1357,9 @@ namespace AMDiS { solveFetiMatrix(vec); } else { solveReducedFetiMatrix(vec); - } - + } } + #endif } diff --git a/AMDiS/src/parallel/PetscSolverFeti.h b/AMDiS/src/parallel/PetscSolverFeti.h index 5f6e96ff..d63f0031 100644 --- a/AMDiS/src/parallel/PetscSolverFeti.h +++ b/AMDiS/src/parallel/PetscSolverFeti.h @@ -87,6 +87,26 @@ namespace AMDiS { }; + struct PetscFetiPreconData { + /// Matrix of scaled Lagrange variables. + Mat *mat_lagrange_scaled; + + Mat *mat_interior_interior, *mat_bound_bound, *mat_interior_bound, *mat_bound_interior; + + /// Pointer to the solver for \ref PetscSolverFeti::mat_bb. + KSP *ksp_interior; + + /// Temporal vector on the B variables. + Vec tmp_vec_b; + + Vec tmp_vec_bound0, tmp_vec_bound1; + + Vec tmp_vec_interior; + + + int nInterior; + }; + /** \brief * FETI-DP implementation based on PETSc. @@ -267,6 +287,21 @@ namespace AMDiS { /// Data for MatMult operation in matrix \ref mat_feti PetscFetiData petscFetiData; + + + Mat mat_lagrange_scaled; + + PC precon_feti; + + PetscFetiPreconData petscFetiPreconData; + + Mat mat_interior_interior, mat_bound_bound, mat_interior_bound, mat_bound_interior; + + KSP ksp_interior; + + int nLocalInterior; + + int nLocalBound; }; #endif -- GitLab