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