PCBlockDiagonal.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include <iostream>
00030 
00031 #include "PetscVecTools.hpp" // Includes Ublas so must come first
00032 #include "PCBlockDiagonal.hpp"
00033 #include "Exception.hpp"
00034 
00035 PCBlockDiagonal::PCBlockDiagonal(KSP& rKspObject)
00036 {
00037 #ifdef TRACE_KSP
00038     mPCContext.mScatterTime = 0.0;
00039     mPCContext.mA1PreconditionerTime = 0.0;;
00040     mPCContext.mA2PreconditionerTime = 0.0;;
00041     mPCContext.mGatherTime = 0.0;;
00042 #endif
00043 
00044     PCBlockDiagonalCreate(rKspObject);
00045     PCBlockDiagonalSetUp();
00046 }
00047 
00048 PCBlockDiagonal::~PCBlockDiagonal()
00049 {
00050 #ifdef TRACE_KSP
00051     if (PetscTools::AmMaster())
00052     {
00053         std::cout << " -- Block diagonal preconditioner profile information: " << std::endl;
00054         std::cout << "\t mScatterTime: " << mPCContext.mScatterTime << std::endl;
00055         std::cout << "\t mA1PreconditionerTime: " << mPCContext.mA1PreconditionerTime << std::endl;
00056         std::cout << "\t mA2PreconditionerTime: " << mPCContext.mA2PreconditionerTime << std::endl;
00057         std::cout << "\t mGatherTime: " << mPCContext.mGatherTime << std::endl;
00058     }
00059 #endif
00060 
00061     MatDestroy(mPCContext.A11_matrix_subblock);
00062     MatDestroy(mPCContext.A22_matrix_subblock);
00063 
00064     PCDestroy(mPCContext.PC_amg_A11);
00065     PCDestroy(mPCContext.PC_amg_A22);
00066 
00067     VecDestroy(mPCContext.x1_subvector);
00068     VecDestroy(mPCContext.y1_subvector);
00069 
00070     VecDestroy(mPCContext.x2_subvector);
00071     VecDestroy(mPCContext.y2_subvector);
00072 
00073     VecScatterDestroy(mPCContext.A11_scatter_ctx);
00074     VecScatterDestroy(mPCContext.A22_scatter_ctx);
00075 }
00076 
00077 void PCBlockDiagonal::PCBlockDiagonalCreate(KSP& rKspObject)
00078 {
00079     KSPGetPC(rKspObject, &mPetscPCObject);
00080 
00081     Mat system_matrix, dummy;
00082     MatStructure flag;
00083     KSPGetOperators(rKspObject, &system_matrix, &dummy, &flag);
00084 
00085     PetscInt num_rows, num_columns;
00086     MatGetSize(system_matrix, &num_rows, &num_columns);
00087     assert(num_rows==num_columns);
00088 
00089     PetscInt num_local_rows, num_local_columns;
00090     MatGetLocalSize(system_matrix, &num_local_rows, &num_local_columns);
00091 
00092     // Odd number of rows: impossible in Bidomain.
00093     // Odd number of local rows: impossible if V_m and phi_e for each node are stored in the same processor.
00094     if ((num_rows%2 != 0) || (num_local_rows%2 != 0))
00095     {
00096         TERMINATE("Wrong matrix parallel layout detected in PCLDUFactorisation.");
00097     }
00098 
00099     // Allocate memory
00100     unsigned subvector_num_rows = num_rows/2;
00101     unsigned subvector_local_rows = num_local_rows/2;
00102     mPCContext.x1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00103     mPCContext.x2_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00104     mPCContext.y1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00105     mPCContext.y2_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00106 
00107     // Create scatter contexts
00108     {
00109         // Needed by SetupInterleavedVectorScatterGather in order to find out parallel layout.
00110         Vec dummy_vec = PetscTools::CreateVec(num_rows, num_local_rows);
00111 
00112         PetscVecTools::SetupInterleavedVectorScatterGather(dummy_vec, mPCContext.A11_scatter_ctx, mPCContext.A22_scatter_ctx);
00113 
00114         VecDestroy(dummy_vec);
00115     }
00116 
00117     // Get matrix sublock A11
00118     {
00119         // Work out local row range for subblock A11 (same as x1 or y1)
00120         PetscInt low, high, global_size;
00121         VecGetOwnershipRange(mPCContext.x1_subvector, &low, &high);
00122         VecGetSize(mPCContext.x1_subvector, &global_size);
00123         assert(global_size == num_rows/2);
00124 
00125         IS A11_local_rows;
00126         IS A11_columns;
00127         ISCreateStride(PETSC_COMM_WORLD, high-low, 2*low, 2, &A11_local_rows);
00128         ISCreateStride(PETSC_COMM_WORLD, global_size, 0, 2, &A11_columns);
00129 
00130 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR == 1) //PETSc 3.1
00131         MatGetSubMatrix(system_matrix, A11_local_rows, A11_local_rows,
00132             MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock);
00133 #else
00134         MatGetSubMatrix(system_matrix, A11_local_rows, A11_columns, PETSC_DECIDE,
00135             MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock);
00136 #endif
00137 
00138 
00139         ISDestroy(A11_local_rows);
00140         ISDestroy(A11_columns);
00141     }
00142 
00143     // Get matrix sublock A22
00144     {
00145         // Work out local row range for subblock A22 (same as x2 or y2)
00146         PetscInt low, high, global_size;
00147         VecGetOwnershipRange(mPCContext.x2_subvector, &low, &high);
00148         VecGetSize(mPCContext.x2_subvector, &global_size);
00149         assert(global_size == num_rows/2);
00150 
00151         IS A22_local_rows;
00152         IS A22_columns;
00153         ISCreateStride(PETSC_COMM_WORLD, high-low, 2*low+1, 2, &A22_local_rows);
00154         ISCreateStride(PETSC_COMM_WORLD, global_size, 1, 2, &A22_columns);
00155 
00156 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR == 1) //PETSc 3.1
00157         MatGetSubMatrix(system_matrix, A22_local_rows, A22_local_rows,
00158             MAT_INITIAL_MATRIX, &mPCContext.A22_matrix_subblock);
00159 #else
00160         MatGetSubMatrix(system_matrix, A22_local_rows, A22_columns, PETSC_DECIDE,
00161             MAT_INITIAL_MATRIX, &mPCContext.A22_matrix_subblock);
00162 #endif
00163 
00164         ISDestroy(A22_local_rows);
00165         ISDestroy(A22_columns);
00166     }
00167 
00168     // Register call-back function and its context
00169     PCSetType(mPetscPCObject, PCSHELL);
00170 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00171     PCShellSetApply(mPetscPCObject, PCBlockDiagonalApply, (void*) &mPCContext);
00172 #else
00173     // Register PC context so it gets passed to PCBlockDiagonalApply
00174     PCShellSetContext(mPetscPCObject, &mPCContext);
00175 
00176     // Register call-back function
00177     PCShellSetApply(mPetscPCObject, PCBlockDiagonalApply);
00178 #endif
00179 
00180 }
00181 
00182 void PCBlockDiagonal::PCBlockDiagonalSetUp()
00183 {
00184     // These options will get read by PCSetFromOptions
00185 //     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00186 //     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00187 //     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00188 
00189     // Set up amg preconditioner for block A11
00190     PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A11));
00191 
00192     //    PCSetType(mPCContext.PC_amg_A11, PCBJACOBI);
00193 
00194     PCSetType(mPCContext.PC_amg_A11, PCHYPRE);
00195     //PCHYPRESetType(mPCContext.PC_amg_A11, "euclid");
00196     PetscOptionsSetValue("-pc_hypre_type", "euclid");
00197     PetscOptionsSetValue("-pc_hypre_euclid_levels", "0");
00198 
00199 
00200     //PCSetType(mPCContext.PC_amg_A11, PCHYPRE);
00201     //PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00202     //PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00203     //PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00204     //PetscOptionsSetValue("-pc_hypre_boomeramg_coarsen_type", "HMIS");
00205 
00206     PCSetOperators(mPCContext.PC_amg_A11, mPCContext.A11_matrix_subblock, mPCContext.A11_matrix_subblock, SAME_PRECONDITIONER);
00207     PCSetFromOptions(mPCContext.PC_amg_A11);
00208     PCSetUp(mPCContext.PC_amg_A11);
00209 
00210     // Set up amg preconditioner for block A22
00211     PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A22));
00212 
00213     /* Full AMG in the block */
00214     PCSetType(mPCContext.PC_amg_A22, PCHYPRE);
00215     //PCHYPRESetType(mPCContext.PC_amg_A22, "boomeramg");
00216     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00217     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00218     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00219     PetscOptionsSetValue("-pc_hypre_boomeramg_coarsen_type", "HMIS");
00220     //    PetscOptionsSetValue("-pc_hypre_boomeramg_relax_type_all","Jacobi");
00221     //PetscOptionsSetValue("-pc_hypre_boomeramg_max_levels","10");
00222     //PetscOptionsSetValue("-pc_hypre_boomeramg_agg_nl", "1");
00223     //    PetscOptionsSetValue("-pc_hypre_boomeramg_print_statistics","");
00224     //    PetscOptionsSetValue("-pc_hypre_boomeramg_interp_type","standard");
00225     //    PetscOptionsSetValue("-pc_hypre_boomeramg_interp_type","ext+i");
00226 
00227     //    PCHYPRESetType(mPCContext.PC_amg_A22, "euclid");
00228 
00229     /* Block Jacobi with AMG at each block */
00230     //     PCSetType(mPCContext.PC_amg_A22, PCBJACOBI);
00231 
00232     //     PetscOptionsSetValue("-sub_pc_type", "hypre");
00233 
00234     //     PetscOptionsSetValue("-sub_pc_hypre_type", "boomeramg");
00235     //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_max_iter", "1");
00236     //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_strong_threshold", "0.0");
00237 
00238     //     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00239     //     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00240     //     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00241 
00242     /* Additive Schwarz with AMG at each block */
00243 //     PCSetType(mPCContext.PC_amg_A22, PCASM);
00244 
00245 //     PetscOptionsSetValue("-pc_asm_type", "basic");
00246 //     PetscOptionsSetValue("-pc_asm_overlap", "1");
00247 
00248 //     PetscOptionsSetValue("-sub_ksp_type", "preonly");
00249 
00250 //     PetscOptionsSetValue("-sub_pc_type", "hypre");
00251 
00252 //     PetscOptionsSetValue("-sub_pc_hypre_type", "boomeramg");
00253 //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_max_iter", "1");
00254 //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_strong_threshold", "0.0");
00255 
00256     PCSetOperators(mPCContext.PC_amg_A22, mPCContext.A22_matrix_subblock, mPCContext.A22_matrix_subblock, SAME_PRECONDITIONER);
00257     PCSetFromOptions(mPCContext.PC_amg_A22);
00258     PCSetUp(mPCContext.PC_amg_A22);
00259 }
00260 
00261 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR == 1) //PETSc 3.1
00262 PetscErrorCode PCBlockDiagonalApply(PC pc_object, Vec x, Vec y)
00263 {
00264   void* pc_context;
00265 
00266   PCShellGetContext(pc_object, &pc_context);
00267 #else
00268 PetscErrorCode PCBlockDiagonalApply(void* pc_context, Vec x, Vec y)
00269 {
00270 #endif
00271 
00272     // Cast the context pointer to PCBlockDiagonalContext
00273     PCBlockDiagonal::PCBlockDiagonalContext* block_diag_context = (PCBlockDiagonal::PCBlockDiagonalContext*) pc_context;
00274     assert(block_diag_context!=NULL);
00275 
00276     /*
00277      * Scatter x = [x1 x2]'
00278      */
00279 #ifdef TRACE_KSP
00280     double init_time = MPI_Wtime();
00281 #endif
00282 
00283     PetscVecTools::DoInterleavedVecScatter(x, block_diag_context->A11_scatter_ctx, block_diag_context->x1_subvector, block_diag_context->A22_scatter_ctx, block_diag_context->x2_subvector);
00284 
00285 #ifdef TRACE_KSP
00286     block_diag_context->mScatterTime += MPI_Wtime() - init_time;
00287 #endif
00288 
00289     /*
00290      * y1 = AMG(A11)*x1
00291      * y2 = AMG(A22)*x2
00292      */
00293 #ifdef TRACE_KSP
00294     init_time = MPI_Wtime();
00295 #endif
00296     PCApply(block_diag_context->PC_amg_A11, block_diag_context->x1_subvector, block_diag_context->y1_subvector);
00297 #ifdef TRACE_KSP
00298     block_diag_context->mA1PreconditionerTime += MPI_Wtime() - init_time;
00299 #endif
00300 
00301 #ifdef TRACE_KSP
00302     init_time = MPI_Wtime();
00303 #endif
00304     PCApply(block_diag_context->PC_amg_A22, block_diag_context->x2_subvector, block_diag_context->y2_subvector);
00305 #ifdef TRACE_KSP
00306     block_diag_context->mA2PreconditionerTime += MPI_Wtime() - init_time;
00307 #endif
00308 
00309     /*
00310      * Gather y = [y1 y2]'
00311      */
00312 //PETSc-3.x.x or PETSc-2.3.3
00313 #ifdef TRACE_KSP
00314     init_time = MPI_Wtime();
00315 #endif
00316 
00317     PetscVecTools::DoInterleavedVecGather(y, block_diag_context->A11_scatter_ctx, block_diag_context->y1_subvector, block_diag_context->A22_scatter_ctx, block_diag_context->y2_subvector);
00318 
00319 #ifdef TRACE_KSP
00320     block_diag_context->mGatherTime += MPI_Wtime() - init_time;
00321 #endif
00322     return 0;
00323 }
Generated on Thu Dec 22 13:00:07 2011 for Chaste by  doxygen 1.6.3