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