Actual source code: dmdasnes.c
petsc-3.7.7 2017-09-25
1: #include <petscdmda.h> /*I "petscdmda.h" I*/
2: #include <petsc/private/dmimpl.h>
3: #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/
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,void*);
9: PetscErrorCode (*objectivelocal)(DMDALocalInfo*,void*,PetscReal*,void*);
10: void *residuallocalctx;
11: void *jacobianlocalctx;
12: void *objectivelocalctx;
13: InsertMode residuallocalimode;
15: /* For Picard iteration defined locally */
16: PetscErrorCode (*rhsplocal)(DMDALocalInfo*,void*,void*,void*);
17: PetscErrorCode (*jacobianplocal)(DMDALocalInfo*,void*,Mat,Mat,void*);
18: void *picardlocalctx;
19: } DMSNES_DA;
23: static PetscErrorCode DMSNESDestroy_DMDA(DMSNES sdm)
24: {
28: PetscFree(sdm->data);
29: return(0);
30: }
34: static PetscErrorCode DMSNESDuplicate_DMDA(DMSNES oldsdm,DMSNES sdm)
35: {
39: PetscNewLog(sdm,(DMSNES_DA**)&sdm->data);
40: if (oldsdm->data) {
41: PetscMemcpy(sdm->data,oldsdm->data,sizeof(DMSNES_DA));
42: }
43: return(0);
44: }
49: static PetscErrorCode DMDASNESGetContext(DM dm,DMSNES sdm,DMSNES_DA **dmdasnes)
50: {
54: *dmdasnes = NULL;
55: if (!sdm->data) {
56: PetscNewLog(dm,(DMSNES_DA**)&sdm->data);
57: sdm->ops->destroy = DMSNESDestroy_DMDA;
58: sdm->ops->duplicate = DMSNESDuplicate_DMDA;
59: }
60: *dmdasnes = (DMSNES_DA*)sdm->data;
61: return(0);
62: }
66: static PetscErrorCode SNESComputeFunction_DMDA(SNES snes,Vec X,Vec F,void *ctx)
67: {
69: DM dm;
70: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
71: DMDALocalInfo info;
72: Vec Xloc;
73: void *x,*f;
79: if (!dmdasnes->residuallocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
80: SNESGetDM(snes,&dm);
81: DMGetLocalVector(dm,&Xloc);
82: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
83: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
84: DMDAGetLocalInfo(dm,&info);
85: DMDAVecGetArray(dm,Xloc,&x);
86: switch (dmdasnes->residuallocalimode) {
87: case INSERT_VALUES: {
88: DMDAVecGetArray(dm,F,&f);
89: PetscLogEventBegin(SNES_FunctionEval,snes,X,F,0);
90: CHKMEMQ;
91: (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
92: CHKMEMQ;
93: PetscLogEventEnd(SNES_FunctionEval,snes,X,F,0);
94: DMDAVecRestoreArray(dm,F,&f);
95: } break;
96: case ADD_VALUES: {
97: Vec Floc;
98: DMGetLocalVector(dm,&Floc);
99: VecZeroEntries(Floc);
100: DMDAVecGetArray(dm,Floc,&f);
101: PetscLogEventBegin(SNES_FunctionEval,snes,X,F,0);
102: CHKMEMQ;
103: (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
104: CHKMEMQ;
105: PetscLogEventEnd(SNES_FunctionEval,snes,X,F,0);
106: DMDAVecRestoreArray(dm,Floc,&f);
107: VecZeroEntries(F);
108: DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
109: DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
110: DMRestoreLocalVector(dm,&Floc);
111: } break;
112: default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
113: }
114: DMDAVecRestoreArray(dm,Xloc,&x);
115: DMRestoreLocalVector(dm,&Xloc);
116: if (snes->domainerror) {
117: VecSetInf(F);
118: }
119: return(0);
120: }
124: static PetscErrorCode SNESComputeObjective_DMDA(SNES snes,Vec X,PetscReal *ob,void *ctx)
125: {
127: DM dm;
128: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
129: DMDALocalInfo info;
130: Vec Xloc;
131: void *x;
137: if (!dmdasnes->objectivelocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
138: SNESGetDM(snes,&dm);
139: DMGetLocalVector(dm,&Xloc);
140: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
141: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
142: DMDAGetLocalInfo(dm,&info);
143: DMDAVecGetArray(dm,Xloc,&x);
144: CHKMEMQ;
145: (*dmdasnes->objectivelocal)(&info,x,ob,dmdasnes->objectivelocalctx);
146: CHKMEMQ;
147: DMDAVecRestoreArray(dm,Xloc,&x);
148: DMRestoreLocalVector(dm,&Xloc);
149: return(0);
150: }
155: /* Routine is called by example, hence must be labeled PETSC_EXTERN */
156: PETSC_EXTERN PetscErrorCode SNESComputeJacobian_DMDA(SNES snes,Vec X,Mat A,Mat B,void *ctx)
157: {
159: DM dm;
160: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
161: DMDALocalInfo info;
162: Vec Xloc;
163: void *x;
166: if (!dmdasnes->residuallocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
167: SNESGetDM(snes,&dm);
169: if (dmdasnes->jacobianlocal) {
170: DMGetLocalVector(dm,&Xloc);
171: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
172: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
173: DMDAGetLocalInfo(dm,&info);
174: DMDAVecGetArray(dm,Xloc,&x);
175: CHKMEMQ;
176: (*dmdasnes->jacobianlocal)(&info,x,A,B,dmdasnes->jacobianlocalctx);
177: CHKMEMQ;
178: DMDAVecRestoreArray(dm,Xloc,&x);
179: DMRestoreLocalVector(dm,&Xloc);
180: } else {
181: MatFDColoring fdcoloring;
182: PetscObjectQuery((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject*)&fdcoloring);
183: if (!fdcoloring) {
184: ISColoring coloring;
186: DMCreateColoring(dm,dm->coloringtype,&coloring);
187: MatFDColoringCreate(B,coloring,&fdcoloring);
188: switch (dm->coloringtype) {
189: case IS_COLORING_GLOBAL:
190: MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))SNESComputeFunction_DMDA,dmdasnes);
191: break;
192: default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_SUP,"No support for coloring type '%s'",ISColoringTypes[dm->coloringtype]);
193: }
194: PetscObjectSetOptionsPrefix((PetscObject)fdcoloring,((PetscObject)dm)->prefix);
195: MatFDColoringSetFromOptions(fdcoloring);
196: MatFDColoringSetUp(B,coloring,fdcoloring);
197: ISColoringDestroy(&coloring);
198: PetscObjectCompose((PetscObject)dm,"DMDASNES_FDCOLORING",(PetscObject)fdcoloring);
199: PetscObjectDereference((PetscObject)fdcoloring);
201: /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call
202: * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the
203: * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually
204: * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be
205: * taken when the PetscObjectList for the Vec inside MatFDColoring is destroyed.
206: */
207: PetscObjectDereference((PetscObject)dm);
208: }
209: MatFDColoringApply(B,fdcoloring,X,snes);
210: }
211: /* This will be redundant if the user called both, but it's too common to forget. */
212: if (A != B) {
213: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
214: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
215: }
216: return(0);
217: }
221: /*@C
222: DMDASNESSetFunctionLocal - set a local residual evaluation function
224: Logically Collective
226: Input Arguments:
227: + dm - DM to associate callback with
228: . imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
229: . func - local residual evaluation
230: - ctx - optional context for local residual evaluation
232: Calling sequence:
233: For PetscErrorCode (*func)(DMDALocalInfo *info,void *x, void *f, void *ctx),
234: + info - DMDALocalInfo defining the subdomain to evaluate the residual on
235: . x - dimensional pointer to state at which to evaluate residual (e.g. PetscScalar *x or **x or ***x)
236: . f - dimensional pointer to residual, write the residual here (e.g. PetscScalar *f or **f or ***f)
237: - ctx - optional context passed above
239: Level: beginner
241: .seealso: DMDASNESSetJacobianLocal(), DMSNESSetFunction(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
242: @*/
243: PetscErrorCode DMDASNESSetFunctionLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),void *ctx)
244: {
246: DMSNES sdm;
247: DMSNES_DA *dmdasnes;
251: DMGetDMSNESWrite(dm,&sdm);
252: DMDASNESGetContext(dm,sdm,&dmdasnes);
254: dmdasnes->residuallocalimode = imode;
255: dmdasnes->residuallocal = func;
256: dmdasnes->residuallocalctx = ctx;
258: DMSNESSetFunction(dm,SNESComputeFunction_DMDA,dmdasnes);
259: if (!sdm->ops->computejacobian) { /* Call us for the Jacobian too, can be overridden by the user. */
260: DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);
261: }
262: return(0);
263: }
267: /*@C
268: DMDASNESSetJacobianLocal - set a local Jacobian evaluation function
270: Logically Collective
272: Input Arguments:
273: + dm - DM to associate callback with
274: . func - local Jacobian evaluation
275: - ctx - optional context for local Jacobian evaluation
277: Calling sequence:
278: For PetscErrorCode (*func)(DMDALocalInfo *info,void *x,Mat J,Mat M,void *ctx),
279: + info - DMDALocalInfo defining the subdomain to evaluate the Jacobian at
280: . x - dimensional pointer to state at which to evaluate Jacobian (e.g. PetscScalar *x or **x or ***x)
281: . J - Mat object for the Jacobian
282: . M - Mat object for the Jacobian preconditioner matrix
283: - ctx - optional context passed above
285: Level: beginner
287: .seealso: DMDASNESSetFunctionLocal(), DMSNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
288: @*/
289: PetscErrorCode DMDASNESSetJacobianLocal(DM dm,PetscErrorCode (*func)(DMDALocalInfo*,void*,Mat,Mat,void*),void *ctx)
290: {
292: DMSNES sdm;
293: DMSNES_DA *dmdasnes;
297: DMGetDMSNESWrite(dm,&sdm);
298: DMDASNESGetContext(dm,sdm,&dmdasnes);
300: dmdasnes->jacobianlocal = func;
301: dmdasnes->jacobianlocalctx = ctx;
303: DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);
304: return(0);
305: }
310: /*@C
311: DMDASNESSetObjectiveLocal - set a local residual evaluation function
313: Logically Collective
315: Input Arguments:
316: + dm - DM to associate callback with
317: . func - local objective evaluation
318: - ctx - optional context for local residual evaluation
320: Calling sequence for func:
321: + info - DMDALocalInfo defining the subdomain to evaluate the residual on
322: . x - dimensional pointer to state at which to evaluate residual
323: . ob - eventual objective value
324: - ctx - optional context passed above
326: Level: beginner
328: .seealso: DMSNESSetFunction(), DMDASNESSetJacobianLocal(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
329: @*/
330: PetscErrorCode DMDASNESSetObjectiveLocal(DM dm,DMDASNESObjective func,void *ctx)
331: {
333: DMSNES sdm;
334: DMSNES_DA *dmdasnes;
338: DMGetDMSNESWrite(dm,&sdm);
339: DMDASNESGetContext(dm,sdm,&dmdasnes);
341: dmdasnes->objectivelocal = func;
342: dmdasnes->objectivelocalctx = ctx;
344: DMSNESSetObjective(dm,SNESComputeObjective_DMDA,dmdasnes);
345: return(0);
346: }
350: static PetscErrorCode SNESComputePicard_DMDA(SNES snes,Vec X,Vec F,void *ctx)
351: {
353: DM dm;
354: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
355: DMDALocalInfo info;
356: Vec Xloc;
357: void *x,*f;
363: if (!dmdasnes->rhsplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
364: SNESGetDM(snes,&dm);
365: DMGetLocalVector(dm,&Xloc);
366: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
367: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
368: DMDAGetLocalInfo(dm,&info);
369: DMDAVecGetArray(dm,Xloc,&x);
370: switch (dmdasnes->residuallocalimode) {
371: case INSERT_VALUES: {
372: DMDAVecGetArray(dm,F,&f);
373: CHKMEMQ;
374: (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
375: CHKMEMQ;
376: DMDAVecRestoreArray(dm,F,&f);
377: } break;
378: case ADD_VALUES: {
379: Vec Floc;
380: DMGetLocalVector(dm,&Floc);
381: VecZeroEntries(Floc);
382: DMDAVecGetArray(dm,Floc,&f);
383: CHKMEMQ;
384: (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
385: CHKMEMQ;
386: DMDAVecRestoreArray(dm,Floc,&f);
387: VecZeroEntries(F);
388: DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
389: DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
390: DMRestoreLocalVector(dm,&Floc);
391: } break;
392: default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
393: }
394: DMDAVecRestoreArray(dm,Xloc,&x);
395: DMRestoreLocalVector(dm,&Xloc);
396: return(0);
397: }
401: static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes,Vec X,Mat A,Mat B,void *ctx)
402: {
404: DM dm;
405: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
406: DMDALocalInfo info;
407: Vec Xloc;
408: void *x;
411: if (!dmdasnes->jacobianplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
412: SNESGetDM(snes,&dm);
414: DMGetLocalVector(dm,&Xloc);
415: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
416: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
417: DMDAGetLocalInfo(dm,&info);
418: DMDAVecGetArray(dm,Xloc,&x);
419: CHKMEMQ;
420: (*dmdasnes->jacobianplocal)(&info,x,A,B,dmdasnes->picardlocalctx);
421: CHKMEMQ;
422: DMDAVecRestoreArray(dm,Xloc,&x);
423: DMRestoreLocalVector(dm,&Xloc);
424: if (A != B) {
425: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
426: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
427: }
428: return(0);
429: }
433: /*@C
434: DMDASNESSetPicardLocal - set a local right hand side and matrix evaluation function for Picard iteration
436: Logically Collective
438: Input Arguments:
439: + dm - DM to associate callback with
440: . imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
441: . func - local residual evaluation
442: - ctx - optional context for local residual evaluation
444: Calling sequence for func:
445: + info - DMDALocalInfo defining the subdomain to evaluate the residual on
446: . x - dimensional pointer to state at which to evaluate residual
447: . f - dimensional pointer to residual, write the residual here
448: - ctx - optional context passed above
450: Notes: The user must use
451: extern PetscErrorCode SNESPicardComputeFunction(SNES,Vec,Vec,void*);
452: extern PetscErrorCode SNESPicardComputeJacobian(SNES,Vec,Mat,Mat,MatStructure*,void*);
453: SNESSetFunction(snes,NULL,SNESPicardComputeFunction,&user);
454: in their code before calling this routine.
457: Level: beginner
459: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
460: @*/
461: PetscErrorCode DMDASNESSetPicardLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),
462: PetscErrorCode (*jac)(DMDALocalInfo*,void*,Mat,Mat,void*),void *ctx)
463: {
465: DMSNES sdm;
466: DMSNES_DA *dmdasnes;
470: DMGetDMSNESWrite(dm,&sdm);
471: DMDASNESGetContext(dm,sdm,&dmdasnes);
473: dmdasnes->residuallocalimode = imode;
474: dmdasnes->rhsplocal = func;
475: dmdasnes->jacobianplocal = jac;
476: dmdasnes->picardlocalctx = ctx;
478: DMSNESSetPicard(dm,SNESComputePicard_DMDA,SNESComputePicardJacobian_DMDA,dmdasnes);
479: return(0);
480: }