PCBlockDiagonal.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 #include "Warnings.hpp"
00042 
00043 PCBlockDiagonal::PCBlockDiagonal(KSP& rKspObject)
00044 {
00045 #ifdef TRACE_KSP
00046     mPCContext.mScatterTime = 0.0;
00047     mPCContext.mA1PreconditionerTime = 0.0;;
00048     mPCContext.mA2PreconditionerTime = 0.0;;
00049     mPCContext.mGatherTime = 0.0;;
00050 #endif
00051 
00052     PCBlockDiagonalCreate(rKspObject);
00053     PCBlockDiagonalSetUp();
00054 }
00055 
00056 PCBlockDiagonal::~PCBlockDiagonal()
00057 {
00058 #ifdef TRACE_KSP
00059     if (PetscTools::AmMaster())
00060     {
00061         std::cout << " -- Block diagonal preconditioner profile information: " << std::endl;
00062         std::cout << "\t mScatterTime: " << mPCContext.mScatterTime << std::endl;
00063         std::cout << "\t mA1PreconditionerTime: " << mPCContext.mA1PreconditionerTime << std::endl;
00064         std::cout << "\t mA2PreconditionerTime: " << mPCContext.mA2PreconditionerTime << std::endl;
00065         std::cout << "\t mGatherTime: " << mPCContext.mGatherTime << std::endl;
00066     }
00067 #endif
00068 
00069     PetscTools::Destroy(mPCContext.A11_matrix_subblock);
00070     PetscTools::Destroy(mPCContext.A22_matrix_subblock);
00071 
00072     PCDestroy(PETSC_DESTROY_PARAM(mPCContext.PC_amg_A11));
00073     PCDestroy(PETSC_DESTROY_PARAM(mPCContext.PC_amg_A22));
00074 
00075     PetscTools::Destroy(mPCContext.x1_subvector);
00076     PetscTools::Destroy(mPCContext.y1_subvector);
00077 
00078     PetscTools::Destroy(mPCContext.x2_subvector);
00079     PetscTools::Destroy(mPCContext.y2_subvector);
00080 
00081     VecScatterDestroy(PETSC_DESTROY_PARAM(mPCContext.A11_scatter_ctx));
00082     VecScatterDestroy(PETSC_DESTROY_PARAM(mPCContext.A22_scatter_ctx));
00083 }
00084 
00085 void PCBlockDiagonal::PCBlockDiagonalCreate(KSP& rKspObject)
00086 {
00087     KSPGetPC(rKspObject, &mPetscPCObject);
00088 
00089     Mat system_matrix, dummy;
00090 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 )
00091     KSPGetOperators(rKspObject, &system_matrix, &dummy);
00092 #else
00093     MatStructure flag;
00094     KSPGetOperators(rKspObject, &system_matrix, &dummy, &flag);
00095 #endif
00096 
00097     PetscInt num_rows, num_columns;
00098     MatGetSize(system_matrix, &num_rows, &num_columns);
00099     assert(num_rows==num_columns);
00100 
00101     PetscInt num_local_rows, num_local_columns;
00102     MatGetLocalSize(system_matrix, &num_local_rows, &num_local_columns);
00103 
00104     // Odd number of rows: impossible in Bidomain.
00105     // Odd number of local rows: impossible if V_m and phi_e for each node are stored in the same processor.
00106     if ((num_rows%2 != 0) || (num_local_rows%2 != 0))
00107     {
00108         TERMINATE("Wrong matrix parallel layout detected in PCLDUFactorisation.");
00109     }
00110 
00111     // Allocate memory
00112     unsigned subvector_num_rows = num_rows/2;
00113     unsigned subvector_local_rows = num_local_rows/2;
00114     mPCContext.x1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00115     mPCContext.x2_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00116     mPCContext.y1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00117     mPCContext.y2_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows);
00118 
00119     // Create scatter contexts
00120     {
00121         // Needed by SetupInterleavedVectorScatterGather in order to find out parallel layout.
00122         Vec dummy_vec = PetscTools::CreateVec(num_rows, num_local_rows);
00123 
00124         PetscVecTools::SetupInterleavedVectorScatterGather(dummy_vec, mPCContext.A11_scatter_ctx, mPCContext.A22_scatter_ctx);
00125 
00126         PetscTools::Destroy(dummy_vec);
00127     }
00128 
00129     // Get matrix sublock A11
00130     {
00131         // Work out local row range for subblock A11 (same as x1 or y1)
00132         PetscInt low, high, global_size;
00133         VecGetOwnershipRange(mPCContext.x1_subvector, &low, &high);
00134         VecGetSize(mPCContext.x1_subvector, &global_size);
00135         assert(global_size == num_rows/2);
00136 
00137         IS A11_local_rows;
00138         IS A11_columns;
00139         ISCreateStride(PETSC_COMM_WORLD, high-low, 2*low, 2, &A11_local_rows);
00140         ISCreateStride(PETSC_COMM_WORLD, global_size, 0, 2, &A11_columns);
00141 
00142 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
00143         MatGetSubMatrix(system_matrix, A11_local_rows, A11_local_rows,
00144             MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock);
00145 #else
00146         MatGetSubMatrix(system_matrix, A11_local_rows, A11_columns, PETSC_DECIDE,
00147             MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock);
00148 #endif
00149 
00150 
00151         ISDestroy(PETSC_DESTROY_PARAM(A11_local_rows));
00152         ISDestroy(PETSC_DESTROY_PARAM(A11_columns));
00153     }
00154 
00155     // Get matrix sublock A22
00156     {
00157         // Work out local row range for subblock A22 (same as x2 or y2)
00158         PetscInt low, high, global_size;
00159         VecGetOwnershipRange(mPCContext.x2_subvector, &low, &high);
00160         VecGetSize(mPCContext.x2_subvector, &global_size);
00161         assert(global_size == num_rows/2);
00162 
00163         IS A22_local_rows;
00164         IS A22_columns;
00165         ISCreateStride(PETSC_COMM_WORLD, high-low, 2*low+1, 2, &A22_local_rows);
00166         ISCreateStride(PETSC_COMM_WORLD, global_size, 1, 2, &A22_columns);
00167 
00168 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
00169         MatGetSubMatrix(system_matrix, A22_local_rows, A22_local_rows,
00170             MAT_INITIAL_MATRIX, &mPCContext.A22_matrix_subblock);
00171 #else
00172         MatGetSubMatrix(system_matrix, A22_local_rows, A22_columns, PETSC_DECIDE,
00173             MAT_INITIAL_MATRIX, &mPCContext.A22_matrix_subblock);
00174 #endif
00175 
00176         ISDestroy(PETSC_DESTROY_PARAM(A22_local_rows));
00177         ISDestroy(PETSC_DESTROY_PARAM(A22_columns));
00178     }
00179 
00180     // Register call-back function and its context
00181     PCSetType(mPetscPCObject, PCSHELL);
00182 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00183     PCShellSetApply(mPetscPCObject, PCBlockDiagonalApply, (void*) &mPCContext);
00184 #else
00185     // Register PC context so it gets passed to PCBlockDiagonalApply
00186     PCShellSetContext(mPetscPCObject, &mPCContext);
00187 
00188     // Register call-back function
00189     PCShellSetApply(mPetscPCObject, PCBlockDiagonalApply);
00190 #endif
00191 
00192 }
00193 
00194 void PCBlockDiagonal::PCBlockDiagonalSetUp()
00195 {
00196     // These options will get read by PCSetFromOptions
00197 //     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00198 //     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00199 //     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00200 
00201     // Set up amg preconditioner for block A11
00202     PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A11));
00203 
00204     //    PCSetType(mPCContext.PC_amg_A11, PCBJACOBI);
00205 
00206     // We are expecting an error from PETSC on systems that don't have the hypre library, so suppress it
00207     // in case it aborts
00208     PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL);
00209     PetscErrorCode pc_set_error = PCSetType(mPCContext.PC_amg_A11, PCHYPRE);
00210     if (pc_set_error != 0)
00211     {
00212         WARNING("PETSc hypre preconditioning library is not installed");
00213     }
00214     // Stop supressing error
00215     PetscPopErrorHandler();
00216 
00217 
00218     //PCHYPRESetType(mPCContext.PC_amg_A11, "euclid");
00219     PetscOptionsSetValue("-pc_hypre_type", "euclid");
00220     PetscOptionsSetValue("-pc_hypre_euclid_levels", "0");
00221 
00222 
00223     //PCSetType(mPCContext.PC_amg_A11, PCHYPRE);
00224     //PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00225     //PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00226     //PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00227     //PetscOptionsSetValue("-pc_hypre_boomeramg_coarsen_type", "HMIS");
00228 
00229 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 )
00230     // Attempt to emulate SAME_PRECONDITIONER below
00231     PCSetReusePreconditioner(mPCContext.PC_amg_A11, PETSC_TRUE);
00232     PCSetOperators(mPCContext.PC_amg_A11, mPCContext.A11_matrix_subblock, mPCContext.A11_matrix_subblock);
00233 #else
00234     PCSetOperators(mPCContext.PC_amg_A11, mPCContext.A11_matrix_subblock, mPCContext.A11_matrix_subblock, SAME_PRECONDITIONER);
00235 #endif
00236     PCSetFromOptions(mPCContext.PC_amg_A11);
00237     PCSetUp(mPCContext.PC_amg_A11);
00238 
00239     // Set up amg preconditioner for block A22
00240     PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A22));
00241 
00242     /* Full AMG in the block */
00243     PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL);
00244     PCSetType(mPCContext.PC_amg_A22, PCHYPRE);
00245     // Stop supressing error
00246     PetscPopErrorHandler();
00247 
00248     //PCHYPRESetType(mPCContext.PC_amg_A22, "boomeramg");
00249     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00250     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00251     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00252     PetscOptionsSetValue("-pc_hypre_boomeramg_coarsen_type", "HMIS");
00253     //    PetscOptionsSetValue("-pc_hypre_boomeramg_relax_type_all","Jacobi");
00254     //PetscOptionsSetValue("-pc_hypre_boomeramg_max_levels","10");
00255     //PetscOptionsSetValue("-pc_hypre_boomeramg_agg_nl", "1");
00256     //    PetscOptionsSetValue("-pc_hypre_boomeramg_print_statistics","");
00257     //    PetscOptionsSetValue("-pc_hypre_boomeramg_interp_type","standard");
00258     //    PetscOptionsSetValue("-pc_hypre_boomeramg_interp_type","ext+i");
00259 
00260     //    PCHYPRESetType(mPCContext.PC_amg_A22, "euclid");
00261 
00262     /* Block Jacobi with AMG at each block */
00263     //     PCSetType(mPCContext.PC_amg_A22, PCBJACOBI);
00264 
00265     //     PetscOptionsSetValue("-sub_pc_type", "hypre");
00266 
00267     //     PetscOptionsSetValue("-sub_pc_hypre_type", "boomeramg");
00268     //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_max_iter", "1");
00269     //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_strong_threshold", "0.0");
00270 
00271     //     PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00272     //     PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00273     //     PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00274 
00275     /* Additive Schwarz with AMG at each block */
00276 //     PCSetType(mPCContext.PC_amg_A22, PCASM);
00277 
00278 //     PetscOptionsSetValue("-pc_asm_type", "basic");
00279 //     PetscOptionsSetValue("-pc_asm_overlap", "1");
00280 
00281 //     PetscOptionsSetValue("-sub_ksp_type", "preonly");
00282 
00283 //     PetscOptionsSetValue("-sub_pc_type", "hypre");
00284 
00285 //     PetscOptionsSetValue("-sub_pc_hypre_type", "boomeramg");
00286 //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_max_iter", "1");
00287 //     PetscOptionsSetValue("-sub_pc_hypre_boomeramg_strong_threshold", "0.0");
00288 
00289 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 )
00290     // Attempt to emulate SAME_PRECONDITIONER below
00291     PCSetReusePreconditioner(mPCContext.PC_amg_A22, PETSC_TRUE);
00292     PCSetOperators(mPCContext.PC_amg_A22, mPCContext.A22_matrix_subblock, mPCContext.A22_matrix_subblock);
00293 #else
00294     PCSetOperators(mPCContext.PC_amg_A22, mPCContext.A22_matrix_subblock, mPCContext.A22_matrix_subblock, SAME_PRECONDITIONER);
00295 #endif
00296     PCSetFromOptions(mPCContext.PC_amg_A22);
00297     PCSetUp(mPCContext.PC_amg_A22);
00298 }
00299 
00300 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
00301 PetscErrorCode PCBlockDiagonalApply(PC pc_object, Vec x, Vec y)
00302 {
00303   void* pc_context;
00304 
00305   PCShellGetContext(pc_object, &pc_context);
00306 #else
00307 PetscErrorCode PCBlockDiagonalApply(void* pc_context, Vec x, Vec y)
00308 {
00309 #endif
00310 
00311     // Cast the context pointer to PCBlockDiagonalContext
00312     PCBlockDiagonal::PCBlockDiagonalContext* block_diag_context = (PCBlockDiagonal::PCBlockDiagonalContext*) pc_context;
00313     assert(block_diag_context!=NULL);
00314 
00315     /*
00316      * Scatter x = [x1 x2]'
00317      */
00318 #ifdef TRACE_KSP
00319     Timer::Reset();
00320 #endif
00321 
00322     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);
00323 
00324 #ifdef TRACE_KSP
00325     block_diag_context->mScatterTime += Timer::GetElapsedTime();
00326 #endif
00327 
00328     /*
00329      * y1 = AMG(A11)*x1
00330      * y2 = AMG(A22)*x2
00331      */
00332 #ifdef TRACE_KSP
00333     Timer::Reset();
00334 #endif
00335     PCApply(block_diag_context->PC_amg_A11, block_diag_context->x1_subvector, block_diag_context->y1_subvector);
00336 #ifdef TRACE_KSP
00337     block_diag_context->mA1PreconditionerTime += Timer::GetElapsedTime();
00338 #endif
00339 
00340 #ifdef TRACE_KSP
00341     Timer::Reset();
00342 #endif
00343     PCApply(block_diag_context->PC_amg_A22, block_diag_context->x2_subvector, block_diag_context->y2_subvector);
00344 #ifdef TRACE_KSP
00345     block_diag_context->mA2PreconditionerTime += Timer::GetElapsedTime();
00346 #endif
00347 
00348     /*
00349      * Gather y = [y1 y2]'
00350      */
00351 //PETSc-3.x.x or PETSc-2.3.3
00352 #ifdef TRACE_KSP
00353     Timer::Reset();
00354 #endif
00355 
00356     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);
00357 
00358 #ifdef TRACE_KSP
00359     block_diag_context->mGatherTime += Timer::GetElapsedTime();
00360 #endif
00361     return 0;
00362 }

Generated by  doxygen 1.6.2