1 #include <petscdmda.h> /*I "petscdmda.h" I*/ 2 #include <petsc-private/dmimpl.h> 3 #include <petsc-private/snesimpl.h> /*I "petscsnes.h" I*/ 4 5 /* This structure holds the user-provided DMDA callbacks */ 6 typedef struct { 7 PetscErrorCode (*residuallocal)(DMDALocalInfo*,void*,void*,void*); 8 PetscErrorCode (*jacobianlocal)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*); 9 PetscErrorCode (*objectivelocal)(DMDALocalInfo*,void*,PetscReal*,void*); 10 void *residuallocalctx; 11 void *jacobianlocalctx; 12 void *objectivelocalctx; 13 InsertMode residuallocalimode; 14 15 /* For Picard iteration defined locally */ 16 PetscErrorCode (*rhsplocal)(DMDALocalInfo*,void*,void*,void*); 17 PetscErrorCode (*jacobianplocal)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*); 18 void *picardlocalctx; 19 } DM_DA_SNES; 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "SNESDMDestroy_DMDA" 23 static PetscErrorCode SNESDMDestroy_DMDA(SNESDM sdm) 24 { 25 PetscErrorCode ierr; 26 27 PetscFunctionBegin; 28 ierr = PetscFree(sdm->data);CHKERRQ(ierr); 29 PetscFunctionReturn(0); 30 } 31 32 #undef __FUNCT__ 33 #define __FUNCT__ "SNESDMDuplicate_DMDA" 34 static PetscErrorCode SNESDMDuplicate_DMDA(SNESDM oldsdm,DM dm) 35 { 36 PetscErrorCode ierr; 37 SNESDM sdm; 38 39 PetscFunctionBegin; 40 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 41 ierr = PetscNewLog(dm,DM_DA_SNES,&sdm->data);CHKERRQ(ierr); 42 if (oldsdm->data) { 43 ierr = PetscMemcpy(sdm->data,oldsdm->data,sizeof(DM_DA_SNES));CHKERRQ(ierr); 44 } 45 PetscFunctionReturn(0); 46 } 47 48 49 #undef __FUNCT__ 50 #define __FUNCT__ "DMDASNESGetContext" 51 static PetscErrorCode DMDASNESGetContext(DM dm,SNESDM sdm,DM_DA_SNES **dmdasnes) 52 { 53 PetscErrorCode ierr; 54 55 PetscFunctionBegin; 56 *dmdasnes = PETSC_NULL; 57 if (!sdm->data) { 58 ierr = PetscNewLog(dm,DM_DA_SNES,&sdm->data);CHKERRQ(ierr); 59 sdm->destroy = SNESDMDestroy_DMDA; 60 sdm->duplicate = SNESDMDuplicate_DMDA; 61 } 62 *dmdasnes = (DM_DA_SNES*)sdm->data; 63 PetscFunctionReturn(0); 64 } 65 66 #undef __FUNCT__ 67 #define __FUNCT__ "SNESComputeFunction_DMDA" 68 /* 69 This function should eventually replace: 70 DMDAComputeFunction() and DMDAComputeFunction1() 71 */ 72 static PetscErrorCode SNESComputeFunction_DMDA(SNES snes,Vec X,Vec F,void *ctx) 73 { 74 PetscErrorCode ierr; 75 DM dm; 76 DM_DA_SNES *dmdasnes = (DM_DA_SNES*)ctx; 77 DMDALocalInfo info; 78 Vec Xloc; 79 void *x,*f; 80 81 PetscFunctionBegin; 82 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 83 PetscValidHeaderSpecific(X,VEC_CLASSID,2); 84 PetscValidHeaderSpecific(F,VEC_CLASSID,3); 85 if (!dmdasnes->residuallocal) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Corrupt context"); 86 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 87 ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr); 88 ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 89 ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 90 ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr); 91 ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr); 92 switch (dmdasnes->residuallocalimode) { 93 case INSERT_VALUES: { 94 ierr = DMDAVecGetArray(dm,F,&f);CHKERRQ(ierr); 95 CHKMEMQ; 96 ierr = (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);CHKERRQ(ierr); 97 CHKMEMQ; 98 ierr = DMDAVecRestoreArray(dm,F,&f);CHKERRQ(ierr); 99 } break; 100 case ADD_VALUES: { 101 Vec Floc; 102 ierr = DMGetLocalVector(dm,&Floc);CHKERRQ(ierr); 103 ierr = VecZeroEntries(Floc);CHKERRQ(ierr); 104 ierr = DMDAVecGetArray(dm,Floc,&f);CHKERRQ(ierr); 105 CHKMEMQ; 106 ierr = (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);CHKERRQ(ierr); 107 CHKMEMQ; 108 ierr = DMDAVecRestoreArray(dm,Floc,&f);CHKERRQ(ierr); 109 ierr = VecZeroEntries(F);CHKERRQ(ierr); 110 ierr = DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr); 111 ierr = DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr); 112 ierr = DMRestoreLocalVector(dm,&Floc);CHKERRQ(ierr); 113 } break; 114 default: SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode); 115 } 116 ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr); 117 ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr); 118 PetscFunctionReturn(0); 119 } 120 121 #undef __FUNCT__ 122 #define __FUNCT__ "SNESComputeObjective_DMDA" 123 /* 124 This function should eventually replace: 125 DMDAComputeFunction() and DMDAComputeFunction1() 126 */ 127 static PetscErrorCode SNESComputeObjective_DMDA(SNES snes,Vec X,PetscReal *ob,void *ctx) 128 { 129 PetscErrorCode ierr; 130 DM dm; 131 DM_DA_SNES *dmdasnes = (DM_DA_SNES*)ctx; 132 DMDALocalInfo info; 133 Vec Xloc; 134 void *x; 135 136 PetscFunctionBegin; 137 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 138 PetscValidHeaderSpecific(X,VEC_CLASSID,2); 139 PetscValidPointer(ob,3); 140 if (!dmdasnes->objectivelocal) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Corrupt context"); 141 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 142 ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr); 143 ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 144 ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 145 ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr); 146 ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr); 147 CHKMEMQ; 148 ierr = (*dmdasnes->objectivelocal)(&info,x,ob,dmdasnes->objectivelocalctx);CHKERRQ(ierr); 149 CHKMEMQ; 150 ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr); 151 ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr); 152 PetscFunctionReturn(0); 153 } 154 155 #undef __FUNCT__ 156 #define __FUNCT__ "SNESComputeLocalBlockFunction_DMDA" 157 /* 158 This function should eventually replace: 159 DMDAComputeFunction() and DMDAComputeFunction1() 160 */ 161 PetscErrorCode SNESComputeLocalBlockFunction_DMDA(SNES snes,Vec X,Vec F,void *dmctx) 162 { 163 PetscErrorCode ierr; 164 DM dm = (DM)dmctx; /* the global DMDA context */ 165 DMDALocalInfo info; 166 void *x,*f; 167 DM_DA_SNES *dmdasnes; 168 SNESDM sdm; 169 170 PetscFunctionBegin; 171 172 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 173 PetscValidHeaderSpecific(X,VEC_CLASSID,2); 174 PetscValidHeaderSpecific(F,VEC_CLASSID,3); 175 PetscValidHeaderSpecific(dm,DM_CLASSID,4); 176 177 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 178 ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr); 179 if (!dmdasnes->residuallocal) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Corrupt context"); 180 ierr = DMDAVecGetArray(dm,X,&x);CHKERRQ(ierr); 181 ierr = DMDAGetLocalBlockInfo(dm,&info);CHKERRQ(ierr); 182 switch (dmdasnes->residuallocalimode) { 183 case INSERT_VALUES: { 184 ierr = DMDAVecGetArray(dm,F,&f);CHKERRQ(ierr); 185 CHKMEMQ; 186 ierr = (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);CHKERRQ(ierr); 187 CHKMEMQ; 188 ierr = DMDAVecRestoreArray(dm,F,&f);CHKERRQ(ierr); 189 } break; 190 case ADD_VALUES: { 191 Vec Floc; 192 ierr = DMGetLocalVector(dm,&Floc);CHKERRQ(ierr); 193 ierr = VecZeroEntries(Floc);CHKERRQ(ierr); 194 ierr = DMDAVecGetArray(dm,Floc,&f);CHKERRQ(ierr); 195 CHKMEMQ; 196 ierr = (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);CHKERRQ(ierr); 197 CHKMEMQ; 198 ierr = DMDAVecRestoreArray(dm,Floc,&f);CHKERRQ(ierr); 199 ierr = VecZeroEntries(F);CHKERRQ(ierr); 200 ierr = DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr); 201 ierr = DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr); 202 ierr = DMRestoreLocalVector(dm,&Floc);CHKERRQ(ierr); 203 } break; 204 default: SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode); 205 } 206 ierr = DMDAVecRestoreArray(dm,X,&x);CHKERRQ(ierr); 207 PetscFunctionReturn(0); 208 } 209 210 #undef __FUNCT__ 211 #define __FUNCT__ "SNESComputeJacobian_DMDA" 212 /* 213 This function should eventually replace: 214 DMComputeJacobian() and DMDAComputeJacobian1() 215 */ 216 static PetscErrorCode SNESComputeJacobian_DMDA(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *ctx) 217 { 218 PetscErrorCode ierr; 219 DM dm; 220 DM_DA_SNES *dmdasnes = (DM_DA_SNES*)ctx; 221 DMDALocalInfo info; 222 Vec Xloc; 223 void *x; 224 225 PetscFunctionBegin; 226 if (!dmdasnes->residuallocal) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Corrupt context"); 227 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 228 229 if (dmdasnes->jacobianlocal) { 230 ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr); 231 ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 232 ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 233 ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr); 234 ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr); 235 CHKMEMQ; 236 ierr = (*dmdasnes->jacobianlocal)(&info,x,*A,*B,mstr,dmdasnes->jacobianlocalctx);CHKERRQ(ierr); 237 CHKMEMQ; 238 ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr); 239 ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr); 240 } else { 241 MatFDColoring fdcoloring; 242 ierr = PetscObjectQuery((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject*)&fdcoloring);CHKERRQ(ierr); 243 if (!fdcoloring) { 244 ISColoring coloring; 245 246 ierr = DMCreateColoring(dm,dm->coloringtype,dm->mattype,&coloring);CHKERRQ(ierr); 247 ierr = MatFDColoringCreate(*B,coloring,&fdcoloring);CHKERRQ(ierr); 248 ierr = ISColoringDestroy(&coloring);CHKERRQ(ierr); 249 switch (dm->coloringtype) { 250 case IS_COLORING_GLOBAL: 251 ierr = MatFDColoringSetFunction(fdcoloring,(PetscErrorCode(*)(void))SNESComputeFunction_DMDA,dmdasnes);CHKERRQ(ierr); 252 break; 253 default: SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_SUP,"No support for coloring type '%s'",ISColoringTypes[dm->coloringtype]); 254 } 255 ierr = PetscObjectSetOptionsPrefix((PetscObject)fdcoloring,((PetscObject)dm)->prefix);CHKERRQ(ierr); 256 ierr = MatFDColoringSetFromOptions(fdcoloring);CHKERRQ(ierr); 257 ierr = PetscObjectCompose((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject)fdcoloring);CHKERRQ(ierr); 258 ierr = PetscObjectDereference((PetscObject)fdcoloring);CHKERRQ(ierr); 259 260 /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call 261 * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the 262 * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually 263 * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be 264 * taken when the PetscOList for the Vec inside MatFDColoring is destroyed. 265 */ 266 ierr = PetscObjectDereference((PetscObject)dm);CHKERRQ(ierr); 267 } 268 *mstr = SAME_NONZERO_PATTERN; 269 ierr = MatFDColoringApply(*B,fdcoloring,X,mstr,snes);CHKERRQ(ierr); 270 } 271 /* This will be redundant if the user called both, but it's too common to forget. */ 272 if (*A != *B) { 273 ierr = MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 274 ierr = MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 275 } 276 PetscFunctionReturn(0); 277 } 278 279 #undef __FUNCT__ 280 #define __FUNCT__ "SNESComputeLocalBlockJacobian_DMDA" 281 /* 282 This function should eventually replace: 283 DMComputeJacobian() and DMDAComputeJacobian1() 284 */ 285 PetscErrorCode SNESComputeLocalBlockJacobian_DMDA(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *dmctx) 286 { 287 PetscErrorCode ierr; 288 DM dm = (DM)dmctx; /* the global DMDA context */ 289 DM_DA_SNES *dmdasnes; 290 SNESDM sdm; 291 DMDALocalInfo info; 292 void *x; 293 294 PetscFunctionBegin; 295 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 296 ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr); 297 if (!dmdasnes->residuallocal) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Corrupt context"); 298 if (dmdasnes->jacobianlocal) { 299 ierr = DMDAVecGetArray(dm,X,&x);CHKERRQ(ierr); 300 CHKMEMQ; 301 ierr = (*dmdasnes->jacobianlocal)(&info,x,*A,*B,mstr,dmdasnes->jacobianlocalctx);CHKERRQ(ierr); 302 CHKMEMQ; 303 ierr = DMDAVecRestoreArray(dm,X,&x);CHKERRQ(ierr); 304 } 305 /* This will be redundant if the user called both, but it's too common to forget. */ 306 if (*A != *B) { 307 ierr = MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 308 ierr = MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 309 } 310 PetscFunctionReturn(0); 311 } 312 313 #undef __FUNCT__ 314 #define __FUNCT__ "DMDASNESSetFunctionLocal" 315 /*@C 316 DMDASNESSetFunctionLocal - set a local residual evaluation function 317 318 Logically Collective 319 320 Input Arguments: 321 + dm - DM to associate callback with 322 . imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part 323 . func - local residual evaluation 324 - ctx - optional context for local residual evaluation 325 326 Calling sequence for func: 327 + info - DMDALocalInfo defining the subdomain to evaluate the residual on 328 . x - dimensional pointer to state at which to evaluate residual 329 . f - dimensional pointer to residual, write the residual here 330 - ctx - optional context passed above 331 332 Level: beginner 333 334 .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d() 335 @*/ 336 PetscErrorCode DMDASNESSetFunctionLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),void *ctx) 337 { 338 PetscErrorCode ierr; 339 SNESDM sdm; 340 DM_DA_SNES *dmdasnes; 341 342 PetscFunctionBegin; 343 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 344 ierr = DMSNESGetContextWrite(dm,&sdm);CHKERRQ(ierr); 345 ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr); 346 dmdasnes->residuallocalimode = imode; 347 dmdasnes->residuallocal = func; 348 dmdasnes->residuallocalctx = ctx; 349 ierr = DMSNESSetFunction(dm,SNESComputeFunction_DMDA,dmdasnes);CHKERRQ(ierr); 350 ierr = DMSNESSetBlockFunction(dm,SNESComputeLocalBlockFunction_DMDA,dm);CHKERRQ(ierr); 351 if (!sdm->computejacobian) { /* Call us for the Jacobian too, can be overridden by the user. */ 352 ierr = DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);CHKERRQ(ierr); 353 } 354 PetscFunctionReturn(0); 355 } 356 357 #undef __FUNCT__ 358 #define __FUNCT__ "DMDASNESSetJacobianLocal" 359 /*@C 360 DMDASNESSetJacobianLocal - set a local residual evaluation function 361 362 Logically Collective 363 364 Input Arguments: 365 + dm - DM to associate callback with 366 . func - local residual evaluation 367 - ctx - optional context for local residual evaluation 368 369 Calling sequence for func: 370 + info - DMDALocalInfo defining the subdomain to evaluate the residual on 371 . x - dimensional pointer to state at which to evaluate residual 372 . f - dimensional pointer to residual, write the residual here 373 - ctx - optional context passed above 374 375 Level: beginner 376 377 .seealso: DMSNESSetJacobian(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d() 378 @*/ 379 PetscErrorCode DMDASNESSetJacobianLocal(DM dm,PetscErrorCode (*func)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*),void *ctx) 380 { 381 PetscErrorCode ierr; 382 SNESDM sdm; 383 DM_DA_SNES *dmdasnes; 384 385 PetscFunctionBegin; 386 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 387 ierr = DMSNESGetContextWrite(dm,&sdm);CHKERRQ(ierr); 388 ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr); 389 dmdasnes->jacobianlocal = func; 390 dmdasnes->jacobianlocalctx = ctx; 391 ierr = DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);CHKERRQ(ierr); 392 ierr = DMSNESSetBlockJacobian(dm,SNESComputeLocalBlockJacobian_DMDA,dm);CHKERRQ(ierr); 393 PetscFunctionReturn(0); 394 } 395 396 397 #undef __FUNCT__ 398 #define __FUNCT__ "DMDASNESSetObjectiveLocal" 399 /*@C 400 DMDASNESSetObjectiveLocal - set a local residual evaluation function 401 402 Logically Collective 403 404 Input Arguments: 405 + dm - DM to associate callback with 406 . func - local objective evaluation 407 - ctx - optional context for local residual evaluation 408 409 Calling sequence for func: 410 + info - DMDALocalInfo defining the subdomain to evaluate the residual on 411 . x - dimensional pointer to state at which to evaluate residual 412 . ob - eventual objective value 413 - ctx - optional context passed above 414 415 Level: beginner 416 417 .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d() 418 @*/ 419 PetscErrorCode DMDASNESSetObjectiveLocal(DM dm,DMDASNESObjective func,void *ctx) 420 { 421 PetscErrorCode ierr; 422 SNESDM sdm; 423 DM_DA_SNES *dmdasnes; 424 425 PetscFunctionBegin; 426 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 427 ierr = DMSNESGetContextWrite(dm,&sdm);CHKERRQ(ierr); 428 ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr); 429 dmdasnes->objectivelocal = func; 430 dmdasnes->objectivelocalctx = ctx; 431 ierr = DMSNESSetObjective(dm,SNESComputeObjective_DMDA,dmdasnes);CHKERRQ(ierr); 432 PetscFunctionReturn(0); 433 } 434 435 #undef __FUNCT__ 436 #define __FUNCT__ "SNESComputePicard_DMDA" 437 static PetscErrorCode SNESComputePicard_DMDA(SNES snes,Vec X,Vec F,void *ctx) 438 { 439 PetscErrorCode ierr; 440 DM dm; 441 DM_DA_SNES *dmdasnes = (DM_DA_SNES*)ctx; 442 DMDALocalInfo info; 443 Vec Xloc; 444 void *x,*f; 445 446 PetscFunctionBegin; 447 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 448 PetscValidHeaderSpecific(X,VEC_CLASSID,2); 449 PetscValidHeaderSpecific(F,VEC_CLASSID,3); 450 if (!dmdasnes->rhsplocal) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Corrupt context"); 451 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 452 ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr); 453 ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 454 ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 455 ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr); 456 ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr); 457 switch (dmdasnes->residuallocalimode) { 458 case INSERT_VALUES: { 459 ierr = DMDAVecGetArray(dm,F,&f);CHKERRQ(ierr); 460 CHKMEMQ; 461 ierr = (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);CHKERRQ(ierr); 462 CHKMEMQ; 463 ierr = DMDAVecRestoreArray(dm,F,&f);CHKERRQ(ierr); 464 } break; 465 case ADD_VALUES: { 466 Vec Floc; 467 ierr = DMGetLocalVector(dm,&Floc);CHKERRQ(ierr); 468 ierr = VecZeroEntries(Floc);CHKERRQ(ierr); 469 ierr = DMDAVecGetArray(dm,Floc,&f);CHKERRQ(ierr); 470 CHKMEMQ; 471 ierr = (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);CHKERRQ(ierr); 472 CHKMEMQ; 473 ierr = DMDAVecRestoreArray(dm,Floc,&f);CHKERRQ(ierr); 474 ierr = VecZeroEntries(F);CHKERRQ(ierr); 475 ierr = DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr); 476 ierr = DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);CHKERRQ(ierr); 477 ierr = DMRestoreLocalVector(dm,&Floc);CHKERRQ(ierr); 478 } break; 479 default: SETERRQ1(((PetscObject)snes)->comm,PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode); 480 } 481 ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr); 482 ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr); 483 PetscFunctionReturn(0); 484 } 485 486 #undef __FUNCT__ 487 #define __FUNCT__ "SNESComputePicardJacobian_DMDA" 488 static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *ctx) 489 { 490 PetscErrorCode ierr; 491 DM dm; 492 DM_DA_SNES *dmdasnes = (DM_DA_SNES*)ctx; 493 DMDALocalInfo info; 494 Vec Xloc; 495 void *x; 496 497 PetscFunctionBegin; 498 if (!dmdasnes->jacobianplocal) SETERRQ(((PetscObject)snes)->comm,PETSC_ERR_PLIB,"Corrupt context"); 499 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 500 501 ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr); 502 ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 503 ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr); 504 ierr = DMDAGetLocalInfo(dm,&info);CHKERRQ(ierr); 505 ierr = DMDAVecGetArray(dm,Xloc,&x);CHKERRQ(ierr); 506 CHKMEMQ; 507 ierr = (*dmdasnes->jacobianplocal)(&info,x,*A,*B,mstr,dmdasnes->picardlocalctx);CHKERRQ(ierr); 508 CHKMEMQ; 509 ierr = DMDAVecRestoreArray(dm,Xloc,&x);CHKERRQ(ierr); 510 ierr = DMRestoreLocalVector(dm,&Xloc);CHKERRQ(ierr); 511 *mstr = SAME_NONZERO_PATTERN; 512 if (*A != *B) { 513 ierr = MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 514 ierr = MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 515 } 516 PetscFunctionReturn(0); 517 } 518 519 #undef __FUNCT__ 520 #define __FUNCT__ "DMDASNESSetPicardLocal" 521 /*@C 522 DMDASNESSetPicardLocal - set a local right hand side and matrix evaluation function for Picard iteration 523 524 Logically Collective 525 526 Input Arguments: 527 + dm - DM to associate callback with 528 . imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part 529 . func - local residual evaluation 530 - ctx - optional context for local residual evaluation 531 532 Calling sequence for func: 533 + info - DMDALocalInfo defining the subdomain to evaluate the residual on 534 . x - dimensional pointer to state at which to evaluate residual 535 . f - dimensional pointer to residual, write the residual here 536 - ctx - optional context passed above 537 538 Notes: The user must use 539 extern PetscErrorCode SNESPicardComputeFunction(SNES,Vec,Vec,void*); 540 extern PetscErrorCode SNESPicardComputeJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*); 541 ierr = SNESSetFunction(snes,PETSC_NULL,SNESPicardComputeFunction,&user);CHKERRQ(ierr); 542 in their code before calling this routine. 543 544 545 Level: beginner 546 547 .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d() 548 @*/ 549 PetscErrorCode DMDASNESSetPicardLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*), 550 PetscErrorCode (*jac)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*),void *ctx) 551 { 552 PetscErrorCode ierr; 553 SNESDM sdm; 554 DM_DA_SNES *dmdasnes; 555 556 PetscFunctionBegin; 557 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 558 ierr = DMSNESGetContextWrite(dm,&sdm);CHKERRQ(ierr); 559 ierr = DMDASNESGetContext(dm,sdm,&dmdasnes);CHKERRQ(ierr); 560 dmdasnes->residuallocalimode = imode; 561 dmdasnes->rhsplocal = func; 562 dmdasnes->jacobianplocal = jac; 563 dmdasnes->picardlocalctx = ctx; 564 ierr = DMSNESSetPicard(dm,SNESComputePicard_DMDA,SNESComputePicardJacobian_DMDA,dmdasnes);CHKERRQ(ierr); 565 PetscFunctionReturn(0); 566 } 567