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