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