1 #include <petscdmshell.h> /*I "petscdmshell.h" I*/ 2 #include <petscmat.h> 3 #include <petsc/private/dmimpl.h> 4 5 typedef struct { 6 Vec Xglobal; 7 Vec Xlocal; 8 Mat A; 9 VecScatter gtol; 10 VecScatter ltog; 11 VecScatter ltol; 12 void *ctx; 13 PetscErrorCode (*destroyctx)(void *); 14 } DM_Shell; 15 16 /*@ 17 DMGlobalToLocalBeginDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to begin a global to local scatter 18 Collective 19 20 Input Parameters: 21 + dm - shell DM 22 . g - global vector 23 . mode - InsertMode 24 - l - local vector 25 26 Level: advanced 27 28 Note: This is not normally called directly by user code, generally user code calls DMGlobalToLocalBegin() and DMGlobalToLocalEnd(). If the user provides their own custom routines to DMShellSetLocalToGlobal() then those routines might have reason to call this function. 29 30 .seealso: `DMGlobalToLocalEndDefaultShell()` 31 @*/ 32 PetscErrorCode DMGlobalToLocalBeginDefaultShell(DM dm, Vec g, InsertMode mode, Vec l) 33 { 34 DM_Shell *shell = (DM_Shell *)dm->data; 35 36 PetscFunctionBegin; 37 PetscCheck(shell->gtol, ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()"); 38 PetscCall(VecScatterBegin(shell->gtol, g, l, mode, SCATTER_FORWARD)); 39 PetscFunctionReturn(PETSC_SUCCESS); 40 } 41 42 /*@ 43 DMGlobalToLocalEndDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to end a global to local scatter 44 Collective 45 46 Input Parameters: 47 + dm - shell DM 48 . g - global vector 49 . mode - InsertMode 50 - l - local vector 51 52 Level: advanced 53 54 .seealso: `DMGlobalToLocalBeginDefaultShell()` 55 @*/ 56 PetscErrorCode DMGlobalToLocalEndDefaultShell(DM dm, Vec g, InsertMode mode, Vec l) 57 { 58 DM_Shell *shell = (DM_Shell *)dm->data; 59 60 PetscFunctionBegin; 61 PetscCheck(shell->gtol, ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()"); 62 PetscCall(VecScatterEnd(shell->gtol, g, l, mode, SCATTER_FORWARD)); 63 PetscFunctionReturn(PETSC_SUCCESS); 64 } 65 66 /*@ 67 DMLocalToGlobalBeginDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to begin a local to global scatter 68 Collective 69 70 Input Parameters: 71 + dm - shell DM 72 . l - local vector 73 . mode - InsertMode 74 - g - global vector 75 76 Level: advanced 77 78 Note: This is not normally called directly by user code, generally user code calls DMLocalToGlobalBegin() and DMLocalToGlobalEnd(). If the user provides their own custom routines to DMShellSetLocalToGlobal() then those routines might have reason to call this function. 79 80 .seealso: `DMLocalToGlobalEndDefaultShell()` 81 @*/ 82 PetscErrorCode DMLocalToGlobalBeginDefaultShell(DM dm, Vec l, InsertMode mode, Vec g) 83 { 84 DM_Shell *shell = (DM_Shell *)dm->data; 85 86 PetscFunctionBegin; 87 PetscCheck(shell->ltog, ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToGlobalVecScatter()"); 88 PetscCall(VecScatterBegin(shell->ltog, l, g, mode, SCATTER_FORWARD)); 89 PetscFunctionReturn(PETSC_SUCCESS); 90 } 91 92 /*@ 93 DMLocalToGlobalEndDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to end a local to global scatter 94 Collective 95 96 Input Parameters: 97 + dm - shell DM 98 . l - local vector 99 . mode - InsertMode 100 - g - global vector 101 102 Level: advanced 103 104 .seealso: `DMLocalToGlobalBeginDefaultShell()` 105 @*/ 106 PetscErrorCode DMLocalToGlobalEndDefaultShell(DM dm, Vec l, InsertMode mode, Vec g) 107 { 108 DM_Shell *shell = (DM_Shell *)dm->data; 109 110 PetscFunctionBegin; 111 PetscCheck(shell->ltog, ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToGlobalVecScatter()"); 112 PetscCall(VecScatterEnd(shell->ltog, l, g, mode, SCATTER_FORWARD)); 113 PetscFunctionReturn(PETSC_SUCCESS); 114 } 115 116 /*@ 117 DMLocalToLocalBeginDefaultShell - Uses the LocalToLocal VecScatter context set by the user to begin a local to local scatter 118 Collective 119 120 Input Parameters: 121 + dm - shell DM 122 . g - the original local vector 123 - mode - InsertMode 124 125 Output Parameter: 126 . l - the local vector with correct ghost values 127 128 Level: advanced 129 130 Note: This is not normally called directly by user code, generally user code calls DMLocalToLocalBegin() and DMLocalToLocalEnd(). If the user provides their own custom routines to DMShellSetLocalToLocal() then those routines might have reason to call this function. 131 132 .seealso: `DMLocalToLocalEndDefaultShell()` 133 @*/ 134 PetscErrorCode DMLocalToLocalBeginDefaultShell(DM dm, Vec g, InsertMode mode, Vec l) 135 { 136 DM_Shell *shell = (DM_Shell *)dm->data; 137 138 PetscFunctionBegin; 139 PetscCheck(shell->ltol, ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToLocalVecScatter()"); 140 PetscCall(VecScatterBegin(shell->ltol, g, l, mode, SCATTER_FORWARD)); 141 PetscFunctionReturn(PETSC_SUCCESS); 142 } 143 144 /*@ 145 DMLocalToLocalEndDefaultShell - Uses the LocalToLocal VecScatter context set by the user to end a local to local scatter 146 Collective 147 148 Input Parameters: 149 + dm - shell DM 150 . g - the original local vector 151 - mode - InsertMode 152 153 Output Parameter: 154 . l - the local vector with correct ghost values 155 156 Level: advanced 157 158 .seealso: `DMLocalToLocalBeginDefaultShell()` 159 @*/ 160 PetscErrorCode DMLocalToLocalEndDefaultShell(DM dm, Vec g, InsertMode mode, Vec l) 161 { 162 DM_Shell *shell = (DM_Shell *)dm->data; 163 164 PetscFunctionBegin; 165 PetscCheck(shell->ltol, ((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()"); 166 PetscCall(VecScatterEnd(shell->ltol, g, l, mode, SCATTER_FORWARD)); 167 PetscFunctionReturn(PETSC_SUCCESS); 168 } 169 170 static PetscErrorCode DMCreateMatrix_Shell(DM dm, Mat *J) 171 { 172 DM_Shell *shell = (DM_Shell *)dm->data; 173 Mat A; 174 175 PetscFunctionBegin; 176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 177 PetscValidPointer(J, 2); 178 if (!shell->A) { 179 if (shell->Xglobal) { 180 PetscInt m, M; 181 PetscCall(PetscInfo(dm, "Naively creating matrix using global vector distribution without preallocation\n")); 182 PetscCall(VecGetSize(shell->Xglobal, &M)); 183 PetscCall(VecGetLocalSize(shell->Xglobal, &m)); 184 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), &shell->A)); 185 PetscCall(MatSetSizes(shell->A, m, m, M, M)); 186 PetscCall(MatSetType(shell->A, dm->mattype)); 187 PetscCall(MatSetUp(shell->A)); 188 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMShellSetMatrix(), DMShellSetCreateMatrix(), or provide a vector"); 189 } 190 A = shell->A; 191 PetscCall(MatDuplicate(A, MAT_SHARE_NONZERO_PATTERN, J)); 192 PetscCall(MatSetDM(*J, dm)); 193 PetscFunctionReturn(PETSC_SUCCESS); 194 } 195 196 PetscErrorCode DMCreateGlobalVector_Shell(DM dm, Vec *gvec) 197 { 198 DM_Shell *shell = (DM_Shell *)dm->data; 199 Vec X; 200 201 PetscFunctionBegin; 202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 203 PetscValidPointer(gvec, 2); 204 *gvec = NULL; 205 X = shell->Xglobal; 206 PetscCheck(X, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMShellSetGlobalVector() or DMShellSetCreateGlobalVector()"); 207 /* Need to create a copy in order to attach the DM to the vector */ 208 PetscCall(VecDuplicate(X, gvec)); 209 PetscCall(VecZeroEntries(*gvec)); 210 PetscCall(VecSetDM(*gvec, dm)); 211 PetscFunctionReturn(PETSC_SUCCESS); 212 } 213 214 PetscErrorCode DMCreateLocalVector_Shell(DM dm, Vec *gvec) 215 { 216 DM_Shell *shell = (DM_Shell *)dm->data; 217 Vec X; 218 219 PetscFunctionBegin; 220 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 221 PetscValidPointer(gvec, 2); 222 *gvec = NULL; 223 X = shell->Xlocal; 224 PetscCheck(X, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMShellSetLocalVector() or DMShellSetCreateLocalVector()"); 225 /* Need to create a copy in order to attach the DM to the vector */ 226 PetscCall(VecDuplicate(X, gvec)); 227 PetscCall(VecZeroEntries(*gvec)); 228 PetscCall(VecSetDM(*gvec, dm)); 229 PetscFunctionReturn(PETSC_SUCCESS); 230 } 231 232 /*@ 233 DMShellSetDestroyContext - set a function that destroys the context provided with `DMShellSetContext()` 234 235 Collective 236 237 Input Parameters: 238 . ctx - the context 239 240 Level: advanced 241 242 .seealso: `DMShellSetContext()`, `DMShellGetContext()` 243 @*/ 244 PetscErrorCode DMShellSetDestroyContext(DM dm, PetscErrorCode (*destroyctx)(void *)) 245 { 246 DM_Shell *shell = (DM_Shell *)dm->data; 247 PetscBool isshell; 248 249 PetscFunctionBegin; 250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 251 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 252 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 253 shell->destroyctx = destroyctx; 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 DMShellSetContext - set some data to be usable by this DM 259 260 Collective 261 262 Input Parameters: 263 + dm - shell DM 264 - ctx - the context 265 266 Level: advanced 267 268 .seealso: `DMCreateMatrix()`, `DMShellGetContext()` 269 @*/ 270 PetscErrorCode DMShellSetContext(DM dm, void *ctx) 271 { 272 DM_Shell *shell = (DM_Shell *)dm->data; 273 PetscBool isshell; 274 275 PetscFunctionBegin; 276 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 277 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 278 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 279 shell->ctx = ctx; 280 PetscFunctionReturn(PETSC_SUCCESS); 281 } 282 283 /*@ 284 DMShellGetContext - Returns the user-provided context associated to the DM 285 286 Collective 287 288 Input Parameter: 289 . dm - shell DM 290 291 Output Parameter: 292 . ctx - the context 293 294 Level: advanced 295 296 .seealso: `DMCreateMatrix()`, `DMShellSetContext()` 297 @*/ 298 PetscErrorCode DMShellGetContext(DM dm, void *ctx) 299 { 300 DM_Shell *shell = (DM_Shell *)dm->data; 301 PetscBool isshell; 302 303 PetscFunctionBegin; 304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 305 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 306 PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs"); 307 *(void **)ctx = shell->ctx; 308 PetscFunctionReturn(PETSC_SUCCESS); 309 } 310 311 /*@ 312 DMShellSetMatrix - sets a template matrix associated with the DMShell 313 314 Collective 315 316 Input Parameters: 317 + dm - shell DM 318 - J - template matrix 319 320 Level: advanced 321 322 Developer Notes: 323 To avoid circular references, if J is already associated to the same DM, then MatDuplicate(SHARE_NONZERO_PATTERN) is called, followed by removing the DM reference from the private template. 324 325 .seealso: `DMCreateMatrix()`, `DMShellSetCreateMatrix()`, `DMShellSetContext()`, `DMShellGetContext()` 326 @*/ 327 PetscErrorCode DMShellSetMatrix(DM dm, Mat J) 328 { 329 DM_Shell *shell = (DM_Shell *)dm->data; 330 PetscBool isshell; 331 DM mdm; 332 333 PetscFunctionBegin; 334 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 335 PetscValidHeaderSpecific(J, MAT_CLASSID, 2); 336 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 337 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 338 if (J == shell->A) PetscFunctionReturn(PETSC_SUCCESS); 339 PetscCall(MatGetDM(J, &mdm)); 340 PetscCall(PetscObjectReference((PetscObject)J)); 341 PetscCall(MatDestroy(&shell->A)); 342 if (mdm == dm) { 343 PetscCall(MatDuplicate(J, MAT_SHARE_NONZERO_PATTERN, &shell->A)); 344 PetscCall(MatSetDM(shell->A, NULL)); 345 } else shell->A = J; 346 PetscFunctionReturn(PETSC_SUCCESS); 347 } 348 349 /*@C 350 DMShellSetCreateMatrix - sets the routine to create a matrix associated with the shell DM 351 352 Logically Collective on dm 353 354 Input Parameters: 355 + dm - the shell DM 356 - func - the function to create a matrix 357 358 Level: advanced 359 360 .seealso: `DMCreateMatrix()`, `DMShellSetMatrix()`, `DMShellSetContext()`, `DMShellGetContext()` 361 @*/ 362 PetscErrorCode DMShellSetCreateMatrix(DM dm, PetscErrorCode (*func)(DM, Mat *)) 363 { 364 PetscFunctionBegin; 365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 366 dm->ops->creatematrix = func; 367 PetscFunctionReturn(PETSC_SUCCESS); 368 } 369 370 /*@ 371 DMShellSetGlobalVector - sets a template global vector associated with the DMShell 372 373 Logically Collective on dm 374 375 Input Parameters: 376 + dm - shell DM 377 - X - template vector 378 379 Level: advanced 380 381 .seealso: `DMCreateGlobalVector()`, `DMShellSetMatrix()`, `DMShellSetCreateGlobalVector()` 382 @*/ 383 PetscErrorCode DMShellSetGlobalVector(DM dm, Vec X) 384 { 385 DM_Shell *shell = (DM_Shell *)dm->data; 386 PetscBool isshell; 387 DM vdm; 388 389 PetscFunctionBegin; 390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 391 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 392 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 393 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 394 PetscCall(VecGetDM(X, &vdm)); 395 /* 396 if the vector proposed as the new base global vector for the DM is a DM vector associated 397 with the same DM then the current base global vector for the DM is ok and if we replace it with the new one 398 we get a circular dependency that prevents the DM from being destroy when it should be. 399 This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided 400 DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries 401 to set its input vector (which is associated with the DM) as the base global vector. 402 Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien 403 for pointing out the problem. 404 */ 405 if (vdm == dm) PetscFunctionReturn(PETSC_SUCCESS); 406 PetscCall(PetscObjectReference((PetscObject)X)); 407 PetscCall(VecDestroy(&shell->Xglobal)); 408 shell->Xglobal = X; 409 PetscFunctionReturn(PETSC_SUCCESS); 410 } 411 412 /*@ 413 DMShellGetGlobalVector - Returns the template global vector associated with the DMShell, or NULL if it was not set 414 415 Not collective 416 417 Input Parameters: 418 + dm - shell DM 419 - X - template vector 420 421 Level: advanced 422 423 .seealso: `DMShellSetGlobalVector()`, `DMShellSetCreateGlobalVector()`, `DMCreateGlobalVector()` 424 @*/ 425 PetscErrorCode DMShellGetGlobalVector(DM dm, Vec *X) 426 { 427 DM_Shell *shell = (DM_Shell *)dm->data; 428 PetscBool isshell; 429 430 PetscFunctionBegin; 431 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 432 PetscValidPointer(X, 2); 433 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 434 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 435 *X = shell->Xglobal; 436 PetscFunctionReturn(PETSC_SUCCESS); 437 } 438 439 /*@C 440 DMShellSetCreateGlobalVector - sets the routine to create a global vector associated with the shell DM 441 442 Logically Collective 443 444 Input Parameters: 445 + dm - the shell DM 446 - func - the creation routine 447 448 Level: advanced 449 450 .seealso: `DMShellSetGlobalVector()`, `DMShellSetCreateMatrix()`, `DMShellSetContext()`, `DMShellGetContext()` 451 @*/ 452 PetscErrorCode DMShellSetCreateGlobalVector(DM dm, PetscErrorCode (*func)(DM, Vec *)) 453 { 454 PetscFunctionBegin; 455 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 456 dm->ops->createglobalvector = func; 457 PetscFunctionReturn(PETSC_SUCCESS); 458 } 459 460 /*@ 461 DMShellSetLocalVector - sets a template local vector associated with the DMShell 462 463 Logically Collective on dm 464 465 Input Parameters: 466 + dm - shell DM 467 - X - template vector 468 469 Level: advanced 470 471 .seealso: `DMCreateLocalVector()`, `DMShellSetMatrix()`, `DMShellSetCreateLocalVector()` 472 @*/ 473 PetscErrorCode DMShellSetLocalVector(DM dm, Vec X) 474 { 475 DM_Shell *shell = (DM_Shell *)dm->data; 476 PetscBool isshell; 477 DM vdm; 478 479 PetscFunctionBegin; 480 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 481 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 482 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 483 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 484 PetscCall(VecGetDM(X, &vdm)); 485 /* 486 if the vector proposed as the new base global vector for the DM is a DM vector associated 487 with the same DM then the current base global vector for the DM is ok and if we replace it with the new one 488 we get a circular dependency that prevents the DM from being destroy when it should be. 489 This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided 490 DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries 491 to set its input vector (which is associated with the DM) as the base global vector. 492 Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien 493 for pointing out the problem. 494 */ 495 if (vdm == dm) PetscFunctionReturn(PETSC_SUCCESS); 496 PetscCall(PetscObjectReference((PetscObject)X)); 497 PetscCall(VecDestroy(&shell->Xlocal)); 498 shell->Xlocal = X; 499 PetscFunctionReturn(PETSC_SUCCESS); 500 } 501 502 /*@C 503 DMShellSetCreateLocalVector - sets the routine to create a local vector associated with the shell DM 504 505 Logically Collective 506 507 Input Parameters: 508 + dm - the shell DM 509 - func - the creation routine 510 511 Level: advanced 512 513 .seealso: `DMShellSetLocalVector()`, `DMShellSetCreateMatrix()`, `DMShellSetContext()`, `DMShellGetContext()` 514 @*/ 515 PetscErrorCode DMShellSetCreateLocalVector(DM dm, PetscErrorCode (*func)(DM, Vec *)) 516 { 517 PetscFunctionBegin; 518 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 519 dm->ops->createlocalvector = func; 520 PetscFunctionReturn(PETSC_SUCCESS); 521 } 522 523 /*@C 524 DMShellSetGlobalToLocal - Sets the routines used to perform a global to local scatter 525 526 Logically Collective on dm 527 528 Input Parameters 529 + dm - the shell DM 530 . begin - the routine that begins the global to local scatter 531 - end - the routine that ends the global to local scatter 532 533 Notes: 534 If these functions are not provided but DMShellSetGlobalToLocalVecScatter() is called then 535 DMGlobalToLocalBeginDefaultShell()/DMGlobalToLocalEndDefaultShell() are used to to perform the transfers 536 537 Level: advanced 538 539 .seealso: `DMShellSetLocalToGlobal()`, `DMGlobalToLocalBeginDefaultShell()`, `DMGlobalToLocalEndDefaultShell()` 540 @*/ 541 PetscErrorCode DMShellSetGlobalToLocal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec)) 542 { 543 PetscFunctionBegin; 544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 545 dm->ops->globaltolocalbegin = begin; 546 dm->ops->globaltolocalend = end; 547 PetscFunctionReturn(PETSC_SUCCESS); 548 } 549 550 /*@C 551 DMShellSetLocalToGlobal - Sets the routines used to perform a local to global scatter 552 553 Logically Collective on dm 554 555 Input Parameters 556 + dm - the shell DM 557 . begin - the routine that begins the local to global scatter 558 - end - the routine that ends the local to global scatter 559 560 Notes: 561 If these functions are not provided but DMShellSetLocalToGlobalVecScatter() is called then 562 DMLocalToGlobalBeginDefaultShell()/DMLocalToGlobalEndDefaultShell() are used to to perform the transfers 563 564 Level: advanced 565 566 .seealso: `DMShellSetGlobalToLocal()` 567 @*/ 568 PetscErrorCode DMShellSetLocalToGlobal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec)) 569 { 570 PetscFunctionBegin; 571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 572 dm->ops->localtoglobalbegin = begin; 573 dm->ops->localtoglobalend = end; 574 PetscFunctionReturn(PETSC_SUCCESS); 575 } 576 577 /*@C 578 DMShellSetLocalToLocal - Sets the routines used to perform a local to local scatter 579 580 Logically Collective on dm 581 582 Input Parameters 583 + dm - the shell DM 584 . begin - the routine that begins the local to local scatter 585 - end - the routine that ends the local to local scatter 586 587 Notes: 588 If these functions are not provided but DMShellSetLocalToLocalVecScatter() is called then 589 DMLocalToLocalBeginDefaultShell()/DMLocalToLocalEndDefaultShell() are used to to perform the transfers 590 591 Level: advanced 592 593 .seealso: `DMShellSetGlobalToLocal()`, `DMLocalToLocalBeginDefaultShell()`, `DMLocalToLocalEndDefaultShell()` 594 @*/ 595 PetscErrorCode DMShellSetLocalToLocal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec)) 596 { 597 PetscFunctionBegin; 598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 599 dm->ops->localtolocalbegin = begin; 600 dm->ops->localtolocalend = end; 601 PetscFunctionReturn(PETSC_SUCCESS); 602 } 603 604 /*@ 605 DMShellSetGlobalToLocalVecScatter - Sets a VecScatter context for global to local communication 606 607 Logically Collective on dm 608 609 Input Parameters 610 + dm - the shell DM 611 - gtol - the global to local VecScatter context 612 613 Level: advanced 614 615 .seealso: `DMShellSetGlobalToLocal()`, `DMGlobalToLocalBeginDefaultShell()`, `DMGlobalToLocalEndDefaultShell()` 616 @*/ 617 PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter gtol) 618 { 619 DM_Shell *shell = (DM_Shell *)dm->data; 620 621 PetscFunctionBegin; 622 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 623 PetscValidHeaderSpecific(gtol, PETSCSF_CLASSID, 2); 624 PetscCall(PetscObjectReference((PetscObject)gtol)); 625 PetscCall(VecScatterDestroy(&shell->gtol)); 626 shell->gtol = gtol; 627 PetscFunctionReturn(PETSC_SUCCESS); 628 } 629 630 /*@ 631 DMShellSetLocalToGlobalVecScatter - Sets a VecScatter context for local to global communication 632 633 Logically Collective on dm 634 635 Input Parameters 636 + dm - the shell DM 637 - ltog - the local to global VecScatter context 638 639 Level: advanced 640 641 .seealso: `DMShellSetLocalToGlobal()`, `DMLocalToGlobalBeginDefaultShell()`, `DMLocalToGlobalEndDefaultShell()` 642 @*/ 643 PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter ltog) 644 { 645 DM_Shell *shell = (DM_Shell *)dm->data; 646 647 PetscFunctionBegin; 648 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 649 PetscValidHeaderSpecific(ltog, PETSCSF_CLASSID, 2); 650 PetscCall(PetscObjectReference((PetscObject)ltog)); 651 PetscCall(VecScatterDestroy(&shell->ltog)); 652 shell->ltog = ltog; 653 PetscFunctionReturn(PETSC_SUCCESS); 654 } 655 656 /*@ 657 DMShellSetLocalToLocalVecScatter - Sets a VecScatter context for local to local communication 658 659 Logically Collective on dm 660 661 Input Parameters 662 + dm - the shell DM 663 - ltol - the local to local VecScatter context 664 665 Level: advanced 666 667 .seealso: `DMShellSetLocalToLocal()`, `DMLocalToLocalBeginDefaultShell()`, `DMLocalToLocalEndDefaultShell()` 668 @*/ 669 PetscErrorCode DMShellSetLocalToLocalVecScatter(DM dm, VecScatter ltol) 670 { 671 DM_Shell *shell = (DM_Shell *)dm->data; 672 673 PetscFunctionBegin; 674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 675 PetscValidHeaderSpecific(ltol, PETSCSF_CLASSID, 2); 676 PetscCall(PetscObjectReference((PetscObject)ltol)); 677 PetscCall(VecScatterDestroy(&shell->ltol)); 678 shell->ltol = ltol; 679 PetscFunctionReturn(PETSC_SUCCESS); 680 } 681 682 /*@C 683 DMShellSetCoarsen - Set the routine used to coarsen the shell DM 684 685 Logically Collective on dm 686 687 Input Parameters 688 + dm - the shell DM 689 - coarsen - the routine that coarsens the DM 690 691 Level: advanced 692 693 .seealso: `DMShellSetRefine()`, `DMCoarsen()`, `DMShellGetCoarsen()`, `DMShellSetContext()`, `DMShellGetContext()` 694 @*/ 695 PetscErrorCode DMShellSetCoarsen(DM dm, PetscErrorCode (*coarsen)(DM, MPI_Comm, DM *)) 696 { 697 PetscBool isshell; 698 699 PetscFunctionBegin; 700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 701 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 702 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 703 dm->ops->coarsen = coarsen; 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 707 /*@C 708 DMShellGetCoarsen - Get the routine used to coarsen the shell DM 709 710 Logically Collective on dm 711 712 Input Parameter: 713 . dm - the shell DM 714 715 Output Parameter: 716 . coarsen - the routine that coarsens the DM 717 718 Level: advanced 719 720 .seealso: `DMShellSetCoarsen()`, `DMCoarsen()`, `DMShellSetRefine()`, `DMRefine()` 721 @*/ 722 PetscErrorCode DMShellGetCoarsen(DM dm, PetscErrorCode (**coarsen)(DM, MPI_Comm, DM *)) 723 { 724 PetscBool isshell; 725 726 PetscFunctionBegin; 727 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 728 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 729 PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs"); 730 *coarsen = dm->ops->coarsen; 731 PetscFunctionReturn(PETSC_SUCCESS); 732 } 733 734 /*@C 735 DMShellSetRefine - Set the routine used to refine the shell DM 736 737 Logically Collective on dm 738 739 Input Parameters 740 + dm - the shell DM 741 - refine - the routine that refines the DM 742 743 Level: advanced 744 745 .seealso: `DMShellSetCoarsen()`, `DMRefine()`, `DMShellGetRefine()`, `DMShellSetContext()`, `DMShellGetContext()` 746 @*/ 747 PetscErrorCode DMShellSetRefine(DM dm, PetscErrorCode (*refine)(DM, MPI_Comm, DM *)) 748 { 749 PetscBool isshell; 750 751 PetscFunctionBegin; 752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 753 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 754 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 755 dm->ops->refine = refine; 756 PetscFunctionReturn(PETSC_SUCCESS); 757 } 758 759 /*@C 760 DMShellGetRefine - Get the routine used to refine the shell DM 761 762 Logically Collective on dm 763 764 Input Parameter: 765 . dm - the shell DM 766 767 Output Parameter: 768 . refine - the routine that refines the DM 769 770 Level: advanced 771 772 .seealso: `DMShellSetCoarsen()`, `DMCoarsen()`, `DMShellSetRefine()`, `DMRefine()` 773 @*/ 774 PetscErrorCode DMShellGetRefine(DM dm, PetscErrorCode (**refine)(DM, MPI_Comm, DM *)) 775 { 776 PetscBool isshell; 777 778 PetscFunctionBegin; 779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 780 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 781 PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs"); 782 *refine = dm->ops->refine; 783 PetscFunctionReturn(PETSC_SUCCESS); 784 } 785 786 /*@C 787 DMShellSetCreateInterpolation - Set the routine used to create the interpolation operator 788 789 Logically Collective on dm 790 791 Input Parameters 792 + dm - the shell DM 793 - interp - the routine to create the interpolation 794 795 Level: advanced 796 797 .seealso: `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateInterpolation()`, `DMShellSetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()` 798 @*/ 799 PetscErrorCode DMShellSetCreateInterpolation(DM dm, PetscErrorCode (*interp)(DM, DM, Mat *, Vec *)) 800 { 801 PetscBool isshell; 802 803 PetscFunctionBegin; 804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 805 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 806 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 807 dm->ops->createinterpolation = interp; 808 PetscFunctionReturn(PETSC_SUCCESS); 809 } 810 811 /*@C 812 DMShellGetCreateInterpolation - Get the routine used to create the interpolation operator 813 814 Logically Collective on dm 815 816 Input Parameter: 817 . dm - the shell DM 818 819 Output Parameter: 820 . interp - the routine to create the interpolation 821 822 Level: advanced 823 824 .seealso: `DMShellGetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()` 825 @*/ 826 PetscErrorCode DMShellGetCreateInterpolation(DM dm, PetscErrorCode (**interp)(DM, DM, Mat *, Vec *)) 827 { 828 PetscBool isshell; 829 830 PetscFunctionBegin; 831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 832 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 833 PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs"); 834 *interp = dm->ops->createinterpolation; 835 PetscFunctionReturn(PETSC_SUCCESS); 836 } 837 838 /*@C 839 DMShellSetCreateRestriction - Set the routine used to create the restriction operator 840 841 Logically Collective on dm 842 843 Input Parameters 844 + dm - the shell DM 845 - striction- the routine to create the restriction 846 847 Level: advanced 848 849 .seealso: `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()` 850 @*/ 851 PetscErrorCode DMShellSetCreateRestriction(DM dm, PetscErrorCode (*restriction)(DM, DM, Mat *)) 852 { 853 PetscBool isshell; 854 855 PetscFunctionBegin; 856 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 857 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 858 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 859 dm->ops->createrestriction = restriction; 860 PetscFunctionReturn(PETSC_SUCCESS); 861 } 862 863 /*@C 864 DMShellGetCreateRestriction - Get the routine used to create the restriction operator 865 866 Logically Collective on dm 867 868 Input Parameter: 869 . dm - the shell DM 870 871 Output Parameter: 872 . restriction - the routine to create the restriction 873 874 Level: advanced 875 876 .seealso: `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellSetContext()`, `DMShellGetContext()` 877 @*/ 878 PetscErrorCode DMShellGetCreateRestriction(DM dm, PetscErrorCode (**restriction)(DM, DM, Mat *)) 879 { 880 PetscBool isshell; 881 882 PetscFunctionBegin; 883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 884 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 885 PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs"); 886 *restriction = dm->ops->createrestriction; 887 PetscFunctionReturn(PETSC_SUCCESS); 888 } 889 890 /*@C 891 DMShellSetCreateInjection - Set the routine used to create the injection operator 892 893 Logically Collective on dm 894 895 Input Parameters: 896 + dm - the shell DM 897 - inject - the routine to create the injection 898 899 Level: advanced 900 901 .seealso: `DMShellSetCreateInterpolation()`, `DMCreateInjection()`, `DMShellGetCreateInjection()`, `DMShellSetContext()`, `DMShellGetContext()` 902 @*/ 903 PetscErrorCode DMShellSetCreateInjection(DM dm, PetscErrorCode (*inject)(DM, DM, Mat *)) 904 { 905 PetscBool isshell; 906 907 PetscFunctionBegin; 908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 909 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 910 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 911 dm->ops->createinjection = inject; 912 PetscFunctionReturn(PETSC_SUCCESS); 913 } 914 915 /*@C 916 DMShellGetCreateInjection - Get the routine used to create the injection operator 917 918 Logically Collective on dm 919 920 Input Parameter: 921 . dm - the shell DM 922 923 Output Parameter: 924 . inject - the routine to create the injection 925 926 Level: advanced 927 928 .seealso: `DMShellGetCreateInterpolation()`, `DMCreateInjection()`, `DMShellSetContext()`, `DMShellGetContext()` 929 @*/ 930 PetscErrorCode DMShellGetCreateInjection(DM dm, PetscErrorCode (**inject)(DM, DM, Mat *)) 931 { 932 PetscBool isshell; 933 934 PetscFunctionBegin; 935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 936 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 937 PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs"); 938 *inject = dm->ops->createinjection; 939 PetscFunctionReturn(PETSC_SUCCESS); 940 } 941 942 /*@C 943 DMShellSetCreateFieldDecomposition - Set the routine used to create a decomposition of fields for the shell DM 944 945 Logically Collective on dm 946 947 Input Parameters: 948 + dm - the shell DM 949 - decomp - the routine to create the decomposition 950 951 Level: advanced 952 953 .seealso: `DMCreateFieldDecomposition()`, `DMShellSetContext()`, `DMShellGetContext()` 954 @*/ 955 PetscErrorCode DMShellSetCreateFieldDecomposition(DM dm, PetscErrorCode (*decomp)(DM, PetscInt *, char ***, IS **, DM **)) 956 { 957 PetscBool isshell; 958 959 PetscFunctionBegin; 960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 961 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 962 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 963 dm->ops->createfielddecomposition = decomp; 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 /*@C 968 DMShellSetCreateDomainDecomposition - Set the routine used to create a domain decomposition for the shell DM 969 970 Logically Collective on dm 971 972 Input Parameters: 973 + dm - the shell DM 974 - decomp - the routine to create the decomposition 975 976 Level: advanced 977 978 .seealso: `DMCreateDomainDecomposition()`, `DMShellSetContext()`, `DMShellGetContext()` 979 @*/ 980 PetscErrorCode DMShellSetCreateDomainDecomposition(DM dm, PetscErrorCode (*decomp)(DM, PetscInt *, char ***, IS **, IS **, DM **)) 981 { 982 PetscBool isshell; 983 984 PetscFunctionBegin; 985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 986 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 987 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 988 dm->ops->createdomaindecomposition = decomp; 989 PetscFunctionReturn(PETSC_SUCCESS); 990 } 991 992 /*@C 993 DMShellSetCreateDomainDecompositionScatters - Set the routine used to create the scatter contexts for domain decomposition with a shell DM 994 995 Logically Collective on dm 996 997 Input Parameters: 998 + dm - the shell DM 999 - scatter - the routine to create the scatters 1000 1001 Level: advanced 1002 1003 .seealso: `DMCreateDomainDecompositionScatters()`, `DMShellSetContext()`, `DMShellGetContext()` 1004 @*/ 1005 PetscErrorCode DMShellSetCreateDomainDecompositionScatters(DM dm, PetscErrorCode (*scatter)(DM, PetscInt, DM *, VecScatter **, VecScatter **, VecScatter **)) 1006 { 1007 PetscBool isshell; 1008 1009 PetscFunctionBegin; 1010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1011 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 1012 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 1013 dm->ops->createddscatters = scatter; 1014 PetscFunctionReturn(PETSC_SUCCESS); 1015 } 1016 1017 /*@C 1018 DMShellSetCreateSubDM - Set the routine used to create a sub DM from the shell DM 1019 1020 Logically Collective on dm 1021 1022 Input Parameters: 1023 + dm - the shell DM 1024 - subdm - the routine to create the decomposition 1025 1026 Level: advanced 1027 1028 .seealso: `DMCreateSubDM()`, `DMShellGetCreateSubDM()`, `DMShellSetContext()`, `DMShellGetContext()` 1029 @*/ 1030 PetscErrorCode DMShellSetCreateSubDM(DM dm, PetscErrorCode (*subdm)(DM, PetscInt, const PetscInt[], IS *, DM *)) 1031 { 1032 PetscBool isshell; 1033 1034 PetscFunctionBegin; 1035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1036 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 1037 if (!isshell) PetscFunctionReturn(PETSC_SUCCESS); 1038 dm->ops->createsubdm = subdm; 1039 PetscFunctionReturn(PETSC_SUCCESS); 1040 } 1041 1042 /*@C 1043 DMShellGetCreateSubDM - Get the routine used to create a sub DM from the shell DM 1044 1045 Logically Collective on dm 1046 1047 Input Parameter: 1048 . dm - the shell DM 1049 1050 Output Parameter: 1051 . subdm - the routine to create the decomposition 1052 1053 Level: advanced 1054 1055 .seealso: `DMCreateSubDM()`, `DMShellSetCreateSubDM()`, `DMShellSetContext()`, `DMShellGetContext()` 1056 @*/ 1057 PetscErrorCode DMShellGetCreateSubDM(DM dm, PetscErrorCode (**subdm)(DM, PetscInt, const PetscInt[], IS *, DM *)) 1058 { 1059 PetscBool isshell; 1060 1061 PetscFunctionBegin; 1062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1063 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell)); 1064 PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs"); 1065 *subdm = dm->ops->createsubdm; 1066 PetscFunctionReturn(PETSC_SUCCESS); 1067 } 1068 1069 static PetscErrorCode DMDestroy_Shell(DM dm) 1070 { 1071 DM_Shell *shell = (DM_Shell *)dm->data; 1072 1073 PetscFunctionBegin; 1074 if (shell->destroyctx) PetscCallBack("Destroy Context", (*shell->destroyctx)(shell->ctx)); 1075 PetscCall(MatDestroy(&shell->A)); 1076 PetscCall(VecDestroy(&shell->Xglobal)); 1077 PetscCall(VecDestroy(&shell->Xlocal)); 1078 PetscCall(VecScatterDestroy(&shell->gtol)); 1079 PetscCall(VecScatterDestroy(&shell->ltog)); 1080 PetscCall(VecScatterDestroy(&shell->ltol)); 1081 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 1082 PetscCall(PetscFree(shell)); 1083 PetscFunctionReturn(PETSC_SUCCESS); 1084 } 1085 1086 static PetscErrorCode DMView_Shell(DM dm, PetscViewer v) 1087 { 1088 DM_Shell *shell = (DM_Shell *)dm->data; 1089 1090 PetscFunctionBegin; 1091 if (shell->Xglobal) PetscCall(VecView(shell->Xglobal, v)); 1092 PetscFunctionReturn(PETSC_SUCCESS); 1093 } 1094 1095 static PetscErrorCode DMLoad_Shell(DM dm, PetscViewer v) 1096 { 1097 DM_Shell *shell = (DM_Shell *)dm->data; 1098 1099 PetscFunctionBegin; 1100 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &shell->Xglobal)); 1101 PetscCall(VecLoad(shell->Xglobal, v)); 1102 PetscFunctionReturn(PETSC_SUCCESS); 1103 } 1104 1105 PetscErrorCode DMCreateSubDM_Shell(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 1106 { 1107 PetscFunctionBegin; 1108 if (subdm) PetscCall(DMShellCreate(PetscObjectComm((PetscObject)dm), subdm)); 1109 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 1110 PetscFunctionReturn(PETSC_SUCCESS); 1111 } 1112 1113 PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm) 1114 { 1115 DM_Shell *shell; 1116 1117 PetscFunctionBegin; 1118 PetscCall(PetscNew(&shell)); 1119 dm->data = shell; 1120 1121 dm->ops->destroy = DMDestroy_Shell; 1122 dm->ops->createglobalvector = DMCreateGlobalVector_Shell; 1123 dm->ops->createlocalvector = DMCreateLocalVector_Shell; 1124 dm->ops->creatematrix = DMCreateMatrix_Shell; 1125 dm->ops->view = DMView_Shell; 1126 dm->ops->load = DMLoad_Shell; 1127 dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell; 1128 dm->ops->globaltolocalend = DMGlobalToLocalEndDefaultShell; 1129 dm->ops->localtoglobalbegin = DMLocalToGlobalBeginDefaultShell; 1130 dm->ops->localtoglobalend = DMLocalToGlobalEndDefaultShell; 1131 dm->ops->localtolocalbegin = DMLocalToLocalBeginDefaultShell; 1132 dm->ops->localtolocalend = DMLocalToLocalEndDefaultShell; 1133 dm->ops->createsubdm = DMCreateSubDM_Shell; 1134 PetscCall(DMSetMatType(dm, MATDENSE)); 1135 PetscFunctionReturn(PETSC_SUCCESS); 1136 } 1137 1138 /*@ 1139 DMShellCreate - Creates a shell DM object, used to manage user-defined problem data 1140 1141 Collective 1142 1143 Input Parameter: 1144 . comm - the processors that will share the global vector 1145 1146 Output Parameters: 1147 . shell - the shell DM 1148 1149 Level: advanced 1150 1151 .seealso `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`, `DMShellSetContext()`, `DMShellGetContext()` 1152 @*/ 1153 PetscErrorCode DMShellCreate(MPI_Comm comm, DM *dm) 1154 { 1155 PetscFunctionBegin; 1156 PetscValidPointer(dm, 2); 1157 PetscCall(DMCreate(comm, dm)); 1158 PetscCall(DMSetType(*dm, DMSHELL)); 1159 PetscCall(DMSetUp(*dm)); 1160 PetscFunctionReturn(PETSC_SUCCESS); 1161 } 1162