Actual source code: dmdasnes.c
petsc-dev 2014-02-02
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,MatStructure*,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,MatStructure*,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: /*
67: This function should eventually replace:
68: DMDAComputeFunction() and DMDAComputeFunction1()
69: */
70: static PetscErrorCode SNESComputeFunction_DMDA(SNES snes,Vec X,Vec F,void *ctx)
71: {
73: DM dm;
74: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
75: DMDALocalInfo info;
76: Vec Xloc;
77: void *x,*f;
83: if (!dmdasnes->residuallocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
84: SNESGetDM(snes,&dm);
85: DMGetLocalVector(dm,&Xloc);
86: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
87: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
88: DMDAGetLocalInfo(dm,&info);
89: DMDAVecGetArray(dm,Xloc,&x);
90: switch (dmdasnes->residuallocalimode) {
91: case INSERT_VALUES: {
92: DMDAVecGetArray(dm,F,&f);
93: CHKMEMQ;
94: (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
95: CHKMEMQ;
96: DMDAVecRestoreArray(dm,F,&f);
97: } break;
98: case ADD_VALUES: {
99: Vec Floc;
100: DMGetLocalVector(dm,&Floc);
101: VecZeroEntries(Floc);
102: DMDAVecGetArray(dm,Floc,&f);
103: CHKMEMQ;
104: (*dmdasnes->residuallocal)(&info,x,f,dmdasnes->residuallocalctx);
105: CHKMEMQ;
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: return(0);
117: }
121: /*
122: This function should eventually replace:
123: DMDAComputeFunction() and DMDAComputeFunction1()
124: */
125: static PetscErrorCode SNESComputeObjective_DMDA(SNES snes,Vec X,PetscReal *ob,void *ctx)
126: {
128: DM dm;
129: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
130: DMDALocalInfo info;
131: Vec Xloc;
132: void *x;
138: if (!dmdasnes->objectivelocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
139: SNESGetDM(snes,&dm);
140: DMGetLocalVector(dm,&Xloc);
141: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
142: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
143: DMDAGetLocalInfo(dm,&info);
144: DMDAVecGetArray(dm,Xloc,&x);
145: CHKMEMQ;
146: (*dmdasnes->objectivelocal)(&info,x,ob,dmdasnes->objectivelocalctx);
147: CHKMEMQ;
148: DMDAVecRestoreArray(dm,Xloc,&x);
149: DMRestoreLocalVector(dm,&Xloc);
150: return(0);
151: }
156: static PetscErrorCode SNESComputeJacobian_DMDA(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,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,mstr,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: *mstr = SAME_NONZERO_PATTERN;
210: MatFDColoringApply(*B,fdcoloring,X,mstr,snes);
211: }
212: /* This will be redundant if the user called both, but it's too common to forget. */
213: if (*A != *B) {
214: MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);
215: MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);
216: }
217: return(0);
218: }
222: /*@C
223: DMDASNESSetFunctionLocal - set a local residual evaluation function
225: Logically Collective
227: Input Arguments:
228: + dm - DM to associate callback with
229: . imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
230: . func - local residual evaluation
231: - ctx - optional context for local residual evaluation
233: Calling sequence for func:
234: + info - DMDALocalInfo defining the subdomain to evaluate the residual on
235: . x - dimensional pointer to state at which to evaluate residual
236: . f - dimensional pointer to residual, write the residual here
237: - ctx - optional context passed above
239: Level: beginner
241: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), 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 residual evaluation
275: - ctx - optional context for local residual evaluation
277: Calling sequence for func:
278: + info - DMDALocalInfo defining the subdomain to evaluate the residual on
279: . x - dimensional pointer to state at which to evaluate residual
280: . f - dimensional pointer to residual, write the residual here
281: - ctx - optional context passed above
283: Level: beginner
285: .seealso: DMSNESSetJacobian(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
286: @*/
287: PetscErrorCode DMDASNESSetJacobianLocal(DM dm,PetscErrorCode (*func)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*),void *ctx)
288: {
290: DMSNES sdm;
291: DMSNES_DA *dmdasnes;
295: DMGetDMSNESWrite(dm,&sdm);
296: DMDASNESGetContext(dm,sdm,&dmdasnes);
298: dmdasnes->jacobianlocal = func;
299: dmdasnes->jacobianlocalctx = ctx;
301: DMSNESSetJacobian(dm,SNESComputeJacobian_DMDA,dmdasnes);
302: return(0);
303: }
308: /*@C
309: DMDASNESSetObjectiveLocal - set a local residual evaluation function
311: Logically Collective
313: Input Arguments:
314: + dm - DM to associate callback with
315: . func - local objective evaluation
316: - ctx - optional context for local residual evaluation
318: Calling sequence for func:
319: + info - DMDALocalInfo defining the subdomain to evaluate the residual on
320: . x - dimensional pointer to state at which to evaluate residual
321: . ob - eventual objective value
322: - ctx - optional context passed above
324: Level: beginner
326: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
327: @*/
328: PetscErrorCode DMDASNESSetObjectiveLocal(DM dm,DMDASNESObjective func,void *ctx)
329: {
331: DMSNES sdm;
332: DMSNES_DA *dmdasnes;
336: DMGetDMSNESWrite(dm,&sdm);
337: DMDASNESGetContext(dm,sdm,&dmdasnes);
339: dmdasnes->objectivelocal = func;
340: dmdasnes->objectivelocalctx = ctx;
342: DMSNESSetObjective(dm,SNESComputeObjective_DMDA,dmdasnes);
343: return(0);
344: }
348: static PetscErrorCode SNESComputePicard_DMDA(SNES snes,Vec X,Vec F,void *ctx)
349: {
351: DM dm;
352: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
353: DMDALocalInfo info;
354: Vec Xloc;
355: void *x,*f;
361: if (!dmdasnes->rhsplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
362: SNESGetDM(snes,&dm);
363: DMGetLocalVector(dm,&Xloc);
364: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
365: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
366: DMDAGetLocalInfo(dm,&info);
367: DMDAVecGetArray(dm,Xloc,&x);
368: switch (dmdasnes->residuallocalimode) {
369: case INSERT_VALUES: {
370: DMDAVecGetArray(dm,F,&f);
371: CHKMEMQ;
372: (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
373: CHKMEMQ;
374: DMDAVecRestoreArray(dm,F,&f);
375: } break;
376: case ADD_VALUES: {
377: Vec Floc;
378: DMGetLocalVector(dm,&Floc);
379: VecZeroEntries(Floc);
380: DMDAVecGetArray(dm,Floc,&f);
381: CHKMEMQ;
382: (*dmdasnes->rhsplocal)(&info,x,f,dmdasnes->picardlocalctx);
383: CHKMEMQ;
384: DMDAVecRestoreArray(dm,Floc,&f);
385: VecZeroEntries(F);
386: DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
387: DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
388: DMRestoreLocalVector(dm,&Floc);
389: } break;
390: default: SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_INCOMP,"Cannot use imode=%d",(int)dmdasnes->residuallocalimode);
391: }
392: DMDAVecRestoreArray(dm,Xloc,&x);
393: DMRestoreLocalVector(dm,&Xloc);
394: return(0);
395: }
399: static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *mstr,void *ctx)
400: {
402: DM dm;
403: DMSNES_DA *dmdasnes = (DMSNES_DA*)ctx;
404: DMDALocalInfo info;
405: Vec Xloc;
406: void *x;
409: if (!dmdasnes->jacobianplocal) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_PLIB,"Corrupt context");
410: SNESGetDM(snes,&dm);
412: DMGetLocalVector(dm,&Xloc);
413: DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
414: DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
415: DMDAGetLocalInfo(dm,&info);
416: DMDAVecGetArray(dm,Xloc,&x);
417: CHKMEMQ;
418: (*dmdasnes->jacobianplocal)(&info,x,*A,*B,mstr,dmdasnes->picardlocalctx);
419: CHKMEMQ;
420: DMDAVecRestoreArray(dm,Xloc,&x);
421: DMRestoreLocalVector(dm,&Xloc);
422: *mstr = SAME_NONZERO_PATTERN;
423: if (*A != *B) {
424: MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY);
425: MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY);
426: }
427: return(0);
428: }
432: /*@C
433: DMDASNESSetPicardLocal - set a local right hand side and matrix evaluation function for Picard iteration
435: Logically Collective
437: Input Arguments:
438: + dm - DM to associate callback with
439: . imode - INSERT_VALUES if local function computes owned part, ADD_VALUES if it contributes to ghosted part
440: . func - local residual evaluation
441: - ctx - optional context for local residual evaluation
443: Calling sequence for func:
444: + info - DMDALocalInfo defining the subdomain to evaluate the residual on
445: . x - dimensional pointer to state at which to evaluate residual
446: . f - dimensional pointer to residual, write the residual here
447: - ctx - optional context passed above
449: Notes: The user must use
450: extern PetscErrorCode SNESPicardComputeFunction(SNES,Vec,Vec,void*);
451: extern PetscErrorCode SNESPicardComputeJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
452: SNESSetFunction(snes,NULL,SNESPicardComputeFunction,&user);
453: in their code before calling this routine.
456: Level: beginner
458: .seealso: DMSNESSetFunction(), DMDASNESSetJacobian(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d()
459: @*/
460: PetscErrorCode DMDASNESSetPicardLocal(DM dm,InsertMode imode,PetscErrorCode (*func)(DMDALocalInfo*,void*,void*,void*),
461: PetscErrorCode (*jac)(DMDALocalInfo*,void*,Mat,Mat,MatStructure*,void*),void *ctx)
462: {
464: DMSNES sdm;
465: DMSNES_DA *dmdasnes;
469: DMGetDMSNESWrite(dm,&sdm);
470: DMDASNESGetContext(dm,sdm,&dmdasnes);
472: dmdasnes->residuallocalimode = imode;
473: dmdasnes->rhsplocal = func;
474: dmdasnes->jacobianplocal = jac;
475: dmdasnes->picardlocalctx = ctx;
477: DMSNESSetPicard(dm,SNESComputePicard_DMDA,SNESComputePicardJacobian_DMDA,dmdasnes);
478: return(0);
479: }