Chaste Release::3.1
|
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 "PCTwoLevelsBlockDiagonal.hpp" 00037 #include "Exception.hpp" 00038 00039 #include <iostream> 00040 00041 PCTwoLevelsBlockDiagonal::PCTwoLevelsBlockDiagonal(KSP& rKspObject, std::vector<PetscInt>& rBathNodes) 00042 { 00043 PCTwoLevelsBlockDiagonalCreate(rKspObject, rBathNodes); 00044 PCTwoLevelsBlockDiagonalSetUp(); 00045 } 00046 00047 PCTwoLevelsBlockDiagonal::~PCTwoLevelsBlockDiagonal() 00048 { 00049 PetscTools::Destroy(mPCContext.A11_matrix_subblock); 00050 PetscTools::Destroy(mPCContext.A22_B1_matrix_subblock); 00051 PetscTools::Destroy(mPCContext.A22_B2_matrix_subblock); 00052 00053 PCDestroy(PETSC_DESTROY_PARAM(mPCContext.PC_amg_A11)); 00054 PCDestroy(PETSC_DESTROY_PARAM(mPCContext.PC_amg_A22_B1)); 00055 PCDestroy(PETSC_DESTROY_PARAM(mPCContext.PC_amg_A22_B2)); 00056 00057 PetscTools::Destroy(mPCContext.x1_subvector); 00058 PetscTools::Destroy(mPCContext.y1_subvector); 00059 00060 PetscTools::Destroy(mPCContext.x21_subvector); 00061 PetscTools::Destroy(mPCContext.y21_subvector); 00062 00063 PetscTools::Destroy(mPCContext.x22_subvector); 00064 PetscTools::Destroy(mPCContext.y22_subvector); 00065 00066 VecScatterDestroy(PETSC_DESTROY_PARAM(mPCContext.A11_scatter_ctx)); 00067 VecScatterDestroy(PETSC_DESTROY_PARAM(mPCContext.A22_B1_scatter_ctx)); 00068 VecScatterDestroy(PETSC_DESTROY_PARAM(mPCContext.A22_B2_scatter_ctx)); 00069 } 00070 00071 void PCTwoLevelsBlockDiagonal::PCTwoLevelsBlockDiagonalCreate(KSP& rKspObject, std::vector<PetscInt>& rBathNodes) 00072 { 00073 KSPGetPC(rKspObject, &mPetscPCObject); 00074 00075 Mat system_matrix, dummy; 00076 MatStructure flag; 00077 KSPGetOperators(rKspObject, &system_matrix, &dummy, &flag); 00078 00079 PetscInt num_rows, num_columns; 00080 MatGetSize(system_matrix, &num_rows, &num_columns); 00081 assert(num_rows==num_columns); 00082 00083 PetscInt num_local_rows, num_local_columns; 00084 MatGetLocalSize(system_matrix, &num_local_rows, &num_local_columns); 00085 00086 // Odd number of rows: impossible in Bidomain. 00087 // Odd number of local rows: impossible if V_m and phi_e for each node are stored in the same processor. 00088 if ((num_rows%2 != 0) || (num_local_rows%2 != 0)) 00089 { 00090 TERMINATE("Wrong matrix parallel layout detected in PCLDUFactorisation."); 00091 } 00092 00093 // Allocate memory 00094 unsigned subvector_num_rows = num_rows/2; 00095 unsigned subvector_local_rows = num_local_rows/2; 00096 00097 unsigned subvector_num_rows_tissue = subvector_num_rows - rBathNodes.size(); 00098 unsigned subvector_local_rows_tissue = subvector_num_rows_tissue; 00099 00100 unsigned subvector_num_rows_bath = rBathNodes.size(); 00101 unsigned subvector_local_rows_bath = subvector_num_rows_bath; 00102 00103 assert(PetscTools::IsSequential()); 00104 00105 mPCContext.x1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows); 00106 mPCContext.x21_subvector = PetscTools::CreateVec(subvector_num_rows_tissue, subvector_local_rows_tissue); 00107 mPCContext.x22_subvector = PetscTools::CreateVec(subvector_num_rows_bath, subvector_local_rows_bath); 00108 mPCContext.y1_subvector = PetscTools::CreateVec(subvector_num_rows, subvector_local_rows); 00109 mPCContext.y21_subvector = PetscTools::CreateVec(subvector_num_rows_tissue, subvector_local_rows_tissue); 00110 mPCContext.y22_subvector = PetscTools::CreateVec(subvector_num_rows_bath, subvector_local_rows_bath); 00111 00112 // Define IS objects that will be used throughout the method 00113 IS A11_all_rows; 00114 ISCreateStride(PETSC_COMM_WORLD, num_rows/2, 0, 2, &A11_all_rows); 00115 00116 IS A22_all_rows; 00117 PetscInt A22_size; 00118 VecGetSize(mPCContext.x1_subvector, &A22_size); 00120 ISCreateStride(PETSC_COMM_WORLD, A22_size, 1, 2, &A22_all_rows); 00121 00122 IS A22_bath_rows; 00123 PetscInt* phi_e_bath_rows = new PetscInt[rBathNodes.size()]; 00124 for (unsigned index=0; index<rBathNodes.size(); index++) 00125 { 00126 phi_e_bath_rows[index] = 2*rBathNodes[index] + 1; 00127 } 00128 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 2) //PETSc 3.2 or later 00129 ISCreateGeneral(PETSC_COMM_WORLD, rBathNodes.size(), phi_e_bath_rows, PETSC_OWN_POINTER, &A22_bath_rows); 00130 #else 00131 ISCreateGeneralWithArray(PETSC_COMM_WORLD, rBathNodes.size(), phi_e_bath_rows, &A22_bath_rows); 00132 #endif 00133 00134 IS A22_tissue_rows; 00135 ISDifference(A22_all_rows, A22_bath_rows, &A22_tissue_rows); 00136 00137 // Create scatter contexts 00138 { 00139 // Needed by VecScatterCreate in order to find out parallel layout. 00140 Vec dummy_vec = PetscTools::CreateVec(num_rows, num_local_rows); 00141 00143 IS& A11_rows=A11_all_rows; 00144 IS& A22_B1_rows=A22_tissue_rows; 00145 IS& A22_B2_rows=A22_bath_rows; 00146 00147 IS all_vector; 00148 ISCreateStride(PETSC_COMM_WORLD, num_rows/2, 0, 1, &all_vector); 00149 00150 IS tissue_vector; 00151 ISCreateStride(PETSC_COMM_WORLD, (num_rows/2)-rBathNodes.size(), 0, 1, &tissue_vector); 00152 00153 IS bath_vector; 00154 ISCreateStride(PETSC_COMM_WORLD, rBathNodes.size(), 0, 1, &bath_vector); 00155 00156 VecScatterCreate(dummy_vec, A11_rows, mPCContext.x1_subvector, all_vector, &mPCContext.A11_scatter_ctx); 00157 VecScatterCreate(dummy_vec, A22_B1_rows, mPCContext.x21_subvector, tissue_vector, &mPCContext.A22_B1_scatter_ctx); 00158 VecScatterCreate(dummy_vec, A22_B2_rows, mPCContext.x22_subvector, bath_vector, &mPCContext.A22_B2_scatter_ctx); 00159 00160 ISDestroy(PETSC_DESTROY_PARAM(all_vector)); 00161 ISDestroy(PETSC_DESTROY_PARAM(tissue_vector)); 00162 ISDestroy(PETSC_DESTROY_PARAM(bath_vector)); 00163 00164 PetscTools::Destroy(dummy_vec); 00165 } 00166 00167 // Get matrix sublock A11 00168 { 00169 // Work out local row range for subblock A11 (same as x1 or y1) 00170 PetscInt low, high, global_size; 00171 VecGetOwnershipRange(mPCContext.x1_subvector, &low, &high); 00172 VecGetSize(mPCContext.x1_subvector, &global_size); 00173 assert(global_size == num_rows/2); 00174 00175 IS A11_local_rows; 00176 IS& A11_columns=A11_all_rows; 00177 ISCreateStride(PETSC_COMM_WORLD, high-low, 2*low, 2, &A11_local_rows); 00178 00179 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later 00180 MatGetSubMatrix(system_matrix, A11_local_rows, A11_columns, 00181 MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock); 00182 #else 00183 MatGetSubMatrix(system_matrix, A11_local_rows, A11_columns, PETSC_DECIDE, 00184 MAT_INITIAL_MATRIX, &mPCContext.A11_matrix_subblock); 00185 #endif 00186 00187 ISDestroy(PETSC_DESTROY_PARAM(A11_local_rows)); 00188 } 00189 00190 // Get matrix sublock A22_B1 00191 { 00192 // // Work out local row range for subblock A22 (same as x2 or y2) 00193 // PetscInt low, high, global_size; 00194 // VecGetOwnershipRange(mPCContext.x21_subvector, &low, &high); 00195 // VecGetSize(mPCContext.x21_subvector, &global_size); 00196 // assert(global_size == (num_rows/2) - (PetscInt) rBathNodes.size()); 00197 00198 assert(PetscTools::IsSequential()); 00199 IS& A22_B1_local_rows = A22_tissue_rows; // wrong in parallel, need to give local rows 00200 IS& A22_B1_columns = A22_tissue_rows; 00201 00202 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later 00203 MatGetSubMatrix(system_matrix, A22_B1_local_rows, A22_B1_columns, 00204 MAT_INITIAL_MATRIX, &mPCContext.A22_B1_matrix_subblock); 00205 #else 00206 MatGetSubMatrix(system_matrix, A22_B1_local_rows, A22_B1_columns, PETSC_DECIDE, 00207 MAT_INITIAL_MATRIX, &mPCContext.A22_B1_matrix_subblock); 00208 #endif 00209 00210 } 00211 00212 // Get matrix sublock A22_B2 00213 { 00214 // // Work out local row range for subblock A22 (same as x2 or y2) 00215 // PetscInt low, high, global_size; 00216 // VecGetOwnershipRange(mPCContext.x21_subvector, &low, &high); 00217 // VecGetSize(mPCContext.x21_subvector, &global_size); 00218 // assert(global_size == (num_rows/2) - (PetscInt) rBathNodes.size()); 00219 00220 assert(PetscTools::IsSequential()); 00221 IS& A22_B2_local_rows = A22_bath_rows; // wrong in parallel, need to give local rows 00222 IS& A22_B2_columns = A22_bath_rows; 00223 00224 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later 00225 MatGetSubMatrix(system_matrix, A22_B2_local_rows, A22_B2_columns, 00226 MAT_INITIAL_MATRIX, &mPCContext.A22_B2_matrix_subblock); 00227 #else 00228 MatGetSubMatrix(system_matrix, A22_B2_local_rows, A22_B2_columns, PETSC_DECIDE, 00229 MAT_INITIAL_MATRIX, &mPCContext.A22_B2_matrix_subblock); 00230 #endif 00231 } 00232 00233 ISDestroy(PETSC_DESTROY_PARAM(A11_all_rows)); 00234 ISDestroy(PETSC_DESTROY_PARAM(A22_all_rows)); 00235 ISDestroy(PETSC_DESTROY_PARAM(A22_bath_rows)); 00236 delete[] phi_e_bath_rows; 00237 ISDestroy(PETSC_DESTROY_PARAM(A22_tissue_rows)); 00238 00239 // Register call-back function and its context 00240 PCSetType(mPetscPCObject, PCSHELL); 00241 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2 00242 PCShellSetApply(mPetscPCObject, PCTwoLevelsBlockDiagonalApply, (void*) &mPCContext); 00243 #else 00244 // Register PC context so it gets passed to PCTwoLevelsBlockDiagonalApply 00245 PCShellSetContext(mPetscPCObject, &mPCContext); 00246 00247 // Register call-back function 00248 PCShellSetApply(mPetscPCObject, PCTwoLevelsBlockDiagonalApply); 00249 #endif 00250 } 00251 00252 void PCTwoLevelsBlockDiagonal::PCTwoLevelsBlockDiagonalSetUp() 00253 { 00254 // These options will get read by PCSetFromOptions 00255 PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1"); 00256 PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0"); 00257 PetscOptionsSetValue("-pc_hypre_type", "boomeramg"); 00258 00259 // Set up amg preconditioner for block A11 00260 PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A11)); 00261 PCSetType(mPCContext.PC_amg_A11, PCBJACOBI); 00262 PCSetOperators(mPCContext.PC_amg_A11, mPCContext.A11_matrix_subblock, mPCContext.A11_matrix_subblock, DIFFERENT_NONZERO_PATTERN);// SAME_PRECONDITIONER); 00263 PCSetFromOptions(mPCContext.PC_amg_A11); 00264 PCSetUp(mPCContext.PC_amg_A11); 00265 00266 // Set up amg preconditioner for block A22_B1 00267 PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A22_B1)); 00268 PCSetType(mPCContext.PC_amg_A22_B1, PCBJACOBI); 00269 PCSetOperators(mPCContext.PC_amg_A22_B1, mPCContext.A22_B1_matrix_subblock, mPCContext.A22_B1_matrix_subblock, DIFFERENT_NONZERO_PATTERN);// SAME_PRECONDITIONER); 00270 PCSetFromOptions(mPCContext.PC_amg_A22_B1); 00271 PCSetUp(mPCContext.PC_amg_A22_B1); 00272 00273 // Set up amg preconditioner for block A22_B2 00274 PCCreate(PETSC_COMM_WORLD, &(mPCContext.PC_amg_A22_B2)); 00275 PCSetType(mPCContext.PC_amg_A22_B2, PCHYPRE); 00276 //PCHYPRESetType(mPCContext.PC_amg_A22_B2, "boomeramg"); 00277 PetscOptionsSetValue("-pc_hypre_type", "boomeramg"); 00278 00279 PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1"); 00280 PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0"); 00281 PetscOptionsSetValue("-pc_hypre_boomeramg_coarsen_type", "HMIS"); 00282 00283 PCSetOperators(mPCContext.PC_amg_A22_B2, mPCContext.A22_B2_matrix_subblock, mPCContext.A22_B2_matrix_subblock, DIFFERENT_NONZERO_PATTERN);// SAME_PRECONDITIONER); 00284 PCSetFromOptions(mPCContext.PC_amg_A22_B2); 00285 PCSetUp(mPCContext.PC_amg_A22_B2); 00286 } 00287 00288 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later 00289 PetscErrorCode PCTwoLevelsBlockDiagonalApply(PC pc_object, Vec x, Vec y) 00290 { 00291 void* pc_context; 00292 00293 PCShellGetContext(pc_object, &pc_context); 00294 #else 00295 PetscErrorCode PCTwoLevelsBlockDiagonalApply(void* pc_context, Vec x, Vec y) 00296 { 00297 #endif 00298 00299 // Cast the context pointer to PCTwoLevelsBlockDiagonalContext 00300 PCTwoLevelsBlockDiagonal::PCTwoLevelsBlockDiagonalContext* block_diag_context = (PCTwoLevelsBlockDiagonal::PCTwoLevelsBlockDiagonalContext*) pc_context; 00301 assert(block_diag_context!=NULL); 00302 00303 /* 00304 * Scatter x = [x1 x21 x22]' 00305 */ 00306 //PETSc-3.x.x or PETSc-2.3.3 00307 #if ( (PETSC_VERSION_MAJOR == 3) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR == 3)) //2.3.3 or 3.x.x 00308 VecScatterBegin(block_diag_context->A11_scatter_ctx, x, block_diag_context->x1_subvector, INSERT_VALUES, SCATTER_FORWARD); 00309 VecScatterEnd(block_diag_context->A11_scatter_ctx, x, block_diag_context->x1_subvector, INSERT_VALUES, SCATTER_FORWARD); 00310 #else 00311 VecScatterBegin(x, block_diag_context->x1_subvector, INSERT_VALUES, SCATTER_FORWARD, block_diag_context->A11_scatter_ctx); 00312 VecScatterEnd(x, block_diag_context->x1_subvector, INSERT_VALUES, SCATTER_FORWARD, block_diag_context->A11_scatter_ctx); 00313 #endif 00314 00315 //PETSc-3.x.x or PETSc-2.3.3 00316 #if ( (PETSC_VERSION_MAJOR == 3) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR == 3)) //2.3.3 or 3.x.x 00317 VecScatterBegin(block_diag_context->A22_B1_scatter_ctx, x, block_diag_context->x21_subvector, INSERT_VALUES, SCATTER_FORWARD); 00318 VecScatterEnd(block_diag_context->A22_B1_scatter_ctx, x, block_diag_context->x21_subvector, INSERT_VALUES, SCATTER_FORWARD); 00319 #else 00320 VecScatterBegin(x, block_diag_context->x21_subvector, INSERT_VALUES, SCATTER_FORWARD, block_diag_context->A22_B1_scatter_ctx); 00321 VecScatterEnd(x, block_diag_context->x21_subvector, INSERT_VALUES, SCATTER_FORWARD, block_diag_context->A22_B1_scatter_ctx); 00322 #endif 00323 00324 //PETSc-3.x.x or PETSc-2.3.3 00325 #if ( (PETSC_VERSION_MAJOR == 3) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR == 3)) //2.3.3 or 3.x.x 00326 VecScatterBegin(block_diag_context->A22_B2_scatter_ctx, x, block_diag_context->x22_subvector, INSERT_VALUES, SCATTER_FORWARD); 00327 VecScatterEnd(block_diag_context->A22_B2_scatter_ctx, x, block_diag_context->x22_subvector, INSERT_VALUES, SCATTER_FORWARD); 00328 #else 00329 VecScatterBegin(x, block_diag_context->x22_subvector, INSERT_VALUES, SCATTER_FORWARD, block_diag_context->A22_B2_scatter_ctx); 00330 VecScatterEnd(x, block_diag_context->x22_subvector, INSERT_VALUES, SCATTER_FORWARD, block_diag_context->A22_B2_scatter_ctx); 00331 #endif 00332 00333 /* 00334 * y1 = ILU(A11)*x1 00335 * y21 = ILU(A22)*x21 00336 * y22 = AMG(A22)*x22 00337 */ 00338 PCApply(block_diag_context->PC_amg_A11, block_diag_context->x1_subvector, block_diag_context->y1_subvector); 00339 PCApply(block_diag_context->PC_amg_A22_B1, block_diag_context->x21_subvector, block_diag_context->y21_subvector); 00340 PCApply(block_diag_context->PC_amg_A22_B2, block_diag_context->x22_subvector, block_diag_context->y22_subvector); 00341 00342 /* 00343 * Gather y = [y1 y21 y22]' 00344 */ 00345 //PETSc-3.x.x or PETSc-2.3.3 00346 #if ( (PETSC_VERSION_MAJOR == 3) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR == 3)) //2.3.3 or 3.x.x 00347 VecScatterBegin(block_diag_context->A11_scatter_ctx, block_diag_context->y1_subvector, y, INSERT_VALUES, SCATTER_REVERSE); 00348 VecScatterEnd(block_diag_context->A11_scatter_ctx, block_diag_context->y1_subvector, y, INSERT_VALUES, SCATTER_REVERSE); 00349 #else 00350 VecScatterBegin(block_diag_context->y1_subvector, y, INSERT_VALUES, SCATTER_REVERSE, block_diag_context->A11_scatter_ctx); 00351 VecScatterEnd(block_diag_context->y1_subvector, y, INSERT_VALUES, SCATTER_REVERSE, block_diag_context->A11_scatter_ctx); 00352 #endif 00353 00354 //PETSc-3.x.x or PETSc-2.3.3 00355 #if ( (PETSC_VERSION_MAJOR == 3) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR == 3)) //2.3.3 or 3.x.x 00356 VecScatterBegin(block_diag_context->A22_B1_scatter_ctx, block_diag_context->y21_subvector, y, INSERT_VALUES, SCATTER_REVERSE); 00357 VecScatterEnd(block_diag_context->A22_B1_scatter_ctx, block_diag_context->y21_subvector, y, INSERT_VALUES, SCATTER_REVERSE); 00358 #else 00359 VecScatterBegin(block_diag_context->y21_subvector, y, INSERT_VALUES, SCATTER_REVERSE, block_diag_context->A22_B1_scatter_ctx); 00360 VecScatterEnd(block_diag_context->y21_subvector, y, INSERT_VALUES, SCATTER_REVERSE, block_diag_context->A22_B1_scatter_ctx); 00361 #endif 00362 00363 //PETSc-3.x.x or PETSc-2.3.3 00364 #if ( (PETSC_VERSION_MAJOR == 3) || (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 3 && PETSC_VERSION_SUBMINOR == 3)) //2.3.3 or 3.x.x 00365 VecScatterBegin(block_diag_context->A22_B2_scatter_ctx, block_diag_context->y22_subvector, y, INSERT_VALUES, SCATTER_REVERSE); 00366 VecScatterEnd(block_diag_context->A22_B2_scatter_ctx, block_diag_context->y22_subvector, y, INSERT_VALUES, SCATTER_REVERSE); 00367 #else 00368 VecScatterBegin(block_diag_context->y22_subvector, y, INSERT_VALUES, SCATTER_REVERSE, block_diag_context->A22_B2_scatter_ctx); 00369 VecScatterEnd(block_diag_context->y22_subvector, y, INSERT_VALUES, SCATTER_REVERSE, block_diag_context->A22_B2_scatter_ctx); 00370 #endif 00371 00372 return 0; 00373 }