xref: /petsc/src/snes/utils/dmsnes.c (revision 1db2f0e57964f94f63a3f5cf6bb1e5befdb56f30)
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