1 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 2 3 #include <../src/mat/impls/aij/seq/aij.h> 4 #include <../src/mat/impls/aij/mpi/mpiaij.h> 5 6 PetscErrorCode MatSetBlockSizes_Default(Mat mat, PetscInt rbs, PetscInt cbs) 7 { 8 PetscFunctionBegin; 9 if (!mat->preallocated) PetscFunctionReturn(PETSC_SUCCESS); 10 PetscCheck(mat->rmap->bs <= 0 || mat->rmap->bs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change row block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->rmap->bs, rbs); 11 PetscCheck(mat->cmap->bs <= 0 || mat->cmap->bs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change column block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->cmap->bs, cbs); 12 PetscFunctionReturn(PETSC_SUCCESS); 13 } 14 15 PetscErrorCode MatShift_Basic(Mat Y, PetscScalar a) 16 { 17 PetscInt i, start, end, oldValA = 0, oldValB = 0; 18 PetscScalar alpha = a; 19 PetscBool prevoption; 20 PetscBool isSeqAIJDerived, isMPIAIJDerived; // all classes sharing SEQAIJHEADER or MPIAIJHEADER 21 Mat A = NULL, B = NULL; 22 23 PetscFunctionBegin; 24 PetscCall(MatGetOption(Y, MAT_NO_OFF_PROC_ENTRIES, &prevoption)); 25 PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 26 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isSeqAIJDerived, MATSEQAIJ, MATSEQBAIJ, MATSEQSBAIJ, "")); 27 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isMPIAIJDerived, MATMPIAIJ, MATMPIBAIJ, MATMPISBAIJ, "")); 28 29 if (isSeqAIJDerived) A = Y; 30 else if (isMPIAIJDerived) { 31 Mat_MPIAIJ *mpiaij = (Mat_MPIAIJ *)Y->data; 32 A = mpiaij->A; 33 B = mpiaij->B; 34 } 35 36 if (A) { 37 oldValA = ((Mat_SeqAIJ *)A->data)->nonew; 38 ((Mat_SeqAIJ *)A->data)->nonew = 0; // so that new nonzero locations are allowed 39 } 40 if (B) { 41 oldValB = ((Mat_SeqAIJ *)B->data)->nonew; 42 ((Mat_SeqAIJ *)B->data)->nonew = 0; 43 } 44 45 PetscCall(MatGetOwnershipRange(Y, &start, &end)); 46 for (i = start; i < end; i++) { 47 if (i < Y->cmap->N) PetscCall(MatSetValues(Y, 1, &i, 1, &i, &alpha, ADD_VALUES)); 48 } 49 PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 50 PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 51 PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, prevoption)); 52 if (A) ((Mat_SeqAIJ *)A->data)->nonew = oldValA; 53 if (B) ((Mat_SeqAIJ *)B->data)->nonew = oldValB; 54 PetscFunctionReturn(PETSC_SUCCESS); 55 } 56 57 /*@ 58 MatCreate - Creates a matrix where the type is determined 59 from either a call to `MatSetType()` or from the options database 60 with a call to `MatSetFromOptions()`. 61 62 Collective 63 64 Input Parameter: 65 . comm - MPI communicator 66 67 Output Parameter: 68 . A - the matrix 69 70 Options Database Keys: 71 + -mat_type seqaij - `MATSEQAIJ` type, uses `MatCreateSeqAIJ()` 72 . -mat_type mpiaij - `MATMPIAIJ` type, uses `MatCreateAIJ()` 73 . -mat_type seqdense - `MATSEQDENSE`, uses `MatCreateSeqDense()` 74 . -mat_type mpidense - `MATMPIDENSE` type, uses `MatCreateDense()` 75 . -mat_type seqbaij - `MATSEQBAIJ` type, uses `MatCreateSeqBAIJ()` 76 - -mat_type mpibaij - `MATMPIBAIJ` type, uses `MatCreateBAIJ()` 77 78 See the manpages for particular formats (e.g., `MATSEQAIJ`) 79 for additional format-specific options. 80 81 Level: beginner 82 83 Notes: 84 The default matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` or 85 `MatCreateAIJ()` if you do not set a type in the options database. If you never call 86 `MatSetType()` or `MatSetFromOptions()` it will generate an error when you try to use the 87 matrix. 88 89 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`, 90 `MatCreateSeqDense()`, `MatCreateDense()`, 91 `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, 92 `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`, 93 `MatConvert()` 94 @*/ 95 PetscErrorCode MatCreate(MPI_Comm comm, Mat *A) 96 { 97 Mat B; 98 99 PetscFunctionBegin; 100 PetscAssertPointer(A, 2); 101 PetscCall(MatInitializePackage()); 102 103 PetscCall(PetscHeaderCreate(B, MAT_CLASSID, "Mat", "Matrix", "Mat", comm, MatDestroy, MatView)); 104 PetscCall(PetscLayoutCreate(comm, &B->rmap)); 105 PetscCall(PetscLayoutCreate(comm, &B->cmap)); 106 PetscCall(PetscStrallocpy(VECSTANDARD, &B->defaultvectype)); 107 PetscCall(PetscStrallocpy(PETSCRANDER48, &B->defaultrandtype)); 108 109 B->symmetric = PETSC_BOOL3_UNKNOWN; 110 B->hermitian = PETSC_BOOL3_UNKNOWN; 111 B->structurally_symmetric = PETSC_BOOL3_UNKNOWN; 112 B->spd = PETSC_BOOL3_UNKNOWN; 113 B->symmetry_eternal = PETSC_FALSE; 114 B->structural_symmetry_eternal = PETSC_FALSE; 115 116 B->congruentlayouts = PETSC_DECIDE; 117 B->preallocated = PETSC_FALSE; 118 #if defined(PETSC_HAVE_DEVICE) 119 B->boundtocpu = PETSC_TRUE; 120 #endif 121 *A = B; 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 /*@ 126 MatCreateFromOptions - Creates a matrix whose type is set from the options database 127 128 Collective 129 130 Input Parameters: 131 + comm - MPI communicator 132 . prefix - [optional] prefix for the options database 133 . bs - the blocksize (commonly 1) 134 . m - the local number of rows (or `PETSC_DECIDE`) 135 . n - the local number of columns (or `PETSC_DECIDE` or `PETSC_DETERMINE`) 136 . M - the global number of rows (or `PETSC_DETERMINE`) 137 - N - the global number of columns (or `PETSC_DETERMINE`) 138 139 Output Parameter: 140 . A - the matrix 141 142 Options Database Key: 143 . -mat_type - see `MatType`, for example `aij`, `aijcusparse`, `baij`, `sbaij`, dense, defaults to `aij` 144 145 Level: beginner 146 147 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`, 148 `MatCreateSeqDense()`, `MatCreateDense()`, 149 `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, 150 `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`, 151 `MatConvert()`, `MatCreate()` 152 @*/ 153 PetscErrorCode MatCreateFromOptions(MPI_Comm comm, const char *prefix, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, Mat *A) 154 { 155 PetscFunctionBegin; 156 PetscAssertPointer(A, 8); 157 PetscCall(MatCreate(comm, A)); 158 if (prefix) PetscCall(MatSetOptionsPrefix(*A, prefix)); 159 PetscCall(MatSetBlockSize(*A, bs)); 160 PetscCall(MatSetSizes(*A, m, n, M, N)); 161 PetscCall(MatSetFromOptions(*A)); 162 PetscFunctionReturn(PETSC_SUCCESS); 163 } 164 165 /*@ 166 MatSetErrorIfFailure - Causes `Mat` to generate an immediate error, for example a zero pivot, is detected. 167 168 Logically Collective 169 170 Input Parameters: 171 + mat - matrix obtained from `MatCreate()` 172 - flg - `PETSC_TRUE` indicates you want the error generated 173 174 Level: advanced 175 176 Note: 177 If this flag is not set then the matrix operation will note the error and continue. The error may cause a later `PC` or `KSP` error 178 or result in a `KSPConvergedReason` indicating the method did not converge. 179 180 .seealso: [](ch_matrices), `Mat`, `PCSetErrorIfFailure()`, `KSPConvergedReason`, `SNESConvergedReason` 181 @*/ 182 PetscErrorCode MatSetErrorIfFailure(Mat mat, PetscBool flg) 183 { 184 PetscFunctionBegin; 185 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 186 PetscValidLogicalCollectiveBool(mat, flg, 2); 187 mat->erroriffailure = flg; 188 PetscFunctionReturn(PETSC_SUCCESS); 189 } 190 191 /*@ 192 MatSetSizes - Sets the local and global sizes, and checks to determine compatibility 193 194 Collective 195 196 Input Parameters: 197 + A - the matrix 198 . m - number of local rows (or `PETSC_DECIDE`) 199 . n - number of local columns (or `PETSC_DECIDE`) 200 . M - number of global rows (or `PETSC_DETERMINE`) 201 - N - number of global columns (or `PETSC_DETERMINE`) 202 203 Level: beginner 204 205 Notes: 206 `m` (`n`) and `M` (`N`) cannot be both `PETSC_DECIDE` 207 If one processor calls this with `M` (`N`) of `PETSC_DECIDE` then all processors must, otherwise the program will hang. 208 209 If `PETSC_DECIDE` is not used for the arguments 'm' and 'n', then the 210 user must ensure that they are chosen to be compatible with the 211 vectors. To do this, one first considers the matrix-vector product 212 'y = A x'. The `m` that is used in the above routine must match the 213 local size of 'y'. Likewise, the `n` used must match the local size of 'x'. 214 215 If `m` and `n` are not `PETSC_DECIDE`, then the values determine the `PetscLayout` of the matrix and the ranges returned by 216 `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, and `MatGetOwnershipRangesColumn()`. 217 218 You cannot change the sizes once they have been set. 219 220 The sizes must be set before `MatSetUp()` or MatXXXSetPreallocation() is called. 221 222 .seealso: [](ch_matrices), `Mat`, `MatGetSize()`, `PetscSplitOwnership()`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, 223 `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`, `VecSetSizes()` 224 @*/ 225 PetscErrorCode MatSetSizes(Mat A, PetscInt m, PetscInt n, PetscInt M, PetscInt N) 226 { 227 PetscFunctionBegin; 228 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 229 PetscValidLogicalCollectiveInt(A, M, 4); 230 PetscValidLogicalCollectiveInt(A, N, 5); 231 PetscCheck(M <= 0 || m <= M, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local row size %" PetscInt_FMT " cannot be larger than global row size %" PetscInt_FMT, m, M); 232 PetscCheck(N <= 0 || n <= N, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local column size %" PetscInt_FMT " cannot be larger than global column size %" PetscInt_FMT, n, N); 233 PetscCheck((A->rmap->n < 0 || A->rmap->N < 0) || (A->rmap->n == m && (M <= 0 || A->rmap->N == M)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset row sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", m, M, 234 A->rmap->n, A->rmap->N); 235 PetscCheck((A->cmap->n < 0 || A->cmap->N < 0) || (A->cmap->n == n && (N <= 0 || A->cmap->N == N)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset column sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", n, N, 236 A->cmap->n, A->cmap->N); 237 A->rmap->n = m; 238 A->cmap->n = n; 239 A->rmap->N = M > -1 ? M : A->rmap->N; 240 A->cmap->N = N > -1 ? N : A->cmap->N; 241 PetscFunctionReturn(PETSC_SUCCESS); 242 } 243 244 /*@ 245 MatSetFromOptions - Creates a matrix where the type is determined 246 from the options database. 247 248 Collective 249 250 Input Parameter: 251 . B - the matrix 252 253 Options Database Keys: 254 + -mat_type seqaij - `MATSEQAIJ` type, uses `MatCreateSeqAIJ()` 255 . -mat_type mpiaij - `MATMPIAIJ` type, uses `MatCreateAIJ()` 256 . -mat_type seqdense - `MATSEQDENSE` type, uses `MatCreateSeqDense()` 257 . -mat_type mpidense - `MATMPIDENSE`, uses `MatCreateDense()` 258 . -mat_type seqbaij - `MATSEQBAIJ`, uses `MatCreateSeqBAIJ()` 259 - -mat_type mpibaij - `MATMPIBAIJ`, uses `MatCreateBAIJ()` 260 261 See the manpages for particular formats (e.g., `MATSEQAIJ`) 262 for additional format-specific options. 263 264 Level: beginner 265 266 Notes: 267 Generates a parallel MPI matrix if the communicator has more than one processor. The default 268 matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` and `MatCreateAIJ()` if you 269 do not select a type in the options database. 270 271 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`, 272 `MatCreateSeqDense()`, `MatCreateDense()`, 273 `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, 274 `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`, 275 `MatConvert()` 276 @*/ 277 PetscErrorCode MatSetFromOptions(Mat B) 278 { 279 const char *deft = MATAIJ; 280 char type[256]; 281 PetscBool flg, set; 282 PetscInt bind_below = 0; 283 284 PetscFunctionBegin; 285 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 286 287 PetscObjectOptionsBegin((PetscObject)B); 288 289 if (B->rmap->bs < 0) { 290 PetscInt newbs = -1; 291 PetscCall(PetscOptionsInt("-mat_block_size", "Set the blocksize used to store the matrix", "MatSetBlockSize", newbs, &newbs, &flg)); 292 if (flg) { 293 PetscCall(PetscLayoutSetBlockSize(B->rmap, newbs)); 294 PetscCall(PetscLayoutSetBlockSize(B->cmap, newbs)); 295 } 296 } 297 298 PetscCall(PetscOptionsFList("-mat_type", "Matrix type", "MatSetType", MatList, deft, type, 256, &flg)); 299 if (flg) { 300 PetscCall(MatSetType(B, type)); 301 } else if (!((PetscObject)B)->type_name) { 302 PetscCall(MatSetType(B, deft)); 303 } 304 305 PetscCall(PetscOptionsName("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", &B->checksymmetryonassembly)); 306 PetscCall(PetscOptionsReal("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", B->checksymmetrytol, &B->checksymmetrytol, NULL)); 307 PetscCall(PetscOptionsBool("-mat_null_space_test", "Checks if provided null space is correct in MatAssemblyEnd()", "MatSetNullSpaceTest", B->checknullspaceonassembly, &B->checknullspaceonassembly, NULL)); 308 PetscCall(PetscOptionsBool("-mat_error_if_failure", "Generate an error if an error occurs when factoring the matrix", "MatSetErrorIfFailure", B->erroriffailure, &B->erroriffailure, NULL)); 309 310 PetscTryTypeMethod(B, setfromoptions, PetscOptionsObject); 311 312 flg = PETSC_FALSE; 313 PetscCall(PetscOptionsBool("-mat_new_nonzero_location_err", "Generate an error if new nonzeros are created in the matrix nonzero structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set)); 314 if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, flg)); 315 flg = PETSC_FALSE; 316 PetscCall(PetscOptionsBool("-mat_new_nonzero_allocation_err", "Generate an error if new nonzeros are allocated in the matrix nonzero structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set)); 317 if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, flg)); 318 flg = PETSC_FALSE; 319 PetscCall(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)); 320 if (set) PetscCall(MatSetOption(B, MAT_IGNORE_ZERO_ENTRIES, flg)); 321 322 flg = PETSC_FALSE; 323 PetscCall(PetscOptionsBool("-mat_form_explicit_transpose", "Hint to form an explicit transpose for operations like MatMultTranspose", "MatSetOption", flg, &flg, &set)); 324 if (set) PetscCall(MatSetOption(B, MAT_FORM_EXPLICIT_TRANSPOSE, flg)); 325 326 /* Bind to CPU if below a user-specified size threshold. 327 * This perhaps belongs in the options for the GPU Mat types, but MatBindToCPU() does nothing when called on non-GPU types, 328 * and putting it here makes is more maintainable than duplicating this for all. */ 329 PetscCall(PetscOptionsInt("-mat_bind_below", "Set the size threshold (in local rows) below which the Mat is bound to the CPU", "MatBindToCPU", bind_below, &bind_below, &flg)); 330 if (flg && B->rmap->n < bind_below) PetscCall(MatBindToCPU(B, PETSC_TRUE)); 331 332 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 333 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)B, PetscOptionsObject)); 334 PetscOptionsEnd(); 335 PetscFunctionReturn(PETSC_SUCCESS); 336 } 337 338 /*@ 339 MatXAIJSetPreallocation - set preallocation for serial and parallel `MATAIJ`, `MATBAIJ`, and `MATSBAIJ` matrices and their unassembled versions. 340 341 Collective 342 343 Input Parameters: 344 + A - matrix being preallocated 345 . bs - block size 346 . dnnz - number of nonzero column blocks per block row of diagonal part of parallel matrix 347 . onnz - number of nonzero column blocks per block row of off-diagonal part of parallel matrix 348 . dnnzu - number of nonzero column blocks per block row of upper-triangular part of diagonal part of parallel matrix 349 - onnzu - number of nonzero column blocks per block row of upper-triangular part of off-diagonal part of parallel matrix 350 351 Level: beginner 352 353 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`, `MatMPIBAIJSetPreallocation()`, 354 `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, 355 `PetscSplitOwnership()` 356 @*/ 357 PetscErrorCode MatXAIJSetPreallocation(Mat A, PetscInt bs, const PetscInt dnnz[], const PetscInt onnz[], const PetscInt dnnzu[], const PetscInt onnzu[]) 358 { 359 PetscInt cbs; 360 PetscBool aij, is, hyp; 361 362 PetscFunctionBegin; 363 if (bs != PETSC_DECIDE) { /* don't mess with an already set block size */ 364 PetscCall(MatSetBlockSize(A, bs)); 365 } 366 PetscCall(PetscLayoutSetUp(A->rmap)); 367 PetscCall(PetscLayoutSetUp(A->cmap)); 368 PetscCall(MatGetBlockSizes(A, &bs, &cbs)); 369 /* these routines assumes bs == cbs, this should be checked somehow */ 370 PetscCall(MatSeqBAIJSetPreallocation(A, bs, 0, dnnz)); 371 PetscCall(MatMPIBAIJSetPreallocation(A, bs, 0, dnnz, 0, onnz)); 372 PetscCall(MatSeqSBAIJSetPreallocation(A, bs, 0, dnnzu)); 373 PetscCall(MatMPISBAIJSetPreallocation(A, bs, 0, dnnzu, 0, onnzu)); 374 /* 375 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 376 good before going on with it. 377 */ 378 PetscCall(PetscObjectHasFunction((PetscObject)A, "MatMPIAIJSetPreallocation_C", &aij)); 379 PetscCall(PetscObjectHasFunction((PetscObject)A, "MatISSetPreallocation_C", &is)); 380 PetscCall(PetscObjectHasFunction((PetscObject)A, "MatHYPRESetPreallocation_C", &hyp)); 381 if (!aij && !is && !hyp) PetscCall(PetscObjectHasFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", &aij)); 382 if (aij || is || hyp) { 383 if (bs == cbs && bs == 1) { 384 PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz)); 385 PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz, 0, onnz)); 386 PetscCall(MatISSetPreallocation(A, 0, dnnz, 0, onnz)); 387 #if defined(PETSC_HAVE_HYPRE) 388 PetscCall(MatHYPRESetPreallocation(A, 0, dnnz, 0, onnz)); 389 #endif 390 } else { /* Convert block-row precallocation to scalar-row */ 391 PetscInt i, m, *sdnnz, *sonnz; 392 PetscCall(MatGetLocalSize(A, &m, NULL)); 393 PetscCall(PetscMalloc2((!!dnnz) * m, &sdnnz, (!!onnz) * m, &sonnz)); 394 for (i = 0; i < m; i++) { 395 if (dnnz) sdnnz[i] = dnnz[i / bs] * cbs; 396 if (onnz) sonnz[i] = onnz[i / bs] * cbs; 397 } 398 PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL)); 399 PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL)); 400 PetscCall(MatISSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL)); 401 #if defined(PETSC_HAVE_HYPRE) 402 PetscCall(MatHYPRESetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL)); 403 #endif 404 PetscCall(PetscFree2(sdnnz, sonnz)); 405 } 406 } 407 PetscFunctionReturn(PETSC_SUCCESS); 408 } 409 410 /*@C 411 MatHeaderMerge - Merges some information from the header of `C` to `A`; the `C` object is then destroyed 412 413 Collective, No Fortran Support 414 415 Input Parameters: 416 + A - a `Mat` being merged into 417 - C - the `Mat` providing the merge information 418 419 Level: developer 420 421 Notes: 422 `A` and `C` must be of the same type. 423 The object list and query function list in `A` are retained, as well as the object name, and prefix. 424 The object state of `A` is increased by 1. 425 426 Developer Note: 427 This is somewhat different from `MatHeaderReplace()`, it would be nice to merge the code 428 429 .seealso: `Mat`, `MatHeaderReplace()` 430 @*/ 431 PetscErrorCode MatHeaderMerge(Mat A, Mat *C) 432 { 433 PetscInt refct; 434 PetscOps Abops; 435 struct _MatOps Aops; 436 char *mtype, *mname, *mprefix; 437 Mat_Product *product; 438 Mat_Redundant *redundant; 439 PetscObjectState state; 440 PetscObjectList olist; 441 PetscFunctionList qlist; 442 443 PetscFunctionBegin; 444 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 445 PetscValidHeaderSpecific(*C, MAT_CLASSID, 2); 446 if (A == *C) PetscFunctionReturn(PETSC_SUCCESS); 447 PetscCheckSameTypeAndComm(A, 1, *C, 2); 448 /* save the parts of A we need */ 449 Abops = ((PetscObject)A)->bops[0]; 450 Aops = A->ops[0]; 451 refct = ((PetscObject)A)->refct; 452 mtype = ((PetscObject)A)->type_name; 453 mname = ((PetscObject)A)->name; 454 state = ((PetscObject)A)->state; 455 mprefix = ((PetscObject)A)->prefix; 456 product = A->product; 457 redundant = A->redundant; 458 qlist = ((PetscObject)A)->qlist; 459 olist = ((PetscObject)A)->olist; 460 461 /* zero these so the destroy below does not free them */ 462 ((PetscObject)A)->type_name = NULL; 463 ((PetscObject)A)->name = NULL; 464 ((PetscObject)A)->qlist = NULL; 465 ((PetscObject)A)->olist = NULL; 466 467 /* 468 free all the interior data structures from mat 469 cannot use PetscUseTypeMethod(A,destroy); because compiler 470 thinks it may print NULL type_name and name 471 */ 472 PetscTryTypeMethod(A, destroy); 473 474 PetscCall(PetscFree(A->defaultvectype)); 475 PetscCall(PetscFree(A->defaultrandtype)); 476 PetscCall(PetscLayoutDestroy(&A->rmap)); 477 PetscCall(PetscLayoutDestroy(&A->cmap)); 478 PetscCall(PetscComposedQuantitiesDestroy((PetscObject)A)); 479 480 /* copy C over to A */ 481 PetscCall(PetscFree(A->factorprefix)); 482 PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat))); 483 484 /* return the parts of A we saved */ 485 ((PetscObject)A)->bops[0] = Abops; 486 A->ops[0] = Aops; 487 ((PetscObject)A)->refct = refct; 488 ((PetscObject)A)->type_name = mtype; 489 ((PetscObject)A)->name = mname; 490 ((PetscObject)A)->prefix = mprefix; 491 ((PetscObject)A)->state = state + 1; 492 A->product = product; 493 A->redundant = redundant; 494 495 /* Append the saved lists */ 496 PetscCall(PetscFunctionListDuplicate(qlist, &((PetscObject)A)->qlist)); 497 PetscCall(PetscObjectListDuplicate(olist, &((PetscObject)A)->olist)); 498 PetscCall(PetscFunctionListDestroy(&qlist)); 499 PetscCall(PetscObjectListDestroy(&olist)); 500 501 /* since these two are copied into A we do not want them destroyed in C */ 502 ((PetscObject)*C)->qlist = NULL; 503 ((PetscObject)*C)->olist = NULL; 504 PetscCall(PetscHeaderDestroy(C)); 505 PetscFunctionReturn(PETSC_SUCCESS); 506 } 507 508 /*@ 509 MatHeaderReplace - Replaces the internal data of matrix `A` by the internal data of matrix `C` while deleting the outer wrapper of `C` 510 511 Input Parameters: 512 + A - a `Mat` whose internal data is to be replaced 513 - C - the `Mat` providing new internal data for `A` 514 515 Level: advanced 516 517 Example Usage\: 518 .vb 519 Mat C; 520 MatCreateSeqAIJWithArrays(..., &C); 521 MatHeaderReplace(A, &C); 522 // C has been destroyed and A contains the matrix entries of C 523 .ve 524 525 Note: 526 This can be used inside a function provided to `SNESSetJacobian()`, `TSSetRHSJacobian()`, or `TSSetIJacobian()` in cases where the user code 527 computes an entirely new sparse matrix (generally with a different matrix nonzero structure/pattern) for each Newton update. 528 It is usually better to reuse the matrix nonzero structure of `A` instead of constructing an entirely new one. 529 530 Developer Note: 531 This is somewhat different from `MatHeaderMerge()` it would be nice to merge the code 532 533 .seealso: `Mat`, `MatHeaderMerge()` 534 @*/ 535 PetscErrorCode MatHeaderReplace(Mat A, Mat *C) 536 { 537 PetscInt refct; 538 PetscObjectState state; 539 struct _p_Mat buffer; 540 MatStencilInfo stencil; 541 542 PetscFunctionBegin; 543 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 544 PetscValidHeaderSpecific(*C, MAT_CLASSID, 2); 545 if (A == *C) PetscFunctionReturn(PETSC_SUCCESS); 546 PetscCheckSameComm(A, 1, *C, 2); 547 PetscCheck(((PetscObject)*C)->refct == 1, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Object C has refct %" PetscInt_FMT " > 1, would leave hanging reference", ((PetscObject)*C)->refct); 548 549 /* swap C and A */ 550 refct = ((PetscObject)A)->refct; 551 state = ((PetscObject)A)->state; 552 stencil = A->stencil; 553 PetscCall(PetscMemcpy(&buffer, A, sizeof(struct _p_Mat))); 554 PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat))); 555 PetscCall(PetscMemcpy(*C, &buffer, sizeof(struct _p_Mat))); 556 ((PetscObject)A)->refct = refct; 557 ((PetscObject)A)->state = state + 1; 558 A->stencil = stencil; 559 560 ((PetscObject)*C)->refct = 1; 561 PetscCall(MatDestroy(C)); 562 PetscFunctionReturn(PETSC_SUCCESS); 563 } 564 565 /*@ 566 MatBindToCPU - marks a matrix to temporarily stay on the CPU and perform computations on the CPU 567 568 Logically Collective 569 570 Input Parameters: 571 + A - the matrix 572 - flg - bind to the CPU if value of `PETSC_TRUE` 573 574 Level: intermediate 575 576 .seealso: [](ch_matrices), `Mat`, `MatBoundToCPU()` 577 @*/ 578 PetscErrorCode MatBindToCPU(Mat A, PetscBool flg) 579 { 580 PetscFunctionBegin; 581 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 582 PetscValidLogicalCollectiveBool(A, flg, 2); 583 #if defined(PETSC_HAVE_DEVICE) 584 if (A->boundtocpu == flg) PetscFunctionReturn(PETSC_SUCCESS); 585 A->boundtocpu = flg; 586 PetscTryTypeMethod(A, bindtocpu, flg); 587 #endif 588 PetscFunctionReturn(PETSC_SUCCESS); 589 } 590 591 /*@ 592 MatBoundToCPU - query if a matrix is bound to the CPU 593 594 Input Parameter: 595 . A - the matrix 596 597 Output Parameter: 598 . flg - the logical flag 599 600 Level: intermediate 601 602 .seealso: [](ch_matrices), `Mat`, `MatBindToCPU()` 603 @*/ 604 PetscErrorCode MatBoundToCPU(Mat A, PetscBool *flg) 605 { 606 PetscFunctionBegin; 607 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 608 PetscAssertPointer(flg, 2); 609 #if defined(PETSC_HAVE_DEVICE) 610 *flg = A->boundtocpu; 611 #else 612 *flg = PETSC_TRUE; 613 #endif 614 PetscFunctionReturn(PETSC_SUCCESS); 615 } 616 617 PetscErrorCode MatSetValuesCOO_Basic(Mat A, const PetscScalar coo_v[], InsertMode imode) 618 { 619 IS is_coo_i, is_coo_j; 620 const PetscInt *coo_i, *coo_j; 621 PetscInt n, n_i, n_j; 622 PetscScalar zero = 0.; 623 624 PetscFunctionBegin; 625 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_i", (PetscObject *)&is_coo_i)); 626 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_j", (PetscObject *)&is_coo_j)); 627 PetscCheck(is_coo_i, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_i IS"); 628 PetscCheck(is_coo_j, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_j IS"); 629 PetscCall(ISGetLocalSize(is_coo_i, &n_i)); 630 PetscCall(ISGetLocalSize(is_coo_j, &n_j)); 631 PetscCheck(n_i == n_j, PETSC_COMM_SELF, PETSC_ERR_COR, "Wrong local size %" PetscInt_FMT " != %" PetscInt_FMT, n_i, n_j); 632 PetscCall(ISGetIndices(is_coo_i, &coo_i)); 633 PetscCall(ISGetIndices(is_coo_j, &coo_j)); 634 if (imode != ADD_VALUES) PetscCall(MatZeroEntries(A)); 635 for (n = 0; n < n_i; n++) PetscCall(MatSetValue(A, coo_i[n], coo_j[n], coo_v ? coo_v[n] : zero, ADD_VALUES)); 636 PetscCall(ISRestoreIndices(is_coo_i, &coo_i)); 637 PetscCall(ISRestoreIndices(is_coo_j, &coo_j)); 638 PetscFunctionReturn(PETSC_SUCCESS); 639 } 640 641 PetscErrorCode MatSetPreallocationCOO_Basic(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) 642 { 643 Mat preallocator; 644 IS is_coo_i, is_coo_j; 645 PetscInt ncoo_i; 646 PetscScalar zero = 0.0; 647 648 PetscFunctionBegin; 649 PetscCall(PetscIntCast(ncoo, &ncoo_i)); 650 PetscCall(PetscLayoutSetUp(A->rmap)); 651 PetscCall(PetscLayoutSetUp(A->cmap)); 652 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &preallocator)); 653 PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 654 PetscCall(MatSetSizes(preallocator, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N)); 655 PetscCall(MatSetLayouts(preallocator, A->rmap, A->cmap)); 656 PetscCall(MatSetUp(preallocator)); 657 for (PetscCount n = 0; n < ncoo; n++) PetscCall(MatSetValue(preallocator, coo_i[n], coo_j[n], zero, INSERT_VALUES)); 658 PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 659 PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 660 PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, A)); 661 PetscCall(MatDestroy(&preallocator)); 662 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_i, PETSC_COPY_VALUES, &is_coo_i)); 663 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_j, PETSC_COPY_VALUES, &is_coo_j)); 664 PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_i", (PetscObject)is_coo_i)); 665 PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_j", (PetscObject)is_coo_j)); 666 PetscCall(ISDestroy(&is_coo_i)); 667 PetscCall(ISDestroy(&is_coo_j)); 668 PetscFunctionReturn(PETSC_SUCCESS); 669 } 670 671 /*@C 672 MatSetPreallocationCOO - set preallocation for matrices using a coordinate format of the entries with global indices 673 674 Collective 675 676 Input Parameters: 677 + A - matrix being preallocated 678 . ncoo - number of entries 679 . coo_i - row indices 680 - coo_j - column indices 681 682 Level: beginner 683 684 Notes: 685 The indices within `coo_i` and `coo_j` may be modified within this function. The caller should not rely on them 686 having any specific value after this function returns. The arrays can be freed or reused immediately 687 after this function returns. 688 689 Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed 690 but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries 691 are allowed and will be properly added or inserted to the matrix, unless the matrix option `MAT_IGNORE_OFF_PROC_ENTRIES` 692 is set, in which case remote entries are ignored, or `MAT_NO_OFF_PROC_ENTRIES` is set, in which case an error will be generated. 693 694 If you just want to create a sequential AIJ matrix (`MATSEQAIJ`), and your matrix entries in COO format are unique, you can also use 695 `MatCreateSeqAIJFromTriple()`. But that is not recommended for iterative applications. 696 697 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`, 698 `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOOLocal()`, 699 `DMSetMatrixPreallocateSkip()`, `MatCreateSeqAIJFromTriple()` 700 @*/ 701 PetscErrorCode MatSetPreallocationCOO(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) 702 { 703 PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL; 704 705 PetscFunctionBegin; 706 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 707 PetscValidType(A, 1); 708 if (ncoo) PetscAssertPointer(coo_i, 3); 709 if (ncoo) PetscAssertPointer(coo_j, 4); 710 PetscCall(PetscLayoutSetUp(A->rmap)); 711 PetscCall(PetscLayoutSetUp(A->cmap)); 712 PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOO_C", &f)); 713 714 PetscCall(PetscLogEventBegin(MAT_PreallCOO, A, 0, 0, 0)); 715 if (f) { 716 PetscCall((*f)(A, ncoo, coo_i, coo_j)); 717 } else { /* allow fallback, very slow */ 718 PetscCall(MatSetPreallocationCOO_Basic(A, ncoo, coo_i, coo_j)); 719 } 720 PetscCall(PetscLogEventEnd(MAT_PreallCOO, A, 0, 0, 0)); 721 A->preallocated = PETSC_TRUE; 722 A->nonzerostate++; 723 PetscFunctionReturn(PETSC_SUCCESS); 724 } 725 726 /*@C 727 MatSetPreallocationCOOLocal - set preallocation for matrices using a coordinate format of the entries with local indices 728 729 Collective 730 731 Input Parameters: 732 + A - matrix being preallocated 733 . ncoo - number of entries 734 . coo_i - row indices (local numbering; may be modified) 735 - coo_j - column indices (local numbering; may be modified) 736 737 Level: beginner 738 739 Notes: 740 The local indices are translated using the local to global mapping, thus `MatSetLocalToGlobalMapping()` must have been 741 called prior to this function. For matrices created with `DMCreateMatrix()` the local to global mapping is often already provided. 742 743 The indices `coo_i` and `coo_j` may be modified within this function. They might be translated to corresponding global 744 indices, but the caller should not rely on them having any specific value after this function returns. The arrays 745 can be freed or reused immediately after this function returns. 746 747 Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed 748 but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries 749 are allowed and will be properly added or inserted to the matrix. 750 751 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`, 752 `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOO()`, 753 `DMSetMatrixPreallocateSkip()` 754 @*/ 755 PetscErrorCode MatSetPreallocationCOOLocal(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) 756 { 757 PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL; 758 759 PetscFunctionBegin; 760 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 761 PetscValidType(A, 1); 762 if (ncoo) PetscAssertPointer(coo_i, 3); 763 if (ncoo) PetscAssertPointer(coo_j, 4); 764 PetscCall(PetscLayoutSetUp(A->rmap)); 765 PetscCall(PetscLayoutSetUp(A->cmap)); 766 767 PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", &f)); 768 if (f) { 769 PetscCall((*f)(A, ncoo, coo_i, coo_j)); 770 A->nonzerostate++; 771 } else { 772 PetscInt ncoo_i; 773 ISLocalToGlobalMapping ltog_row, ltog_col; 774 775 PetscCall(MatGetLocalToGlobalMapping(A, <og_row, <og_col)); 776 if (ltog_row) { 777 PetscCall(PetscIntCast(ncoo, &ncoo_i)); 778 PetscCall(ISLocalToGlobalMappingApply(ltog_row, ncoo_i, coo_i, coo_i)); 779 } 780 if (ltog_col) { 781 PetscCall(PetscIntCast(ncoo, &ncoo_i)); 782 PetscCall(ISLocalToGlobalMappingApply(ltog_col, ncoo_i, coo_j, coo_j)); 783 } 784 PetscCall(MatSetPreallocationCOO(A, ncoo, coo_i, coo_j)); 785 } 786 A->preallocated = PETSC_TRUE; 787 PetscFunctionReturn(PETSC_SUCCESS); 788 } 789 790 /*@ 791 MatSetValuesCOO - set values at once in a matrix preallocated using `MatSetPreallocationCOO()` 792 793 Collective 794 795 Input Parameters: 796 + A - matrix being preallocated 797 . coo_v - the matrix values (can be `NULL`) 798 - imode - the insert mode 799 800 Level: beginner 801 802 Notes: 803 The values must follow the order of the indices prescribed with `MatSetPreallocationCOO()` or `MatSetPreallocationCOOLocal()`. 804 805 When repeated entries are specified in the COO indices the `coo_v` values are first properly summed, regardless of the value of imode. 806 The imode flag indicates if coo_v must be added to the current values of the matrix (`ADD_VALUES`) or overwritten (`INSERT_VALUES`). 807 808 `MatAssemblyBegin()` and `MatAssemblyEnd()` do not need to be called after this routine. It automatically handles the assembly process. 809 810 .seealso: [](ch_matrices), `Mat`, `MatSetPreallocationCOO()`, `MatSetPreallocationCOOLocal()`, `InsertMode`, `INSERT_VALUES`, `ADD_VALUES` 811 @*/ 812 PetscErrorCode MatSetValuesCOO(Mat A, const PetscScalar coo_v[], InsertMode imode) 813 { 814 PetscErrorCode (*f)(Mat, const PetscScalar[], InsertMode) = NULL; 815 PetscBool oldFlg; 816 817 PetscFunctionBegin; 818 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 819 PetscValidType(A, 1); 820 MatCheckPreallocated(A, 1); 821 PetscValidLogicalCollectiveEnum(A, imode, 3); 822 PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetValuesCOO_C", &f)); 823 PetscCall(PetscLogEventBegin(MAT_SetVCOO, A, 0, 0, 0)); 824 if (f) { 825 PetscCall((*f)(A, coo_v, imode)); // all known COO implementations do not use MatStash. They do their own off-proc communication 826 PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &oldFlg)); 827 PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); // set A->nooffprocentries to avoid costly MatStash scatter in MatAssembly 828 } else { 829 PetscCall(MatSetValuesCOO_Basic(A, coo_v, imode)); // fall back to MatSetValues, which might use MatStash 830 } 831 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 832 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 833 if (f) PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, oldFlg)); 834 PetscCall(PetscLogEventEnd(MAT_SetVCOO, A, 0, 0, 0)); 835 PetscFunctionReturn(PETSC_SUCCESS); 836 } 837 838 /*@ 839 MatSetBindingPropagates - Sets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects 840 841 Input Parameters: 842 + A - the matrix 843 - flg - flag indicating whether the boundtocpu flag should be propagated 844 845 Level: developer 846 847 Notes: 848 If the value of flg is set to true, the following will occur 849 + `MatCreateSubMatrices()` and `MatCreateRedundantMatrix()` - bind created matrices to CPU if the input matrix is bound to the CPU. 850 - `MatCreateVecs()` - bind created vectors to CPU if the input matrix is bound to the CPU. 851 852 The bindingpropagates flag itself is also propagated by the above routines. 853 854 Developer Notes: 855 If the fine-scale `DMDA` has the `-dm_bind_below` option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()` 856 on the restriction/interpolation operator to set the bindingpropagates flag to true. 857 858 .seealso: [](ch_matrices), `Mat`, `VecSetBindingPropagates()`, `MatGetBindingPropagates()` 859 @*/ 860 PetscErrorCode MatSetBindingPropagates(Mat A, PetscBool flg) 861 { 862 PetscFunctionBegin; 863 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 864 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP) 865 A->bindingpropagates = flg; 866 #endif 867 PetscFunctionReturn(PETSC_SUCCESS); 868 } 869 870 /*@ 871 MatGetBindingPropagates - Gets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects 872 873 Input Parameter: 874 . A - the matrix 875 876 Output Parameter: 877 . flg - flag indicating whether the boundtocpu flag will be propagated 878 879 Level: developer 880 881 .seealso: [](ch_matrices), `Mat`, `MatSetBindingPropagates()` 882 @*/ 883 PetscErrorCode MatGetBindingPropagates(Mat A, PetscBool *flg) 884 { 885 PetscFunctionBegin; 886 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 887 PetscAssertPointer(flg, 2); 888 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP) 889 *flg = A->bindingpropagates; 890 #else 891 *flg = PETSC_FALSE; 892 #endif 893 PetscFunctionReturn(PETSC_SUCCESS); 894 } 895