1 #include <private/snesimpl.h> /*I "petscsnes.h" I*/ 2 #include <petscdm.h> /*I "petscdm.h" I*/ 3 4 #undef __FUNCT__ 5 #define __FUNCT__ "PetscContainerDestroy_SNESDM" 6 static PetscErrorCode PetscContainerDestroy_SNESDM(void *ctx) 7 { 8 PetscErrorCode ierr; 9 SNESDM sdm = (SNESDM)ctx; 10 11 PetscFunctionBegin; 12 if (sdm->destroy) {ierr = (*sdm->destroy)(sdm);CHKERRQ(ierr);} 13 ierr = PetscFree(sdm);CHKERRQ(ierr); 14 PetscFunctionReturn(0); 15 } 16 17 #undef __FUNCT__ 18 #define __FUNCT__ "DMCoarsenHook_SNESDM" 19 /* Attaches the SNESDM to the coarse level. 20 * Under what conditions should we copy versus duplicate? 21 */ 22 static PetscErrorCode DMCoarsenHook_SNESDM(DM dm,DM dmc,void *ctx) 23 { 24 PetscErrorCode ierr; 25 26 PetscFunctionBegin; 27 ierr = DMSNESCopyContext(dm,dmc);CHKERRQ(ierr); 28 ierr = DMCoarsenHookAdd(dmc,DMCoarsenHook_SNESDM,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 29 PetscFunctionReturn(0); 30 } 31 32 #undef __FUNCT__ 33 #define __FUNCT__ "DMSNESGetContext" 34 /*@C 35 DMSNESGetContext - get read-only private SNESDM context from a DM 36 37 Not Collective 38 39 Input Argument: 40 . dm - DM to be used with SNES 41 42 Output Argument: 43 . snesdm - private SNESDM context 44 45 Level: developer 46 47 Notes: 48 Use DMSNESGetContextWrite() if write access is needed. The DMSNESSetXXX API should be used wherever possible. 49 50 .seealso: DMSNESGetContextWrite() 51 @*/ 52 PetscErrorCode DMSNESGetContext(DM dm,SNESDM *snesdm) 53 { 54 PetscErrorCode ierr; 55 PetscContainer container; 56 SNESDM sdm; 57 58 PetscFunctionBegin; 59 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 60 ierr = PetscObjectQuery((PetscObject)dm,"SNESDM",(PetscObject*)&container);CHKERRQ(ierr); 61 if (container) { 62 ierr = PetscContainerGetPointer(container,(void**)snesdm);CHKERRQ(ierr); 63 } else { 64 ierr = PetscInfo(dm,"Creating new SNESDM\n");CHKERRQ(ierr); 65 ierr = PetscContainerCreate(((PetscObject)dm)->comm,&container);CHKERRQ(ierr); 66 ierr = PetscNewLog(dm,struct _n_SNESDM,&sdm);CHKERRQ(ierr); 67 ierr = PetscContainerSetPointer(container,sdm);CHKERRQ(ierr); 68 ierr = PetscContainerSetUserDestroy(container,PetscContainerDestroy_SNESDM);CHKERRQ(ierr); 69 ierr = PetscObjectCompose((PetscObject)dm,"SNESDM",(PetscObject)container);CHKERRQ(ierr); 70 ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_SNESDM,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 71 ierr = PetscContainerGetPointer(container,(void**)snesdm);CHKERRQ(ierr); 72 ierr = PetscContainerDestroy(&container);CHKERRQ(ierr); 73 } 74 PetscFunctionReturn(0); 75 } 76 77 #undef __FUNCT__ 78 #define __FUNCT__ "DMSNESGetContextWrite" 79 /*@C 80 DMSNESGetContextWrite - get write access to private SNESDM context from a DM 81 82 Not Collective 83 84 Input Argument: 85 . dm - DM to be used with SNES 86 87 Output Argument: 88 . snesdm - private SNESDM context 89 90 Level: developer 91 92 .seealso: DMSNESGetContext() 93 @*/ 94 PetscErrorCode DMSNESGetContextWrite(DM dm,SNESDM *snesdm) 95 { 96 PetscErrorCode ierr; 97 SNESDM sdm; 98 99 PetscFunctionBegin; 100 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 101 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 102 if (!sdm->originaldm) sdm->originaldm = dm; 103 if (sdm->originaldm != dm) { /* Copy on write */ 104 PetscContainer container; 105 SNESDM oldsdm = sdm; 106 ierr = PetscInfo(dm,"Copying SNESDM due to write\n");CHKERRQ(ierr); 107 ierr = PetscContainerCreate(((PetscObject)dm)->comm,&container);CHKERRQ(ierr); 108 ierr = PetscNewLog(dm,struct _n_SNESDM,&sdm);CHKERRQ(ierr); 109 ierr = PetscMemcpy(sdm,oldsdm,sizeof *sdm);CHKERRQ(ierr); 110 ierr = PetscContainerSetPointer(container,sdm);CHKERRQ(ierr); 111 ierr = PetscContainerSetUserDestroy(container,PetscContainerDestroy_SNESDM);CHKERRQ(ierr); 112 ierr = PetscObjectCompose((PetscObject)dm,"SNESDM",(PetscObject)container);CHKERRQ(ierr); 113 ierr = PetscContainerDestroy(&container);CHKERRQ(ierr); 114 } 115 *snesdm = sdm; 116 PetscFunctionReturn(0); 117 } 118 119 #undef __FUNCT__ 120 #define __FUNCT__ "DMSNESCopyContext" 121 /*@C 122 DMSNESCopyContext - copies a DM context to a new DM 123 124 Logically Collective 125 126 Input Arguments: 127 + dmsrc - DM to obtain context from 128 - dmdest - DM to add context to 129 130 Level: developer 131 132 Note: 133 The context is copied by reference. This function does not ensure that a context exists. 134 135 .seealso: DMSNESGetContext(), SNESSetDM() 136 @*/ 137 PetscErrorCode DMSNESCopyContext(DM dmsrc,DM dmdest) 138 { 139 PetscErrorCode ierr; 140 PetscContainer container; 141 142 PetscFunctionBegin; 143 PetscValidHeaderSpecific(dmsrc,DM_CLASSID,1); 144 PetscValidHeaderSpecific(dmdest,DM_CLASSID,2); 145 ierr = PetscObjectQuery((PetscObject)dmsrc,"SNESDM",(PetscObject*)&container);CHKERRQ(ierr); 146 if (container) { 147 ierr = PetscObjectCompose((PetscObject)dmdest,"SNESDM",(PetscObject)container);CHKERRQ(ierr); 148 } 149 PetscFunctionReturn(0); 150 } 151 152 #undef __FUNCT__ 153 #define __FUNCT__ "DMSNESSetFunction" 154 /*@C 155 DMSNESSetFunction - set SNES residual evaluation function 156 157 Not Collective 158 159 Input Arguments: 160 + dm - DM to be used with SNES 161 . func - residual evaluation function, see SNESSetFunction() for calling sequence 162 - ctx - context for residual evaluation 163 164 Level: advanced 165 166 Note: 167 SNESSetFunction() is normally used, but it calls this function internally because the user context is actually 168 associated with the DM. This makes the interface consistent regardless of whether the user interacts with a DM or 169 not. If DM took a more central role at some later date, this could become the primary method of setting the residual. 170 171 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian() 172 @*/ 173 PetscErrorCode DMSNESSetFunction(DM dm,PetscErrorCode (*func)(SNES,Vec,Vec,void*),void *ctx) 174 { 175 PetscErrorCode ierr; 176 SNESDM sdm; 177 178 PetscFunctionBegin; 179 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 180 ierr = DMSNESGetContextWrite(dm,&sdm);CHKERRQ(ierr); 181 if (func) sdm->computefunction = func; 182 if (ctx) sdm->functionctx = ctx; 183 PetscFunctionReturn(0); 184 } 185 186 #undef __FUNCT__ 187 #define __FUNCT__ "DMSNESGetFunction" 188 /*@C 189 DMSNESGetFunction - get SNES residual evaluation function 190 191 Not Collective 192 193 Input Argument: 194 . dm - DM to be used with SNES 195 196 Output Arguments: 197 + func - residual evaluation function, see SNESSetFunction() for calling sequence 198 - ctx - context for residual evaluation 199 200 Level: advanced 201 202 Note: 203 SNESGetFunction() is normally used, but it calls this function internally because the user context is actually 204 associated with the DM. 205 206 .seealso: DMSNESSetContext(), DMSNESSetFunction(), SNESSetFunction() 207 @*/ 208 PetscErrorCode DMSNESGetFunction(DM dm,PetscErrorCode (**func)(SNES,Vec,Vec,void*),void **ctx) 209 { 210 PetscErrorCode ierr; 211 SNESDM sdm; 212 213 PetscFunctionBegin; 214 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 215 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 216 if (func) *func = sdm->computefunction; 217 if (ctx) *ctx = sdm->functionctx; 218 PetscFunctionReturn(0); 219 } 220 221 #undef __FUNCT__ 222 #define __FUNCT__ "DMSNESSetGS" 223 /*@C 224 DMSNESSetGS - set SNES Gauss-Seidel relaxation function 225 226 Not Collective 227 228 Input Argument: 229 + dm - DM to be used with SNES 230 . func - relaxation function, see SNESSetGS() for calling sequence 231 - ctx - context for residual evaluation 232 233 Level: advanced 234 235 Note: 236 SNESSetGS() is normally used, but it calls this function internally because the user context is actually 237 associated with the DM. This makes the interface consistent regardless of whether the user interacts with a DM or 238 not. If DM took a more central role at some later date, this could become the primary method of setting the residual. 239 240 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian(), DMSNESSetFunction() 241 @*/ 242 PetscErrorCode DMSNESSetGS(DM dm,PetscErrorCode (*func)(SNES,Vec,Vec,void*),void *ctx) 243 { 244 PetscErrorCode ierr; 245 SNESDM sdm; 246 247 PetscFunctionBegin; 248 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 249 ierr = DMSNESGetContextWrite(dm,&sdm);CHKERRQ(ierr); 250 if (func) sdm->computegs = func; 251 if (ctx) sdm->gsctx = ctx; 252 PetscFunctionReturn(0); 253 } 254 255 #undef __FUNCT__ 256 #define __FUNCT__ "DMSNESGetGS" 257 /*@C 258 DMSNESGetGS - get SNES Gauss-Seidel relaxation function 259 260 Not Collective 261 262 Input Argument: 263 . dm - DM to be used with SNES 264 265 Output Arguments: 266 + func - relaxation function, see SNESSetGS() for calling sequence 267 - ctx - context for residual evaluation 268 269 Level: advanced 270 271 Note: 272 SNESGetGS() is normally used, but it calls this function internally because the user context is actually 273 associated with the DM. This makes the interface consistent regardless of whether the user interacts with a DM or 274 not. If DM took a more central role at some later date, this could become the primary method of setting the residual. 275 276 .seealso: DMSNESSetContext(), SNESGetGS(), DMSNESGetJacobian(), DMSNESGetFunction() 277 @*/ 278 PetscErrorCode DMSNESGetGS(DM dm,PetscErrorCode (**func)(SNES,Vec,Vec,void*),void **ctx) 279 { 280 PetscErrorCode ierr; 281 SNESDM sdm; 282 283 PetscFunctionBegin; 284 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 285 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 286 if (func) *func = sdm->computegs; 287 if (ctx) *ctx = sdm->gsctx; 288 PetscFunctionReturn(0); 289 } 290 291 #undef __FUNCT__ 292 #define __FUNCT__ "DMSNESSetJacobian" 293 /*@C 294 DMSNESSetFunction - set SNES Jacobian evaluation function 295 296 Not Collective 297 298 Input Argument: 299 + dm - DM to be used with SNES 300 . func - Jacobian evaluation function, see SNESSetJacobian() for calling sequence 301 - ctx - context for residual evaluation 302 303 Level: advanced 304 305 Note: 306 SNESSetJacobian() is normally used, but it calls this function internally because the user context is actually 307 associated with the DM. This makes the interface consistent regardless of whether the user interacts with a DM or 308 not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian. 309 310 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESGetJacobian(), SNESSetJacobian() 311 @*/ 312 PetscErrorCode DMSNESSetJacobian(DM dm,PetscErrorCode (*func)(SNES,Vec,Mat*,Mat*,MatStructure*,void*),void *ctx) 313 { 314 PetscErrorCode ierr; 315 SNESDM sdm; 316 317 PetscFunctionBegin; 318 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 319 ierr = DMSNESGetContextWrite(dm,&sdm);CHKERRQ(ierr); 320 if (func) sdm->computejacobian = func; 321 if (ctx) sdm->jacobianctx = ctx; 322 PetscFunctionReturn(0); 323 } 324 325 #undef __FUNCT__ 326 #define __FUNCT__ "DMSNESGetJacobian" 327 /*@C 328 DMSNESGetFunction - get SNES Jacobian evaluation function 329 330 Not Collective 331 332 Input Argument: 333 . dm - DM to be used with SNES 334 335 Output Arguments: 336 + func - Jacobian evaluation function, see SNESSetJacobian() for calling sequence 337 - ctx - context for residual evaluation 338 339 Level: advanced 340 341 Note: 342 SNESGetJacobian() is normally used, but it calls this function internally because the user context is actually 343 associated with the DM. This makes the interface consistent regardless of whether the user interacts with a DM or 344 not. If DM took a more central role at some later date, this could become the primary method of setting the Jacobian. 345 346 .seealso: DMSNESSetContext(), SNESSetFunction(), DMSNESSetJacobian() 347 @*/ 348 PetscErrorCode DMSNESGetJacobian(DM dm,PetscErrorCode (**func)(SNES,Vec,Mat*,Mat*,MatStructure*,void*),void **ctx) 349 { 350 PetscErrorCode ierr; 351 SNESDM sdm; 352 353 PetscFunctionBegin; 354 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 355 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 356 if (func) *func = sdm->computejacobian; 357 if (ctx) *ctx = sdm->jacobianctx; 358 PetscFunctionReturn(0); 359 } 360 361 #undef __FUNCT__ 362 #define __FUNCT__ "SNESDefaultComputeFunction_DMLegacy" 363 static PetscErrorCode SNESDefaultComputeFunction_DMLegacy(SNES snes,Vec X,Vec F,void *ctx) 364 { 365 PetscErrorCode ierr; 366 DM dm; 367 368 PetscFunctionBegin; 369 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 370 ierr = DMComputeFunction(dm,X,F);CHKERRQ(ierr); 371 PetscFunctionReturn(0); 372 } 373 374 #undef __FUNCT__ 375 #define __FUNCT__ "SNESDefaultComputeJacobian_DMLegacy" 376 static PetscErrorCode SNESDefaultComputeJacobian_DMLegacy(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *ctx) 377 { 378 PetscErrorCode ierr; 379 DM dm; 380 381 PetscFunctionBegin; 382 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 383 ierr = DMComputeJacobian(dm,X,*A,*B,mstr);CHKERRQ(ierr); 384 PetscFunctionReturn(0); 385 } 386 387 #undef __FUNCT__ 388 #define __FUNCT__ "DMSNESSetUpLegacy" 389 /* Sets up calling of legacy DM routines */ 390 PetscErrorCode DMSNESSetUpLegacy(DM dm) 391 { 392 PetscErrorCode ierr; 393 SNESDM sdm; 394 395 PetscFunctionBegin; 396 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 397 if (!sdm->computefunction) {ierr = DMSNESSetFunction(dm,SNESDefaultComputeFunction_DMLegacy,PETSC_NULL);CHKERRQ(ierr);} 398 ierr = DMSNESGetContext(dm,&sdm);CHKERRQ(ierr); 399 if (!sdm->computejacobian) {ierr = DMSNESSetJacobian(dm,SNESDefaultComputeJacobian_DMLegacy,PETSC_NULL);CHKERRQ(ierr);} 400 PetscFunctionReturn(0); 401 } 402