Chaste Release::3.1
PCBlockDiagonal.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #include <iostream>
00037 
00038 #include "PetscVecTools.hpp" // Includes Ublas so must come first
00039 #include "PCBlockDiagonal.hpp"
00040 #include "Exception.hpp"
00041 
00042 PCBlockDiagonal::PCBlockDiagonal(KSP& rKspObject)
00043 {
00044 #ifdef TRACE_KSP
00045     mPCContext.mScatterTime = 0.0;
00046     mPCContext.mA1PreconditionerTime = 0.0;;
00047     mPCContext.mA2PreconditionerTime = 0.0;;
00048     mPCContext.mGatherTime = 0.0;;
00049 #endif
00050 
00051     PCBlockDiagonalCreate(rKspObject);
00052     PCBlockDiagonalSetUp();
00053 }
00054 
00055 PCBlockDiagonal::~PCBlockDiagonal()
00056 {
00057 #ifdef TRACE_KSP
00058     if (PetscTools::AmMaster())
00059     {
00060         std::cout << " -- Block diagonal preconditioner profile information: " << std::endl;
00061         std::cout << "\t mScatterTime: " << mPCContext.mScatterTime << std::endl;
00062         std::cout << "\t mA1PreconditionerTime: " << mPCContext.mA1PreconditionerTime << std::endl;
00063         std::cout << "\t mA2PreconditionerTime: " << mPCContext.mA2PreconditionerTime << std::endl;
00064         std::cout << "\t mGatherTime: " << mPCContext.mGatherTime << std::endl;
00065     }
00066 #endif
00067 
00068     PetscTools::Destroy(mPCContext.A11_matrix_subblock);
00069     PetscTools::Destroy(mPCContext.A22_matrix_subblock);
00070 
00071     PCDestroy(PETSC_DESTROY_PARAM(mPCContext.PC_amg_A11));
00072     PCDestroy(PETSC_DESTROY_PARAM(mPCContext.PC_amg_A22));
00073 
00074     PetscTools::Destroy(mPCContext.x1_subvector);
00075     PetscTools::Destroy(mPCContext.y1_subvector);
00076 
00077     PetscTools::Destroy(mPCContext.x2_subvector);
00078     PetscTools::Destroy(mPCContext.y2_subvector);
00079 
00080     VecScatterDestroy(PETSC_DESTROY_PARAM(mPCContext.A11_scatter_ctx));
00081     VecScatterDestroy(PETSC_DESTROY_PARAM(mPCContext.A22_scatter_ctx));
00082 }
00083 
00084 void PCBlockDiagonal::PCBlockDiagonalCreate(KSP& rKspObject)
00085 {
00086     KSPGetPC(rKspObject, &mPetscPCObject);
00087 
00088     Mat system_matrix, dummy;
00089     MatStructure flag;
00090     KSPGetOperators(rKspObject, &system_matrix, &dummy, &flag);
00091 
00092     PetscInt num_rows, num_columns;
00093     MatGetSize(system_matrix, &num_rows, &num_columns);
00094     assert(num_rows==num_columns);
00095 
00096     PetscInt num_local_rows, num_local_columns;
00097     MatGetLocalSize(system_matrix, &num_local_rows, &num_local_columns);
00098 
00099     // Odd number of rows: impossible in Bidomain.
00100     // Odd number of local rows: impossible if V_m and phi_e for each node are stored in the same processor.
00101     if ((num_rows%2 != 0) || (num_local_rows%2 != 0))
00102     {
00103         TERMINATE("Wrong matrix parallel layout detected in PCLDUFactorisation.");
00104     }
00105 
00106     // Allocate memory
00107     unsigned subvector_num_rows = num_rows/2;
00108     unsigned subvector_local_rows = num_local_rows/2;
00109     mPCContext.x1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00110     mPCContext.x2_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00111     mPCContext.y1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00112     mPCContext.y2_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00113 
00114     // Create scatter contexts
00115     {
00116         // Needed by SetupInterleavedVectorScatterGather in order to find out parallel layout.
00117         Vec dummy_vec = PetscTools::CreateVec(num_rows, num_local_rows);
00118 
00119         PetscVecTools::SetupInterleavedVectorScatterGather(dummy_vec, mPCContext.A11_scatter_ctx, mPCContext.A22_scatter_ctx);
00120 
00121         PetscTools::Destroy(dummy_vec);
00122     }
00123 
00124     // Get matrix sublock A11
00125     {
00126         // Work out local row range for subblock A11 (same as x1 or y1)
00127         PetscInt low, high, global_size;
00128         VecGetOwnershipRange(mPCContext.x1_subvector, &low, &high);
00129         VecGetSize(mPCContext.x1_subvector, &global_size);
00130         assert(global_size == num_rows/2);
00131 
00132         IS A11_local_rows;
00133         IS A11_columns;
00134         ISCreateStride(PETSC_COMM_WORLD, high-low, 2*low, 2, &A11_local_rows);
00135         ISCreateStride(PETSC_COMM_WORLD, global_size, 0, 2, &A11_columns);
00136 
00137 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
00138         MatGetSubMatrix(system_matrix, A11_local_rows, A11_local_rows,
00139             MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock);
00140 #else
00141         MatGetSubMatrix(system_matrix, A11_local_rows, A11_columns, PETSC_DECIDE,
00142             MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock);
00143 #endif
00144 
00145 
00146         ISDestroy(PETSC_DESTROY_PARAM(A11_local_rows));
00147         ISDestroy(PETSC_DESTROY_PARAM(A11_columns));
00148     }
00149 
00150     // Get matrix sublock A22
00151     {
00152         // Work out local row range for subblock A22 (same as x2 or y2)
00153         PetscInt low, high, global_size;
00154         VecGetOwnershipRange(mPCContext.x2_subvector, &low, &high);
00155         VecGetSize(mPCContext.x2_subvector, &global_size);
00156         assert(global_size == num_rows/2);
00157 
00158         IS A22_local_rows;
00159         IS A22_columns;
00160         ISCreateStride(PETSC_COMM_WORLD, high-low, 2*low+1, 2, &A22_local_rows);
00161         ISCreateStride(PETSC_COMM_WORLD, global_size, 1, 2, &A22_columns);
00162 
00163 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
00164         MatGetSubMatrix(system_matrix, A22_local_rows, A22_local_rows,
00165             MAT_INITIAL_MATRIX, &mPCContext.A22_matrix_subblock);
00166 #else
00167         MatGetSubMatrix(system_matrix, A22_local_rows, A22_columns, PETSC_DECIDE,
00168             MAT_INITIAL_MATRIX, &mPCContext.A22_matrix_subblock);
00169 #endif
00170 
00171         ISDestroy(PETSC_DESTROY_PARAM(A22_local_rows));
00172         ISDestroy(PETSC_DESTROY_PARAM(A22_columns));
00173     }
00174 
00175     // Register call-back function and its context
00176     PCSetType(mPetscPCObject, PCSHELL);
00177 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00178     PCShellSetApply(mPetscPCObject, PCBlockDiagonalApply, (void*) &mPCContext);
00179 #else
00180     // Register PC context so it gets passed to PCBlockDiagonalApply
00181     PCShellSetContext(mPetscPCObject, &mPCContext);
00182 
00183     // Register call-back function
00184     PCShellSetApply(mPetscPCObject, PCBlockDiagonalApply);
00185 #endif
00186 
00187 }
00188 
00189 void PCBlockDiagonal::PCBlockDiagonalSetUp()
00190 {
00191     // These options will get read by PCSetFromOptions
00192 //     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00193 //     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00194 //     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00195 
00196     // Set up amg preconditioner for block A11
00197     PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A11));
00198 
00199     //    PCSetType(mPCContext.PC_amg_A11, PCBJACOBI);
00200 
00201     PCSetType(mPCContext.PC_amg_A11, PCHYPRE);
00202     //PCHYPRESetType(mPCContext.PC_amg_A11, "euclid");
00203     PetscOptionsSetValue("-pc_hypre_type", "euclid");
00204     PetscOptionsSetValue("-pc_hypre_euclid_levels", "0");
00205 
00206 
00207     //PCSetType(mPCContext.PC_amg_A11, PCHYPRE);
00208     //PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00209     //PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00210     //PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00211     //PetscOptionsSetValue("-pc_hypre_boomeramg_coarsen_type", "HMIS");
00212 
00213     PCSetOperators(mPCContext.PC_amg_A11, mPCContext.A11_matrix_subblock, mPCContext.A11_matrix_subblock, SAME_PRECONDITIONER);
00214     PCSetFromOptions(mPCContext.PC_amg_A11);
00215     PCSetUp(mPCContext.PC_amg_A11);
00216 
00217     // Set up amg preconditioner for block A22
00218     PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A22));
00219 
00220     /* Full AMG in the block */
00221     PCSetType(mPCContext.PC_amg_A22, PCHYPRE);
00222     //PCHYPRESetType(mPCContext.PC_amg_A22, "boomeramg");
00223     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00224     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00225     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00226     PetscOptionsSetValue("-pc_hypre_boomeramg_coarsen_type", "HMIS");
00227     //    PetscOptionsSetValue("-pc_hypre_boomeramg_relax_type_all","Jacobi");
00228     //PetscOptionsSetValue("-pc_hypre_boomeramg_max_levels","10");
00229     //PetscOptionsSetValue("-pc_hypre_boomeramg_agg_nl", "1");
00230     //    PetscOptionsSetValue("-pc_hypre_boomeramg_print_statistics","");
00231     //    PetscOptionsSetValue("-pc_hypre_boomeramg_interp_type","standard");
00232     //    PetscOptionsSetValue("-pc_hypre_boomeramg_interp_type","ext+i");
00233 
00234     //    PCHYPRESetType(mPCContext.PC_amg_A22, "euclid");
00235 
00236     /* Block Jacobi with AMG at each block */
00237     //     PCSetType(mPCContext.PC_amg_A22, PCBJACOBI);
00238 
00239     //     PetscOptionsSetValue("-sub_pc_type", "hypre");
00240 
00241     //     PetscOptionsSetValue("-sub_pc_hypre_type", "boomeramg");
00242     //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_max_iter", "1");
00243     //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_strong_threshold", "0.0");
00244 
00245     //     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00246     //     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00247     //     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00248 
00249     /* Additive Schwarz with AMG at each block */
00250 //     PCSetType(mPCContext.PC_amg_A22, PCASM);
00251 
00252 //     PetscOptionsSetValue("-pc_asm_type", "basic");
00253 //     PetscOptionsSetValue("-pc_asm_overlap", "1");
00254 
00255 //     PetscOptionsSetValue("-sub_ksp_type", "preonly");
00256 
00257 //     PetscOptionsSetValue("-sub_pc_type", "hypre");
00258 
00259 //     PetscOptionsSetValue("-sub_pc_hypre_type", "boomeramg");
00260 //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_max_iter", "1");
00261 //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_strong_threshold", "0.0");
00262 
00263     PCSetOperators(mPCContext.PC_amg_A22, mPCContext.A22_matrix_subblock, mPCContext.A22_matrix_subblock, SAME_PRECONDITIONER);
00264     PCSetFromOptions(mPCContext.PC_amg_A22);
00265     PCSetUp(mPCContext.PC_amg_A22);
00266 }
00267 
00268 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
00269 PetscErrorCode PCBlockDiagonalApply(PC pc_object, Vec x, Vec y)
00270 {
00271   void* pc_context;
00272 
00273   PCShellGetContext(pc_object, &pc_context);
00274 #else
00275 PetscErrorCode PCBlockDiagonalApply(void* pc_context, Vec x, Vec y)
00276 {
00277 #endif
00278 
00279     // Cast the context pointer to PCBlockDiagonalContext
00280     PCBlockDiagonal::PCBlockDiagonalContext* block_diag_context = (PCBlockDiagonal::PCBlockDiagonalContext*) pc_context;
00281     assert(block_diag_context!=NULL);
00282 
00283     /*
00284      * Scatter x = [x1 x2]'
00285      */
00286 #ifdef TRACE_KSP
00287     double init_time = MPI_Wtime();
00288 #endif
00289 
00290     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);
00291 
00292 #ifdef TRACE_KSP
00293     block_diag_context->mScatterTime += MPI_Wtime() - init_time;
00294 #endif
00295 
00296     /*
00297      * y1 = AMG(A11)*x1
00298      * y2 = AMG(A22)*x2
00299      */
00300 #ifdef TRACE_KSP
00301     init_time = MPI_Wtime();
00302 #endif
00303     PCApply(block_diag_context->PC_amg_A11, block_diag_context->x1_subvector, block_diag_context->y1_subvector);
00304 #ifdef TRACE_KSP
00305     block_diag_context->mA1PreconditionerTime += MPI_Wtime() - init_time;
00306 #endif
00307 
00308 #ifdef TRACE_KSP
00309     init_time = MPI_Wtime();
00310 #endif
00311     PCApply(block_diag_context->PC_amg_A22, block_diag_context->x2_subvector, block_diag_context->y2_subvector);
00312 #ifdef TRACE_KSP
00313     block_diag_context->mA2PreconditionerTime += MPI_Wtime() - init_time;
00314 #endif
00315 
00316     /*
00317      * Gather y = [y1 y2]'
00318      */
00319 //PETSc-3.x.x or PETSc-2.3.3
00320 #ifdef TRACE_KSP
00321     init_time = MPI_Wtime();
00322 #endif
00323 
00324     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);
00325 
00326 #ifdef TRACE_KSP
00327     block_diag_context->mGatherTime += MPI_Wtime() - init_time;
00328 #endif
00329     return 0;
00330 }