1 2 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 3 4 PETSC_INTERN PetscErrorCode MatSetBlockSizes_Default(Mat mat,PetscInt rbs, PetscInt cbs) 5 { 6 PetscFunctionBegin; 7 if (!mat->preallocated) PetscFunctionReturn(0); 8 if (mat->rmap->bs > 0 && mat->rmap->bs != rbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot change row block size %D to %D\n",mat->rmap->bs,rbs); 9 if (mat->cmap->bs > 0 && mat->cmap->bs != cbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot change column block size %D to %D\n",mat->cmap->bs,cbs); 10 PetscFunctionReturn(0); 11 } 12 13 PETSC_INTERN PetscErrorCode MatShift_Basic(Mat Y,PetscScalar a) 14 { 15 PetscErrorCode ierr; 16 PetscInt i,start,end; 17 PetscScalar alpha = a; 18 PetscBool prevoption; 19 20 PetscFunctionBegin; 21 ierr = MatGetOption(Y,MAT_NO_OFF_PROC_ENTRIES,&prevoption);CHKERRQ(ierr); 22 ierr = MatSetOption(Y,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);CHKERRQ(ierr); 23 ierr = MatGetOwnershipRange(Y,&start,&end);CHKERRQ(ierr); 24 for (i=start; i<end; i++) { 25 if (i < Y->cmap->N) { 26 ierr = MatSetValues(Y,1,&i,1,&i,&alpha,ADD_VALUES);CHKERRQ(ierr); 27 } 28 } 29 ierr = MatAssemblyBegin(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 30 ierr = MatAssemblyEnd(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 31 ierr = MatSetOption(Y,MAT_NO_OFF_PROC_ENTRIES,prevoption);CHKERRQ(ierr); 32 PetscFunctionReturn(0); 33 } 34 35 /*@ 36 MatCreate - Creates a matrix where the type is determined 37 from either a call to MatSetType() or from the options database 38 with a call to MatSetFromOptions(). The default matrix type is 39 AIJ, using the routines MatCreateSeqAIJ() or MatCreateAIJ() 40 if you do not set a type in the options database. If you never 41 call MatSetType() or MatSetFromOptions() it will generate an 42 error when you try to use the matrix. 43 44 Collective 45 46 Input Parameter: 47 . comm - MPI communicator 48 49 Output Parameter: 50 . A - the matrix 51 52 Options Database Keys: 53 + -mat_type seqaij - AIJ type, uses MatCreateSeqAIJ() 54 . -mat_type mpiaij - AIJ type, uses MatCreateAIJ() 55 . -mat_type seqdense - dense type, uses MatCreateSeqDense() 56 . -mat_type mpidense - dense type, uses MatCreateDense() 57 . -mat_type seqbaij - block AIJ type, uses MatCreateSeqBAIJ() 58 - -mat_type mpibaij - block AIJ type, uses MatCreateBAIJ() 59 60 Even More Options Database Keys: 61 See the manpages for particular formats (e.g., MatCreateSeqAIJ()) 62 for additional format-specific options. 63 64 Level: beginner 65 66 .seealso: MatCreateSeqAIJ(), MatCreateAIJ(), 67 MatCreateSeqDense(), MatCreateDense(), 68 MatCreateSeqBAIJ(), MatCreateBAIJ(), 69 MatCreateSeqSBAIJ(), MatCreateSBAIJ(), 70 MatConvert() 71 @*/ 72 PetscErrorCode MatCreate(MPI_Comm comm,Mat *A) 73 { 74 Mat B; 75 PetscErrorCode ierr; 76 77 PetscFunctionBegin; 78 PetscValidPointer(A,2); 79 80 *A = NULL; 81 ierr = MatInitializePackage();CHKERRQ(ierr); 82 83 ierr = PetscHeaderCreate(B,MAT_CLASSID,"Mat","Matrix","Mat",comm,MatDestroy,MatView);CHKERRQ(ierr); 84 ierr = PetscLayoutCreate(comm,&B->rmap);CHKERRQ(ierr); 85 ierr = PetscLayoutCreate(comm,&B->cmap);CHKERRQ(ierr); 86 ierr = PetscStrallocpy(VECSTANDARD,&B->defaultvectype);CHKERRQ(ierr); 87 88 B->congruentlayouts = PETSC_DECIDE; 89 B->preallocated = PETSC_FALSE; 90 *A = B; 91 PetscFunctionReturn(0); 92 } 93 94 /*@ 95 MatSetErrorIfFailure - Causes Mat to generate an error, for example a zero pivot, is detected. 96 97 Logically Collective on Mat 98 99 Input Parameters: 100 + mat - matrix obtained from MatCreate() 101 - flg - PETSC_TRUE indicates you want the error generated 102 103 Level: advanced 104 105 .seealso: PCSetErrorIfFailure() 106 @*/ 107 PetscErrorCode MatSetErrorIfFailure(Mat mat,PetscBool flg) 108 { 109 PetscFunctionBegin; 110 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 111 PetscValidLogicalCollectiveBool(mat,flg,2); 112 mat->erroriffailure = flg; 113 PetscFunctionReturn(0); 114 } 115 116 /*@ 117 MatSetSizes - Sets the local and global sizes, and checks to determine compatibility 118 119 Collective on Mat 120 121 Input Parameters: 122 + A - the matrix 123 . m - number of local rows (or PETSC_DECIDE) 124 . n - number of local columns (or PETSC_DECIDE) 125 . M - number of global rows (or PETSC_DETERMINE) 126 - N - number of global columns (or PETSC_DETERMINE) 127 128 Notes: 129 m (n) and M (N) cannot be both PETSC_DECIDE 130 If one processor calls this with M (N) of PETSC_DECIDE then all processors must, otherwise the program will hang. 131 132 If PETSC_DECIDE is not used for the arguments 'm' and 'n', then the 133 user must ensure that they are chosen to be compatible with the 134 vectors. To do this, one first considers the matrix-vector product 135 'y = A x'. The 'm' that is used in the above routine must match the 136 local size used in the vector creation routine VecCreateMPI() for 'y'. 137 Likewise, the 'n' used must match that used as the local size in 138 VecCreateMPI() for 'x'. 139 140 You cannot change the sizes once they have been set. 141 142 The sizes must be set before MatSetUp() or MatXXXSetPreallocation() is called. 143 144 Level: beginner 145 146 .seealso: MatGetSize(), PetscSplitOwnership() 147 @*/ 148 PetscErrorCode MatSetSizes(Mat A, PetscInt m, PetscInt n, PetscInt M, PetscInt N) 149 { 150 PetscFunctionBegin; 151 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 152 PetscValidLogicalCollectiveInt(A,M,4); 153 PetscValidLogicalCollectiveInt(A,N,5); 154 if (M > 0 && m > M) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local row size %D cannot be larger than global row size %D",m,M); 155 if (N > 0 && n > N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local column size %D cannot be larger than global column size %D",n,N); 156 if ((A->rmap->n >= 0 && A->rmap->N >= 0) && (A->rmap->n != m || (M > 0 && A->rmap->N != M))) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot change/reset row sizes to %D local %D global after previously setting them to %D local %D global",m,M,A->rmap->n,A->rmap->N); 157 if ((A->cmap->n >= 0 && A->cmap->N >= 0) && (A->cmap->n != n || (N > 0 && A->cmap->N != N))) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot change/reset column sizes to %D local %D global after previously setting them to %D local %D global",n,N,A->cmap->n,A->cmap->N); 158 A->rmap->n = m; 159 A->cmap->n = n; 160 A->rmap->N = M > -1 ? M : A->rmap->N; 161 A->cmap->N = N > -1 ? N : A->cmap->N; 162 PetscFunctionReturn(0); 163 } 164 165 /*@ 166 MatSetFromOptions - Creates a matrix where the type is determined 167 from the options database. Generates a parallel MPI matrix if the 168 communicator has more than one processor. The default matrix type is 169 AIJ, using the routines MatCreateSeqAIJ() and MatCreateAIJ() if 170 you do not select a type in the options database. 171 172 Collective on Mat 173 174 Input Parameter: 175 . A - the matrix 176 177 Options Database Keys: 178 + -mat_type seqaij - AIJ type, uses MatCreateSeqAIJ() 179 . -mat_type mpiaij - AIJ type, uses MatCreateAIJ() 180 . -mat_type seqdense - dense type, uses MatCreateSeqDense() 181 . -mat_type mpidense - dense type, uses MatCreateDense() 182 . -mat_type seqbaij - block AIJ type, uses MatCreateSeqBAIJ() 183 - -mat_type mpibaij - block AIJ type, uses MatCreateBAIJ() 184 185 Even More Options Database Keys: 186 See the manpages for particular formats (e.g., MatCreateSeqAIJ()) 187 for additional format-specific options. 188 189 Level: beginner 190 191 .seealso: MatCreateSeqAIJ((), MatCreateAIJ(), 192 MatCreateSeqDense(), MatCreateDense(), 193 MatCreateSeqBAIJ(), MatCreateBAIJ(), 194 MatCreateSeqSBAIJ(), MatCreateSBAIJ(), 195 MatConvert() 196 @*/ 197 PetscErrorCode MatSetFromOptions(Mat B) 198 { 199 PetscErrorCode ierr; 200 const char *deft = MATAIJ; 201 char type[256]; 202 PetscBool flg,set; 203 204 PetscFunctionBegin; 205 PetscValidHeaderSpecific(B,MAT_CLASSID,1); 206 207 ierr = PetscObjectOptionsBegin((PetscObject)B);CHKERRQ(ierr); 208 209 if (B->rmap->bs < 0) { 210 PetscInt newbs = -1; 211 ierr = PetscOptionsInt("-mat_block_size","Set the blocksize used to store the matrix","MatSetBlockSize",newbs,&newbs,&flg);CHKERRQ(ierr); 212 if (flg) { 213 ierr = PetscLayoutSetBlockSize(B->rmap,newbs);CHKERRQ(ierr); 214 ierr = PetscLayoutSetBlockSize(B->cmap,newbs);CHKERRQ(ierr); 215 } 216 } 217 218 ierr = PetscOptionsFList("-mat_type","Matrix type","MatSetType",MatList,deft,type,256,&flg);CHKERRQ(ierr); 219 if (flg) { 220 ierr = MatSetType(B,type);CHKERRQ(ierr); 221 } else if (!((PetscObject)B)->type_name) { 222 ierr = MatSetType(B,deft);CHKERRQ(ierr); 223 } 224 225 ierr = PetscOptionsName("-mat_is_symmetric","Checks if mat is symmetric on MatAssemblyEnd()","MatIsSymmetric",&B->checksymmetryonassembly);CHKERRQ(ierr); 226 ierr = PetscOptionsReal("-mat_is_symmetric","Checks if mat is symmetric on MatAssemblyEnd()","MatIsSymmetric",B->checksymmetrytol,&B->checksymmetrytol,NULL);CHKERRQ(ierr); 227 ierr = PetscOptionsBool("-mat_null_space_test","Checks if provided null space is correct in MatAssemblyEnd()","MatSetNullSpaceTest",B->checknullspaceonassembly,&B->checknullspaceonassembly,NULL);CHKERRQ(ierr); 228 ierr = PetscOptionsBool("-mat_error_if_failure","Generate an error if an error occurs when factoring the matrix","MatSetErrorIfFailure",B->erroriffailure,&B->erroriffailure,NULL);CHKERRQ(ierr); 229 230 if (B->ops->setfromoptions) { 231 ierr = (*B->ops->setfromoptions)(PetscOptionsObject,B);CHKERRQ(ierr); 232 } 233 234 flg = PETSC_FALSE; 235 ierr = PetscOptionsBool("-mat_new_nonzero_location_err","Generate an error if new nonzeros are created in the matrix structure (useful to test preallocation)","MatSetOption",flg,&flg,&set);CHKERRQ(ierr); 236 if (set) {ierr = MatSetOption(B,MAT_NEW_NONZERO_LOCATION_ERR,flg);CHKERRQ(ierr);} 237 flg = PETSC_FALSE; 238 ierr = PetscOptionsBool("-mat_new_nonzero_allocation_err","Generate an error if new nonzeros are allocated in the matrix structure (useful to test preallocation)","MatSetOption",flg,&flg,&set);CHKERRQ(ierr); 239 if (set) {ierr = MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR,flg);CHKERRQ(ierr);} 240 flg = PETSC_FALSE; 241 ierr = PetscOptionsBool("-mat_ignore_zero_entries","For AIJ/IS matrices this will stop zero values from creating a zero location in the matrix","MatSetOption",flg,&flg,&set);CHKERRQ(ierr); 242 if (set) {ierr = MatSetOption(B,MAT_IGNORE_ZERO_ENTRIES,flg);CHKERRQ(ierr);} 243 244 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 245 ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)B);CHKERRQ(ierr); 246 ierr = PetscOptionsEnd();CHKERRQ(ierr); 247 PetscFunctionReturn(0); 248 } 249 250 /*@C 251 MatXAIJSetPreallocation - set preallocation for serial and parallel AIJ, BAIJ, and SBAIJ matrices and their unassembled versions. 252 253 Collective on Mat 254 255 Input Arguments: 256 + A - matrix being preallocated 257 . bs - block size 258 . dnnz - number of nonzero column blocks per block row of diagonal part of parallel matrix 259 . onnz - number of nonzero column blocks per block row of off-diagonal part of parallel matrix 260 . dnnzu - number of nonzero column blocks per block row of upper-triangular part of diagonal part of parallel matrix 261 - onnzu - number of nonzero column blocks per block row of upper-triangular part of off-diagonal part of parallel matrix 262 263 Level: beginner 264 265 .seealso: MatSeqAIJSetPreallocation(), MatMPIAIJSetPreallocation(), MatSeqBAIJSetPreallocation(), MatMPIBAIJSetPreallocation(), MatSeqSBAIJSetPreallocation(), MatMPISBAIJSetPreallocation(), 266 PetscSplitOwnership() 267 @*/ 268 PetscErrorCode MatXAIJSetPreallocation(Mat A,PetscInt bs,const PetscInt dnnz[],const PetscInt onnz[],const PetscInt dnnzu[],const PetscInt onnzu[]) 269 { 270 PetscErrorCode ierr; 271 PetscInt cbs; 272 void (*aij)(void); 273 void (*is)(void); 274 void (*hyp)(void) = NULL; 275 276 PetscFunctionBegin; 277 if (bs != PETSC_DECIDE) { /* don't mess with an already set block size */ 278 ierr = MatSetBlockSize(A,bs);CHKERRQ(ierr); 279 } 280 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 281 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 282 ierr = MatGetBlockSizes(A,&bs,&cbs);CHKERRQ(ierr); 283 /* these routines assumes bs == cbs, this should be checked somehow */ 284 ierr = MatSeqBAIJSetPreallocation(A,bs,0,dnnz);CHKERRQ(ierr); 285 ierr = MatMPIBAIJSetPreallocation(A,bs,0,dnnz,0,onnz);CHKERRQ(ierr); 286 ierr = MatSeqSBAIJSetPreallocation(A,bs,0,dnnzu);CHKERRQ(ierr); 287 ierr = MatMPISBAIJSetPreallocation(A,bs,0,dnnzu,0,onnzu);CHKERRQ(ierr); 288 /* 289 In general, we have to do extra work to preallocate for scalar (AIJ) or unassembled (IS) matrices so we check whether it will do any 290 good before going on with it. 291 */ 292 ierr = PetscObjectQueryFunction((PetscObject)A,"MatMPIAIJSetPreallocation_C",&aij);CHKERRQ(ierr); 293 ierr = PetscObjectQueryFunction((PetscObject)A,"MatISSetPreallocation_C",&is);CHKERRQ(ierr); 294 #if defined(PETSC_HAVE_HYPRE) 295 ierr = PetscObjectQueryFunction((PetscObject)A,"MatHYPRESetPreallocation_C",&hyp);CHKERRQ(ierr); 296 #endif 297 if (!aij && !is && !hyp) { 298 ierr = PetscObjectQueryFunction((PetscObject)A,"MatSeqAIJSetPreallocation_C",&aij);CHKERRQ(ierr); 299 } 300 if (aij || is || hyp) { 301 if (bs == cbs && bs == 1) { 302 ierr = MatSeqAIJSetPreallocation(A,0,dnnz);CHKERRQ(ierr); 303 ierr = MatMPIAIJSetPreallocation(A,0,dnnz,0,onnz);CHKERRQ(ierr); 304 ierr = MatISSetPreallocation(A,0,dnnz,0,onnz);CHKERRQ(ierr); 305 #if defined(PETSC_HAVE_HYPRE) 306 ierr = MatHYPRESetPreallocation(A,0,dnnz,0,onnz);CHKERRQ(ierr); 307 #endif 308 } else { /* Convert block-row precallocation to scalar-row */ 309 PetscInt i,m,*sdnnz,*sonnz; 310 ierr = MatGetLocalSize(A,&m,NULL);CHKERRQ(ierr); 311 ierr = PetscMalloc2((!!dnnz)*m,&sdnnz,(!!onnz)*m,&sonnz);CHKERRQ(ierr); 312 for (i=0; i<m; i++) { 313 if (dnnz) sdnnz[i] = dnnz[i/bs] * cbs; 314 if (onnz) sonnz[i] = onnz[i/bs] * cbs; 315 } 316 ierr = MatSeqAIJSetPreallocation(A,0,dnnz ? sdnnz : NULL);CHKERRQ(ierr); 317 ierr = MatMPIAIJSetPreallocation(A,0,dnnz ? sdnnz : NULL,0,onnz ? sonnz : NULL);CHKERRQ(ierr); 318 ierr = MatISSetPreallocation(A,0,dnnz ? sdnnz : NULL,0,onnz ? sonnz : NULL);CHKERRQ(ierr); 319 #if defined(PETSC_HAVE_HYPRE) 320 ierr = MatHYPRESetPreallocation(A,0,dnnz ? sdnnz : NULL,0,onnz ? sonnz : NULL);CHKERRQ(ierr); 321 #endif 322 ierr = PetscFree2(sdnnz,sonnz);CHKERRQ(ierr); 323 } 324 } 325 PetscFunctionReturn(0); 326 } 327 328 /* 329 Merges some information from Cs header to A; the C object is then destroyed 330 331 This is somewhat different from MatHeaderReplace() it would be nice to merge the code 332 */ 333 PetscErrorCode MatHeaderMerge(Mat A,Mat *C) 334 { 335 PetscErrorCode ierr; 336 PetscInt refct; 337 PetscOps Abops; 338 struct _MatOps Aops; 339 char *mtype,*mname,*mprefix; 340 Mat_Product *product; 341 342 PetscFunctionBegin; 343 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 344 PetscValidHeaderSpecific(*C,MAT_CLASSID,2); 345 if (A == *C) PetscFunctionReturn(0); 346 PetscCheckSameComm(A,1,*C,2); 347 /* save the parts of A we need */ 348 Abops = ((PetscObject)A)->bops[0]; 349 Aops = A->ops[0]; 350 refct = ((PetscObject)A)->refct; 351 mtype = ((PetscObject)A)->type_name; 352 mname = ((PetscObject)A)->name; 353 mprefix = ((PetscObject)A)->prefix; 354 product = A->product; 355 356 /* zero these so the destroy below does not free them */ 357 ((PetscObject)A)->type_name = NULL; 358 ((PetscObject)A)->name = NULL; 359 360 /* free all the interior data structures from mat */ 361 ierr = (*A->ops->destroy)(A);CHKERRQ(ierr); 362 363 ierr = PetscFree(A->defaultvectype);CHKERRQ(ierr); 364 ierr = PetscLayoutDestroy(&A->rmap);CHKERRQ(ierr); 365 ierr = PetscLayoutDestroy(&A->cmap);CHKERRQ(ierr); 366 ierr = PetscFunctionListDestroy(&((PetscObject)A)->qlist);CHKERRQ(ierr); 367 ierr = PetscObjectListDestroy(&((PetscObject)A)->olist);CHKERRQ(ierr); 368 369 /* copy C over to A */ 370 ierr = PetscMemcpy(A,*C,sizeof(struct _p_Mat));CHKERRQ(ierr); 371 372 /* return the parts of A we saved */ 373 ((PetscObject)A)->bops[0] = Abops; 374 A->ops[0] = Aops; 375 ((PetscObject)A)->refct = refct; 376 ((PetscObject)A)->type_name = mtype; 377 ((PetscObject)A)->name = mname; 378 ((PetscObject)A)->prefix = mprefix; 379 A->product = product; 380 381 /* since these two are copied into A we do not want them destroyed in C */ 382 ((PetscObject)*C)->qlist = NULL; 383 ((PetscObject)*C)->olist = NULL; 384 385 ierr = PetscHeaderDestroy(C);CHKERRQ(ierr); 386 PetscFunctionReturn(0); 387 } 388 /* 389 Replace A's header with that of C; the C object is then destroyed 390 391 This is essentially code moved from MatDestroy() 392 393 This is somewhat different from MatHeaderMerge() it would be nice to merge the code 394 395 Used in DM hence is declared PETSC_EXTERN 396 */ 397 PETSC_EXTERN PetscErrorCode MatHeaderReplace(Mat A,Mat *C) 398 { 399 PetscErrorCode ierr; 400 PetscInt refct; 401 PetscObjectState state; 402 struct _p_Mat buffer; 403 MatStencilInfo stencil; 404 405 PetscFunctionBegin; 406 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 407 PetscValidHeaderSpecific(*C,MAT_CLASSID,2); 408 if (A == *C) PetscFunctionReturn(0); 409 PetscCheckSameComm(A,1,*C,2); 410 if (((PetscObject)*C)->refct != 1) SETERRQ1(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Object C has refct %D > 1, would leave hanging reference",((PetscObject)*C)->refct); 411 412 /* swap C and A */ 413 refct = ((PetscObject)A)->refct; 414 state = ((PetscObject)A)->state; 415 stencil = A->stencil; 416 ierr = PetscMemcpy(&buffer,A,sizeof(struct _p_Mat));CHKERRQ(ierr); 417 ierr = PetscMemcpy(A,*C,sizeof(struct _p_Mat));CHKERRQ(ierr); 418 ierr = PetscMemcpy(*C,&buffer,sizeof(struct _p_Mat));CHKERRQ(ierr); 419 ((PetscObject)A)->refct = refct; 420 ((PetscObject)A)->state = state + 1; 421 A->stencil = stencil; 422 423 ((PetscObject)*C)->refct = 1; 424 ierr = MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))NULL);CHKERRQ(ierr); 425 ierr = MatDestroy(C);CHKERRQ(ierr); 426 PetscFunctionReturn(0); 427 } 428 429 /*@ 430 MatBindToCPU - marks a matrix to temporarily stay on the CPU and perform computations on the CPU 431 432 Input Parameters: 433 + A - the matrix 434 - flg - bind to the CPU if value of PETSC_TRUE 435 436 Level: intermediate 437 @*/ 438 PetscErrorCode MatBindToCPU(Mat A,PetscBool flg) 439 { 440 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) 441 PetscErrorCode ierr; 442 443 PetscFunctionBegin; 444 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 445 PetscValidLogicalCollectiveBool(A,flg,2); 446 if (A->boundtocpu == flg) PetscFunctionReturn(0); 447 A->boundtocpu = flg; 448 if (A->ops->bindtocpu) { 449 ierr = (*A->ops->bindtocpu)(A,flg);CHKERRQ(ierr); 450 } 451 PetscFunctionReturn(0); 452 #else 453 PetscFunctionBegin; 454 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 455 PetscValidLogicalCollectiveBool(A,flg,2); 456 PetscFunctionReturn(0); 457 #endif 458 } 459