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 } DM_Shell; 12 13 #undef __FUNCT__ 14 #define __FUNCT__ "DMGlobalToLocalBeginDefaultShell" 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 #undef __FUNCT__ 43 #define __FUNCT__ "DMGlobalToLocalEndDefaultShell" 44 /*@ 45 DMGlobalToLocalEndDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to end a global to local scatter 46 Collective 47 48 Input Arguments: 49 + dm - shell DM 50 . g - global vector 51 . mode - InsertMode 52 - l - local vector 53 54 Level: advanced 55 56 .seealso: DMGlobalToLocalBeginDefaultShell() 57 @*/ 58 PetscErrorCode DMGlobalToLocalEndDefaultShell(DM dm,Vec g,InsertMode mode,Vec l) 59 { 60 PetscErrorCode ierr; 61 DM_Shell *shell = (DM_Shell*)dm->data; 62 63 PetscFunctionBegin; 64 if (!shell->gtol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()"); 65 ierr = VecScatterEnd(*(shell->gtol),g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr); 66 PetscFunctionReturn(0); 67 } 68 69 #undef __FUNCT__ 70 #define __FUNCT__ "DMCreateMatrix_Shell" 71 static PetscErrorCode DMCreateMatrix_Shell(DM dm,MatType mtype,Mat *J) 72 { 73 PetscErrorCode ierr; 74 DM_Shell *shell = (DM_Shell*)dm->data; 75 Mat A; 76 77 PetscFunctionBegin; 78 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 79 PetscValidPointer(J,3); 80 if (!shell->A) { 81 if (shell->Xglobal) { 82 PetscInt m,M; 83 ierr = PetscInfo(dm,"Naively creating matrix using global vector distribution without preallocation");CHKERRQ(ierr); 84 ierr = VecGetSize(shell->Xglobal,&M);CHKERRQ(ierr); 85 ierr = VecGetLocalSize(shell->Xglobal,&m);CHKERRQ(ierr); 86 ierr = MatCreate(PetscObjectComm((PetscObject)dm),&shell->A);CHKERRQ(ierr); 87 ierr = MatSetSizes(shell->A,m,m,M,M);CHKERRQ(ierr); 88 if (mtype) {ierr = MatSetType(shell->A,mtype);CHKERRQ(ierr);} 89 ierr = MatSetUp(shell->A);CHKERRQ(ierr); 90 } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetMatrix(), DMShellSetCreateMatrix(), or provide a vector"); 91 } 92 A = shell->A; 93 /* the check below is tacky and incomplete */ 94 if (mtype) { 95 PetscBool flg,aij,seqaij,mpiaij; 96 ierr = PetscObjectTypeCompare((PetscObject)A,mtype,&flg);CHKERRQ(ierr); 97 ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&seqaij);CHKERRQ(ierr); 98 ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&mpiaij);CHKERRQ(ierr); 99 ierr = PetscStrcmp(mtype,MATAIJ,&aij);CHKERRQ(ierr); 100 if (!flg) { 101 if (!(aij & (seqaij || mpiaij))) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Requested matrix of type %s, but only %s available",mtype,((PetscObject)A)->type_name); 102 } 103 } 104 if (((PetscObject)A)->refct < 2) { /* We have an exclusive reference so we can give it out */ 105 ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr); 106 ierr = MatZeroEntries(A);CHKERRQ(ierr); 107 *J = A; 108 } else { /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */ 109 ierr = MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,J);CHKERRQ(ierr); 110 ierr = MatZeroEntries(*J);CHKERRQ(ierr); 111 } 112 PetscFunctionReturn(0); 113 } 114 115 #undef __FUNCT__ 116 #define __FUNCT__ "DMCreateGlobalVector_Shell" 117 PetscErrorCode DMCreateGlobalVector_Shell(DM dm,Vec *gvec) 118 { 119 PetscErrorCode ierr; 120 DM_Shell *shell = (DM_Shell*)dm->data; 121 Vec X; 122 123 PetscFunctionBegin; 124 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 125 PetscValidPointer(gvec,2); 126 *gvec = 0; 127 X = shell->Xglobal; 128 if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetGlobalVector() or DMShellSetCreateGlobalVector()"); 129 if (((PetscObject)X)->refct < 2) { /* We have an exclusive reference so we can give it out */ 130 ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr); 131 ierr = VecZeroEntries(X);CHKERRQ(ierr); 132 *gvec = X; 133 } else { /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */ 134 ierr = VecDuplicate(X,gvec);CHKERRQ(ierr); 135 ierr = VecZeroEntries(*gvec);CHKERRQ(ierr); 136 } 137 ierr = VecSetDM(*gvec,dm);CHKERRQ(ierr); 138 PetscFunctionReturn(0); 139 } 140 141 #undef __FUNCT__ 142 #define __FUNCT__ "DMCreateLocalVector_Shell" 143 PetscErrorCode DMCreateLocalVector_Shell(DM dm,Vec *gvec) 144 { 145 PetscErrorCode ierr; 146 DM_Shell *shell = (DM_Shell*)dm->data; 147 Vec X; 148 149 PetscFunctionBegin; 150 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 151 PetscValidPointer(gvec,2); 152 *gvec = 0; 153 X = shell->Xlocal; 154 if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetLocalVector() or DMShellSetCreateLocalVector()"); 155 if (((PetscObject)X)->refct < 2) { /* We have an exclusive reference so we can give it out */ 156 ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr); 157 ierr = VecZeroEntries(X);CHKERRQ(ierr); 158 *gvec = X; 159 } else { /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */ 160 ierr = VecDuplicate(X,gvec);CHKERRQ(ierr); 161 ierr = VecZeroEntries(*gvec);CHKERRQ(ierr); 162 } 163 ierr = VecSetDM(*gvec,dm);CHKERRQ(ierr); 164 PetscFunctionReturn(0); 165 } 166 167 #undef __FUNCT__ 168 #define __FUNCT__ "DMShellSetMatrix" 169 /*@ 170 DMShellSetMatrix - sets a template matrix associated with the DMShell 171 172 Collective 173 174 Input Arguments: 175 + dm - shell DM 176 - J - template matrix 177 178 Level: advanced 179 180 .seealso: DMCreateMatrix(), DMShellSetCreateMatrix() 181 @*/ 182 PetscErrorCode DMShellSetMatrix(DM dm,Mat J) 183 { 184 DM_Shell *shell = (DM_Shell*)dm->data; 185 PetscErrorCode ierr; 186 PetscBool isshell; 187 188 PetscFunctionBegin; 189 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 190 PetscValidHeaderSpecific(J,MAT_CLASSID,2); 191 ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr); 192 if (!isshell) PetscFunctionReturn(0); 193 ierr = PetscObjectReference((PetscObject)J);CHKERRQ(ierr); 194 ierr = MatDestroy(&shell->A);CHKERRQ(ierr); 195 shell->A = J; 196 PetscFunctionReturn(0); 197 } 198 199 #undef __FUNCT__ 200 #define __FUNCT__ "DMShellSetCreateMatrix" 201 /*@C 202 DMShellSetCreateMatrix - sets the routine to create a matrix associated with the shell DM 203 204 Logically Collective on DM 205 206 Input Arguments: 207 + dm - the shell DM 208 - func - the function to create a matrix 209 210 Level: advanced 211 212 .seealso: DMCreateMatrix(), DMShellSetMatrix() 213 @*/ 214 PetscErrorCode DMShellSetCreateMatrix(DM dm,PetscErrorCode (*func)(DM,MatType,Mat*)) 215 { 216 217 PetscFunctionBegin; 218 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 219 dm->ops->creatematrix = func; 220 PetscFunctionReturn(0); 221 } 222 223 #undef __FUNCT__ 224 #define __FUNCT__ "DMShellSetGlobalVector" 225 /*@ 226 DMShellSetGlobalVector - sets a template global vector associated with the DMShell 227 228 Logically Collective on DM 229 230 Input Arguments: 231 + dm - shell DM 232 - X - template vector 233 234 Level: advanced 235 236 .seealso: DMCreateGlobalVector(), DMShellSetMatrix(), DMShellSetCreateGlobalVector() 237 @*/ 238 PetscErrorCode DMShellSetGlobalVector(DM dm,Vec X) 239 { 240 DM_Shell *shell = (DM_Shell*)dm->data; 241 PetscErrorCode ierr; 242 PetscBool isshell; 243 244 PetscFunctionBegin; 245 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 246 PetscValidHeaderSpecific(X,VEC_CLASSID,2); 247 ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr); 248 if (!isshell) PetscFunctionReturn(0); 249 ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr); 250 ierr = VecDestroy(&shell->Xglobal);CHKERRQ(ierr); 251 shell->Xglobal = X; 252 PetscFunctionReturn(0); 253 } 254 255 #undef __FUNCT__ 256 #define __FUNCT__ "DMShellSetCreateGlobalVector" 257 /*@C 258 DMShellSetCreateGlobalVector - sets the routine to create a global vector associated with the shell DM 259 260 Logically Collective 261 262 Input Arguments: 263 + dm - the shell DM 264 - func - the creation routine 265 266 Level: advanced 267 268 .seealso: DMShellSetGlobalVector(), DMShellSetCreateMatrix() 269 @*/ 270 PetscErrorCode DMShellSetCreateGlobalVector(DM dm,PetscErrorCode (*func)(DM,Vec*)) 271 { 272 273 PetscFunctionBegin; 274 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 275 dm->ops->createglobalvector = func; 276 PetscFunctionReturn(0); 277 } 278 279 #undef __FUNCT__ 280 #define __FUNCT__ "DMShellSetLocalVector" 281 /*@ 282 DMShellSetLocalVector - sets a template local vector associated with the DMShell 283 284 Logically Collective on DM 285 286 Input Arguments: 287 + dm - shell DM 288 - X - template vector 289 290 Level: advanced 291 292 .seealso: DMCreateLocalVector(), DMShellSetMatrix(), DMShellSetCreateLocalVector() 293 @*/ 294 PetscErrorCode DMShellSetLocalVector(DM dm,Vec X) 295 { 296 DM_Shell *shell = (DM_Shell*)dm->data; 297 PetscErrorCode ierr; 298 PetscBool isshell; 299 300 PetscFunctionBegin; 301 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 302 PetscValidHeaderSpecific(X,VEC_CLASSID,2); 303 ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr); 304 if (!isshell) PetscFunctionReturn(0); 305 ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr); 306 ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr); 307 shell->Xlocal = X; 308 PetscFunctionReturn(0); 309 } 310 311 #undef __FUNCT__ 312 #define __FUNCT__ "DMShellSetCreateLocalVector" 313 /*@C 314 DMShellSetCreateLocalVector - sets the routine to create a local vector associated with the shell DM 315 316 Logically Collective 317 318 Input Arguments: 319 + dm - the shell DM 320 - func - the creation routine 321 322 Level: advanced 323 324 .seealso: DMShellSetLocalVector(), DMShellSetCreateMatrix() 325 @*/ 326 PetscErrorCode DMShellSetCreateLocalVector(DM dm,PetscErrorCode (*func)(DM,Vec*)) 327 { 328 329 PetscFunctionBegin; 330 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 331 dm->ops->createlocalvector = func; 332 PetscFunctionReturn(0); 333 } 334 335 #undef __FUNCT__ 336 #define __FUNCT__ "DMShellSetGlobalToLocal" 337 /*@C 338 DMShellSetGlobalToLocal - Sets the routines used to perform a global to local scatter 339 340 Logically Collective on DM 341 342 Input Arguments 343 + dm - the shell DM 344 . begin - the routine that begins the global to local scatter 345 - end - the routine that ends the global to local scatter 346 347 Notes: If these functions are not provided but DMShellSetGlobalToLocalVecScatter() is called then 348 DMGlobalToLocalBeginDefaultShell() are used to to perform the transfers DMGlobalToLocalEndDefaultShell() 349 350 Level: advanced 351 352 .seealso: DMShellSetLocalToGlobal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell() 353 @*/ 354 PetscErrorCode DMShellSetGlobalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) { 355 PetscFunctionBegin; 356 dm->ops->globaltolocalbegin = begin; 357 dm->ops->globaltolocalend = end; 358 PetscFunctionReturn(0); 359 } 360 361 #undef __FUNCT__ 362 #define __FUNCT__ "DMShellSetLocalToGlobal" 363 /*@C 364 DMShellSetLocalToGlobal - Sets the routines used to perform a local to global scatter 365 366 Logically Collective on DM 367 368 Input Arguments 369 + dm - the shell DM 370 . begin - the routine that begins the local to global scatter 371 - end - the routine that ends the local to global scatter 372 373 Level: advanced 374 375 .seealso: DMShellSetGlobalToLocal() 376 @*/ 377 PetscErrorCode DMShellSetLocalToGlobal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) { 378 PetscFunctionBegin; 379 dm->ops->localtoglobalbegin = begin; 380 dm->ops->localtoglobalend = end; 381 PetscFunctionReturn(0); 382 } 383 384 #undef __FUNCT__ 385 #define __FUNCT__ "DMShellSetGlobalToLocalVecScatter" 386 /*@ 387 DMShellSetGlobalToLocalVecScatter - Sets a VecScatter context for global to local communication 388 389 Logically Collective on DM 390 391 Input Arguments 392 + dm - the shell DM 393 - gtol - the global to local VecScatter context 394 395 Level: advanced 396 397 .seealso: DMShellSetGlobalToLocal() 398 @*/ 399 PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter *gtol) 400 { 401 DM_Shell *shell = (DM_Shell*)dm->data; 402 403 PetscFunctionBegin; 404 shell->gtol = gtol; 405 PetscFunctionReturn(0); 406 } 407 408 #undef __FUNCT__ 409 #define __FUNCT__ "DMDestroy_Shell" 410 static PetscErrorCode DMDestroy_Shell(DM dm) 411 { 412 PetscErrorCode ierr; 413 DM_Shell *shell = (DM_Shell*)dm->data; 414 415 PetscFunctionBegin; 416 ierr = MatDestroy(&shell->A);CHKERRQ(ierr); 417 ierr = VecDestroy(&shell->Xglobal);CHKERRQ(ierr); 418 ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr); 419 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 420 ierr = PetscFree(shell);CHKERRQ(ierr); 421 PetscFunctionReturn(0); 422 } 423 424 #undef __FUNCT__ 425 #define __FUNCT__ "DMView_Shell" 426 static PetscErrorCode DMView_Shell(DM dm,PetscViewer v) 427 { 428 PetscErrorCode ierr; 429 DM_Shell *shell = (DM_Shell*)dm->data; 430 431 PetscFunctionBegin; 432 ierr = VecView(shell->Xglobal,v);CHKERRQ(ierr); 433 PetscFunctionReturn(0); 434 } 435 436 #undef __FUNCT__ 437 #define __FUNCT__ "DMLoad_Shell" 438 static PetscErrorCode DMLoad_Shell(DM dm,PetscViewer v) 439 { 440 PetscErrorCode ierr; 441 DM_Shell *shell = (DM_Shell*)dm->data; 442 443 PetscFunctionBegin; 444 ierr = VecCreate(PetscObjectComm((PetscObject)dm),&shell->Xglobal);CHKERRQ(ierr); 445 ierr = VecLoad(shell->Xglobal,v);CHKERRQ(ierr); 446 PetscFunctionReturn(0); 447 } 448 449 #undef __FUNCT__ 450 #define __FUNCT__ "DMCreate_Shell" 451 PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm) 452 { 453 PetscErrorCode ierr; 454 DM_Shell *shell; 455 456 PetscFunctionBegin; 457 ierr = PetscNewLog(dm,DM_Shell,&shell);CHKERRQ(ierr); 458 dm->data = shell; 459 460 ierr = PetscObjectChangeTypeName((PetscObject)dm,DMSHELL);CHKERRQ(ierr); 461 462 dm->ops->destroy = DMDestroy_Shell; 463 dm->ops->createglobalvector = DMCreateGlobalVector_Shell; 464 dm->ops->createlocalvector = DMCreateLocalVector_Shell; 465 dm->ops->creatematrix = DMCreateMatrix_Shell; 466 dm->ops->view = DMView_Shell; 467 dm->ops->load = DMLoad_Shell; 468 dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell; 469 dm->ops->globaltolocalend = DMGlobalToLocalEndDefaultShell; 470 PetscFunctionReturn(0); 471 } 472 473 #undef __FUNCT__ 474 #define __FUNCT__ "DMShellCreate" 475 /*@ 476 DMShellCreate - Creates a shell DM object, used to manage user-defined problem data 477 478 Collective on MPI_Comm 479 480 Input Parameter: 481 . comm - the processors that will share the global vector 482 483 Output Parameters: 484 . shell - the shell DM 485 486 Level: advanced 487 488 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateLocalVector() 489 @*/ 490 PetscErrorCode DMShellCreate(MPI_Comm comm,DM *dm) 491 { 492 PetscErrorCode ierr; 493 494 PetscFunctionBegin; 495 PetscValidPointer(dm,2); 496 ierr = DMCreate(comm,dm);CHKERRQ(ierr); 497 ierr = DMSetType(*dm,DMSHELL);CHKERRQ(ierr); 498 PetscFunctionReturn(0); 499 } 500 501