xref: /petsc/src/dm/impls/shell/dmshell.c (revision feff33ee0b5b037fa8f9f294dede656a2f85cc47)
1 #include <petscdmshell.h>       /*I    "petscdmshell.h"  I*/
2 #include <petscmat.h>
3 #include <petsc/private/dmimpl.h>
4 
5 typedef struct  {
6   Vec        Xglobal;
7   Vec        Xlocal;
8   Mat        A;
9   VecScatter gtol;
10   VecScatter ltog;
11   VecScatter ltol;
12   void       *ctx;
13 } DM_Shell;
14 
15 /*@
16    DMGlobalToLocalBeginDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to begin a global to local scatter
17    Collective
18 
19    Input Arguments:
20 +  dm - shell DM
21 .  g - global vector
22 .  mode - InsertMode
23 -  l - local vector
24 
25    Level: advanced
26 
27    Note:  This is not normally called directly by user code, generally user code calls DMGlobalToLocalBegin() and DMGlobalToLocalEnd(). If the user provides their own custom routines to DMShellSetLocalToGlobal() then those routines might have reason to call this function.
28 
29 .seealso: DMGlobalToLocalEndDefaultShell()
30 @*/
31 PetscErrorCode DMGlobalToLocalBeginDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
32 {
33   PetscErrorCode ierr;
34   DM_Shell       *shell = (DM_Shell*)dm->data;
35 
36   PetscFunctionBegin;
37   if (!shell->gtol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
38   ierr = VecScatterBegin(shell->gtol,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
39   PetscFunctionReturn(0);
40 }
41 
42 /*@
43    DMGlobalToLocalEndDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to end a global to local scatter
44    Collective
45 
46    Input Arguments:
47 +  dm - shell DM
48 .  g - global vector
49 .  mode - InsertMode
50 -  l - local vector
51 
52    Level: advanced
53 
54 .seealso: DMGlobalToLocalBeginDefaultShell()
55 @*/
56 PetscErrorCode DMGlobalToLocalEndDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
57 {
58   PetscErrorCode ierr;
59   DM_Shell       *shell = (DM_Shell*)dm->data;
60 
61   PetscFunctionBegin;
62    if (!shell->gtol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
63   ierr = VecScatterEnd(shell->gtol,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
64   PetscFunctionReturn(0);
65 }
66 
67 /*@
68    DMLocalToGlobalBeginDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to begin a local to global scatter
69    Collective
70 
71    Input Arguments:
72 +  dm - shell DM
73 .  l - local vector
74 .  mode - InsertMode
75 -  g - global vector
76 
77    Level: advanced
78 
79    Note:  This is not normally called directly by user code, generally user code calls DMLocalToGlobalBegin() and DMLocalToGlobalEnd(). If the user provides their own custom routines to DMShellSetLocalToGlobal() then those routines might have reason to call this function.
80 
81 .seealso: DMLocalToGlobalEndDefaultShell()
82 @*/
83 PetscErrorCode DMLocalToGlobalBeginDefaultShell(DM dm,Vec l,InsertMode mode,Vec g)
84 {
85   PetscErrorCode ierr;
86   DM_Shell       *shell = (DM_Shell*)dm->data;
87 
88   PetscFunctionBegin;
89   if (!shell->ltog) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToGlobalVecScatter()");
90   ierr = VecScatterBegin(shell->ltog,l,g,mode,SCATTER_FORWARD);CHKERRQ(ierr);
91   PetscFunctionReturn(0);
92 }
93 
94 /*@
95    DMLocalToGlobalEndDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to end a local to global scatter
96    Collective
97 
98    Input Arguments:
99 +  dm - shell DM
100 .  l - local vector
101 .  mode - InsertMode
102 -  g - global vector
103 
104    Level: advanced
105 
106 .seealso: DMLocalToGlobalBeginDefaultShell()
107 @*/
108 PetscErrorCode DMLocalToGlobalEndDefaultShell(DM dm,Vec l,InsertMode mode,Vec g)
109 {
110   PetscErrorCode ierr;
111   DM_Shell       *shell = (DM_Shell*)dm->data;
112 
113   PetscFunctionBegin;
114    if (!shell->ltog) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToGlobalVecScatter()");
115   ierr = VecScatterEnd(shell->ltog,l,g,mode,SCATTER_FORWARD);CHKERRQ(ierr);
116   PetscFunctionReturn(0);
117 }
118 
119 /*@
120    DMLocalToLocalBeginDefaultShell - Uses the LocalToLocal VecScatter context set by the user to begin a local to local scatter
121    Collective
122 
123    Input Arguments:
124 +  dm - shell DM
125 .  g - the original local vector
126 -  mode - InsertMode
127 
128    Output Parameter:
129 .  l  - the local vector with correct ghost values
130 
131    Level: advanced
132 
133    Note:  This is not normally called directly by user code, generally user code calls DMLocalToLocalBegin() and DMLocalToLocalEnd(). If the user provides their own custom routines to DMShellSetLocalToLocal() then those routines might have reason to call this function.
134 
135 .seealso: DMLocalToLocalEndDefaultShell()
136 @*/
137 PetscErrorCode DMLocalToLocalBeginDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
138 {
139   PetscErrorCode ierr;
140   DM_Shell       *shell = (DM_Shell*)dm->data;
141 
142   PetscFunctionBegin;
143   if (!shell->ltol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToLocalVecScatter()");
144   ierr = VecScatterBegin(shell->ltol,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
145   PetscFunctionReturn(0);
146 }
147 
148 /*@
149    DMLocalToLocalEndDefaultShell - Uses the LocalToLocal VecScatter context set by the user to end a local to local scatter
150    Collective
151 
152    Input Arguments:
153 +  dm - shell DM
154 .  g - the original local vector
155 -  mode - InsertMode
156 
157    Output Parameter:
158 .  l  - the local vector with correct ghost values
159 
160    Level: advanced
161 
162 .seealso: DMLocalToLocalBeginDefaultShell()
163 @*/
164 PetscErrorCode DMLocalToLocalEndDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
165 {
166   PetscErrorCode ierr;
167   DM_Shell       *shell = (DM_Shell*)dm->data;
168 
169   PetscFunctionBegin;
170    if (!shell->ltol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
171   ierr = VecScatterEnd(shell->ltol,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
172   PetscFunctionReturn(0);
173 }
174 
175 static PetscErrorCode DMCreateMatrix_Shell(DM dm,Mat *J)
176 {
177   PetscErrorCode ierr;
178   DM_Shell       *shell = (DM_Shell*)dm->data;
179   Mat            A;
180 
181   PetscFunctionBegin;
182   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
183   PetscValidPointer(J,3);
184   if (!shell->A) {
185     if (shell->Xglobal) {
186       PetscInt m,M;
187       ierr = PetscInfo(dm,"Naively creating matrix using global vector distribution without preallocation\n");CHKERRQ(ierr);
188       ierr = VecGetSize(shell->Xglobal,&M);CHKERRQ(ierr);
189       ierr = VecGetLocalSize(shell->Xglobal,&m);CHKERRQ(ierr);
190       ierr = MatCreate(PetscObjectComm((PetscObject)dm),&shell->A);CHKERRQ(ierr);
191       ierr = MatSetSizes(shell->A,m,m,M,M);CHKERRQ(ierr);
192       ierr = MatSetType(shell->A,dm->mattype);CHKERRQ(ierr);
193       ierr = MatSetUp(shell->A);CHKERRQ(ierr);
194     } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetMatrix(), DMShellSetCreateMatrix(), or provide a vector");
195   }
196   A = shell->A;
197   /* the check below is tacky and incomplete */
198   if (dm->mattype) {
199     PetscBool flg,aij,seqaij,mpiaij;
200     ierr = PetscObjectTypeCompare((PetscObject)A,dm->mattype,&flg);CHKERRQ(ierr);
201     ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&seqaij);CHKERRQ(ierr);
202     ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&mpiaij);CHKERRQ(ierr);
203     ierr = PetscStrcmp(dm->mattype,MATAIJ,&aij);CHKERRQ(ierr);
204     if (!flg) {
205       if (!(aij && (seqaij || mpiaij))) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Requested matrix of type %s, but only %s available",dm->mattype,((PetscObject)A)->type_name);
206     }
207   }
208   if (((PetscObject)A)->refct < 2) { /* We have an exclusive reference so we can give it out */
209     ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
210     ierr = MatZeroEntries(A);CHKERRQ(ierr);
211     *J   = A;
212   } else {                      /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */
213     ierr = MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,J);CHKERRQ(ierr);
214     ierr = MatZeroEntries(*J);CHKERRQ(ierr);
215   }
216   PetscFunctionReturn(0);
217 }
218 
219 PetscErrorCode DMCreateGlobalVector_Shell(DM dm,Vec *gvec)
220 {
221   PetscErrorCode ierr;
222   DM_Shell       *shell = (DM_Shell*)dm->data;
223   Vec            X;
224 
225   PetscFunctionBegin;
226   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
227   PetscValidPointer(gvec,2);
228   *gvec = 0;
229   X     = shell->Xglobal;
230   if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetGlobalVector() or DMShellSetCreateGlobalVector()");
231   if (((PetscObject)X)->refct < 2) { /* We have an exclusive reference so we can give it out */
232     ierr  = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
233     ierr  = VecZeroEntries(X);CHKERRQ(ierr);
234     *gvec = X;
235   } else {                      /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */
236     ierr = VecDuplicate(X,gvec);CHKERRQ(ierr);
237     ierr = VecZeroEntries(*gvec);CHKERRQ(ierr);
238   }
239   ierr = VecSetDM(*gvec,dm);CHKERRQ(ierr);
240   PetscFunctionReturn(0);
241 }
242 
243 PetscErrorCode DMCreateLocalVector_Shell(DM dm,Vec *gvec)
244 {
245   PetscErrorCode ierr;
246   DM_Shell       *shell = (DM_Shell*)dm->data;
247   Vec            X;
248 
249   PetscFunctionBegin;
250   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
251   PetscValidPointer(gvec,2);
252   *gvec = 0;
253   X     = shell->Xlocal;
254   if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetLocalVector() or DMShellSetCreateLocalVector()");
255   if (((PetscObject)X)->refct < 2) { /* We have an exclusive reference so we can give it out */
256     ierr  = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
257     ierr  = VecZeroEntries(X);CHKERRQ(ierr);
258     *gvec = X;
259   } else {                      /* Need to create a copy, could use MAT_SHARE_NONZERO_PATTERN in most cases */
260     ierr = VecDuplicate(X,gvec);CHKERRQ(ierr);
261     ierr = VecZeroEntries(*gvec);CHKERRQ(ierr);
262   }
263   ierr = VecSetDM(*gvec,dm);CHKERRQ(ierr);
264   PetscFunctionReturn(0);
265 }
266 
267 /*@
268    DMShellSetContext - set some data to be usable by this DM
269 
270    Collective
271 
272    Input Arguments:
273 +  dm - shell DM
274 -  ctx - the context
275 
276    Level: advanced
277 
278 .seealso: DMCreateMatrix(), DMShellGetContext()
279 @*/
280 PetscErrorCode DMShellSetContext(DM dm,void *ctx)
281 {
282   DM_Shell       *shell = (DM_Shell*)dm->data;
283   PetscErrorCode ierr;
284   PetscBool      isshell;
285 
286   PetscFunctionBegin;
287   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
288   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
289   if (!isshell) PetscFunctionReturn(0);
290   shell->ctx = ctx;
291   PetscFunctionReturn(0);
292 }
293 
294 /*@
295    DMShellGetContext - set some data to be usable by this DM
296 
297    Collective
298 
299    Input Argument:
300 .  dm - shell DM
301 
302    Output Argument:
303 .  ctx - the context
304 
305    Level: advanced
306 
307 .seealso: DMCreateMatrix(), DMShellSetContext()
308 @*/
309 PetscErrorCode DMShellGetContext(DM dm,void **ctx)
310 {
311   DM_Shell       *shell = (DM_Shell*)dm->data;
312   PetscErrorCode ierr;
313   PetscBool      isshell;
314 
315   PetscFunctionBegin;
316   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
317   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
318   if (!isshell) PetscFunctionReturn(0);
319   *ctx = shell->ctx;
320   PetscFunctionReturn(0);
321 }
322 
323 /*@
324    DMShellSetMatrix - sets a template matrix associated with the DMShell
325 
326    Collective
327 
328    Input Arguments:
329 +  dm - shell DM
330 -  J - template matrix
331 
332    Level: advanced
333 
334 .seealso: DMCreateMatrix(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
335 @*/
336 PetscErrorCode DMShellSetMatrix(DM dm,Mat J)
337 {
338   DM_Shell       *shell = (DM_Shell*)dm->data;
339   PetscErrorCode ierr;
340   PetscBool      isshell;
341 
342   PetscFunctionBegin;
343   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
344   PetscValidHeaderSpecific(J,MAT_CLASSID,2);
345   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
346   if (!isshell) PetscFunctionReturn(0);
347   ierr     = PetscObjectReference((PetscObject)J);CHKERRQ(ierr);
348   ierr     = MatDestroy(&shell->A);CHKERRQ(ierr);
349   shell->A = J;
350   PetscFunctionReturn(0);
351 }
352 
353 /*@C
354    DMShellSetCreateMatrix - sets the routine to create a matrix associated with the shell DM
355 
356    Logically Collective on DM
357 
358    Input Arguments:
359 +  dm - the shell DM
360 -  func - the function to create a matrix
361 
362    Level: advanced
363 
364 .seealso: DMCreateMatrix(), DMShellSetMatrix(), DMShellSetContext(), DMShellGetContext()
365 @*/
366 PetscErrorCode DMShellSetCreateMatrix(DM dm,PetscErrorCode (*func)(DM,Mat*))
367 {
368 
369   PetscFunctionBegin;
370   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
371   dm->ops->creatematrix = func;
372   PetscFunctionReturn(0);
373 }
374 
375 /*@
376    DMShellSetGlobalVector - sets a template global vector associated with the DMShell
377 
378    Logically Collective on DM
379 
380    Input Arguments:
381 +  dm - shell DM
382 -  X - template vector
383 
384    Level: advanced
385 
386 .seealso: DMCreateGlobalVector(), DMShellSetMatrix(), DMShellSetCreateGlobalVector()
387 @*/
388 PetscErrorCode DMShellSetGlobalVector(DM dm,Vec X)
389 {
390   DM_Shell       *shell = (DM_Shell*)dm->data;
391   PetscErrorCode ierr;
392   PetscBool      isshell;
393   DM             vdm;
394 
395   PetscFunctionBegin;
396   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
397   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
398   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
399   if (!isshell) PetscFunctionReturn(0);
400   ierr = VecGetDM(X,&vdm);CHKERRQ(ierr);
401   /*
402       if the vector proposed as the new base global vector for the DM is a DM vector associated
403       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
404       we get a circular dependency that prevents the DM from being destroy when it should be.
405       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
406       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
407       to set its input vector (which is associated with the DM) as the base global vector.
408       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
409       for pointing out the problem.
410    */
411   if (vdm == dm) PetscFunctionReturn(0);
412   ierr           = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
413   ierr           = VecDestroy(&shell->Xglobal);CHKERRQ(ierr);
414   shell->Xglobal = X;
415   PetscFunctionReturn(0);
416 }
417 
418 /*@C
419    DMShellSetCreateGlobalVector - sets the routine to create a global vector associated with the shell DM
420 
421    Logically Collective
422 
423    Input Arguments:
424 +  dm - the shell DM
425 -  func - the creation routine
426 
427    Level: advanced
428 
429 .seealso: DMShellSetGlobalVector(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
430 @*/
431 PetscErrorCode DMShellSetCreateGlobalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
432 {
433 
434   PetscFunctionBegin;
435   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
436   dm->ops->createglobalvector = func;
437   PetscFunctionReturn(0);
438 }
439 
440 /*@
441    DMShellSetLocalVector - sets a template local vector associated with the DMShell
442 
443    Logically Collective on DM
444 
445    Input Arguments:
446 +  dm - shell DM
447 -  X - template vector
448 
449    Level: advanced
450 
451 .seealso: DMCreateLocalVector(), DMShellSetMatrix(), DMShellSetCreateLocalVector()
452 @*/
453 PetscErrorCode DMShellSetLocalVector(DM dm,Vec X)
454 {
455   DM_Shell       *shell = (DM_Shell*)dm->data;
456   PetscErrorCode ierr;
457   PetscBool      isshell;
458   DM             vdm;
459 
460   PetscFunctionBegin;
461   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
462   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
463   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
464   if (!isshell) PetscFunctionReturn(0);
465   ierr           = VecGetDM(X,&vdm);CHKERRQ(ierr);
466   /*
467       if the vector proposed as the new base global vector for the DM is a DM vector associated
468       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
469       we get a circular dependency that prevents the DM from being destroy when it should be.
470       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
471       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
472       to set its input vector (which is associated with the DM) as the base global vector.
473       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
474       for pointing out the problem.
475    */
476   if (vdm == dm) PetscFunctionReturn(0);
477   ierr = PetscObjectReference((PetscObject)X);CHKERRQ(ierr);
478   ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr);
479   shell->Xlocal = X;
480   PetscFunctionReturn(0);
481 }
482 
483 /*@C
484    DMShellSetCreateLocalVector - sets the routine to create a local vector associated with the shell DM
485 
486    Logically Collective
487 
488    Input Arguments:
489 +  dm - the shell DM
490 -  func - the creation routine
491 
492    Level: advanced
493 
494 .seealso: DMShellSetLocalVector(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
495 @*/
496 PetscErrorCode DMShellSetCreateLocalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
497 {
498 
499   PetscFunctionBegin;
500   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
501   dm->ops->createlocalvector = func;
502   PetscFunctionReturn(0);
503 }
504 
505 /*@C
506    DMShellSetGlobalToLocal - Sets the routines used to perform a global to local scatter
507 
508    Logically Collective on DM
509 
510    Input Arguments
511 +  dm - the shell DM
512 .  begin - the routine that begins the global to local scatter
513 -  end - the routine that ends the global to local scatter
514 
515    Notes: If these functions are not provided but DMShellSetGlobalToLocalVecScatter() is called then
516    DMGlobalToLocalBeginDefaultShell()/DMGlobalToLocalEndDefaultShell() are used to to perform the transfers
517 
518    Level: advanced
519 
520 .seealso: DMShellSetLocalToGlobal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
521 @*/
522 PetscErrorCode DMShellSetGlobalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
523   PetscFunctionBegin;
524   dm->ops->globaltolocalbegin = begin;
525   dm->ops->globaltolocalend = end;
526   PetscFunctionReturn(0);
527 }
528 
529 /*@C
530    DMShellSetLocalToGlobal - Sets the routines used to perform a local to global scatter
531 
532    Logically Collective on DM
533 
534    Input Arguments
535 +  dm - the shell DM
536 .  begin - the routine that begins the local to global scatter
537 -  end - the routine that ends the local to global scatter
538 
539    Notes: If these functions are not provided but DMShellSetLocalToGlobalVecScatter() is called then
540    DMLocalToGlobalBeginDefaultShell()/DMLocalToGlobalEndDefaultShell() are used to to perform the transfers
541 
542    Level: advanced
543 
544 .seealso: DMShellSetGlobalToLocal()
545 @*/
546 PetscErrorCode DMShellSetLocalToGlobal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
547   PetscFunctionBegin;
548   dm->ops->localtoglobalbegin = begin;
549   dm->ops->localtoglobalend = end;
550   PetscFunctionReturn(0);
551 }
552 
553 /*@C
554    DMShellSetLocalToLocal - Sets the routines used to perform a local to local scatter
555 
556    Logically Collective on DM
557 
558    Input Arguments
559 +  dm - the shell DM
560 .  begin - the routine that begins the local to local scatter
561 -  end - the routine that ends the local to local scatter
562 
563    Notes: If these functions are not provided but DMShellSetLocalToLocalVecScatter() is called then
564    DMLocalToLocalBeginDefaultShell()/DMLocalToLocalEndDefaultShell() are used to to perform the transfers
565 
566    Level: advanced
567 
568 .seealso: DMShellSetGlobalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
569 @*/
570 PetscErrorCode DMShellSetLocalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
571   PetscFunctionBegin;
572   dm->ops->localtolocalbegin = begin;
573   dm->ops->localtolocalend = end;
574   PetscFunctionReturn(0);
575 }
576 
577 /*@
578    DMShellSetGlobalToLocalVecScatter - Sets a VecScatter context for global to local communication
579 
580    Logically Collective on DM
581 
582    Input Arguments
583 +  dm - the shell DM
584 -  gtol - the global to local VecScatter context
585 
586    Level: advanced
587 
588 .seealso: DMShellSetGlobalToLocal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
589 @*/
590 PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter gtol)
591 {
592   DM_Shell       *shell = (DM_Shell*)dm->data;
593   PetscErrorCode ierr;
594 
595   PetscFunctionBegin;
596   ierr = PetscObjectReference((PetscObject)gtol);CHKERRQ(ierr);
597   /* Call VecScatterDestroy() to avoid a memory leak in case of re-setting. */
598   ierr = VecScatterDestroy(&shell->gtol);CHKERRQ(ierr);
599   shell->gtol = gtol;
600   PetscFunctionReturn(0);
601 }
602 
603 /*@
604    DMShellSetLocalToGlobalVecScatter - Sets a VecScatter context for local to global communication
605 
606    Logically Collective on DM
607 
608    Input Arguments
609 +  dm - the shell DM
610 -  ltog - the local to global VecScatter context
611 
612    Level: advanced
613 
614 .seealso: DMShellSetLocalToGlobal(), DMLocalToGlobalBeginDefaultShell(), DMLocalToGlobalEndDefaultShell()
615 @*/
616 PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter ltog)
617 {
618   DM_Shell       *shell = (DM_Shell*)dm->data;
619   PetscErrorCode ierr;
620 
621   PetscFunctionBegin;
622   ierr = PetscObjectReference((PetscObject)ltog);CHKERRQ(ierr);
623   /* Call VecScatterDestroy() to avoid a memory leak in case of re-setting. */
624   ierr = VecScatterDestroy(&shell->ltog);CHKERRQ(ierr);
625   shell->ltog = ltog;
626   PetscFunctionReturn(0);
627 }
628 
629 /*@
630    DMShellSetLocalToLocalVecScatter - Sets a VecScatter context for local to local communication
631 
632    Logically Collective on DM
633 
634    Input Arguments
635 +  dm - the shell DM
636 -  ltol - the local to local VecScatter context
637 
638    Level: advanced
639 
640 .seealso: DMShellSetLocalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
641 @*/
642 PetscErrorCode DMShellSetLocalToLocalVecScatter(DM dm, VecScatter ltol)
643 {
644   DM_Shell       *shell = (DM_Shell*)dm->data;
645   PetscErrorCode ierr;
646 
647   PetscFunctionBegin;
648   ierr = PetscObjectReference((PetscObject)ltol);CHKERRQ(ierr);
649   /* Call VecScatterDestroy() to avoid a memory leak in case of re-setting. */
650   ierr = VecScatterDestroy(&shell->ltol);CHKERRQ(ierr);
651   shell->ltol = ltol;
652   PetscFunctionReturn(0);
653 }
654 
655 /*@C
656    DMShellSetCoarsen - Set the routine used to coarsen the shell DM
657 
658    Logically Collective on DM
659 
660    Input Arguments
661 +  dm - the shell DM
662 -  coarsen - the routine that coarsens the DM
663 
664    Level: advanced
665 
666 .seealso: DMShellSetRefine(), DMCoarsen(), DMShellSetContext(), DMShellGetContext()
667 @*/
668 PetscErrorCode DMShellSetCoarsen(DM dm, PetscErrorCode (*coarsen)(DM,MPI_Comm,DM*))
669 {
670   PetscErrorCode ierr;
671   PetscBool      isshell;
672 
673   PetscFunctionBegin;
674   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
675   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
676   if (!isshell) PetscFunctionReturn(0);
677   dm->ops->coarsen = coarsen;
678   PetscFunctionReturn(0);
679 }
680 
681 /*@C
682    DMShellSetRefine - Set the routine used to refine the shell DM
683 
684    Logically Collective on DM
685 
686    Input Arguments
687 +  dm - the shell DM
688 -  refine - the routine that refines the DM
689 
690    Level: advanced
691 
692 .seealso: DMShellSetCoarsen(), DMRefine(), DMShellSetContext(), DMShellGetContext()
693 @*/
694 PetscErrorCode DMShellSetRefine(DM dm, PetscErrorCode (*refine)(DM,MPI_Comm,DM*))
695 {
696   PetscErrorCode ierr;
697   PetscBool      isshell;
698 
699   PetscFunctionBegin;
700   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
701   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
702   if (!isshell) PetscFunctionReturn(0);
703   dm->ops->refine = refine;
704   PetscFunctionReturn(0);
705 }
706 
707 /*@C
708    DMShellSetCreateInterpolation - Set the routine used to create the interpolation operator
709 
710    Logically Collective on DM
711 
712    Input Arguments
713 +  dm - the shell DM
714 -  interp - the routine to create the interpolation
715 
716    Level: advanced
717 
718 .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellSetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
719 @*/
720 PetscErrorCode DMShellSetCreateInterpolation(DM dm, PetscErrorCode (*interp)(DM,DM,Mat*,Vec*))
721 {
722   PetscErrorCode ierr;
723   PetscBool      isshell;
724 
725   PetscFunctionBegin;
726   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
727   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
728   if (!isshell) PetscFunctionReturn(0);
729   dm->ops->createinterpolation = interp;
730   PetscFunctionReturn(0);
731 }
732 
733 /*@C
734    DMShellSetCreateRestriction - Set the routine used to create the restriction operator
735 
736    Logically Collective on DM
737 
738    Input Arguments
739 +  dm - the shell DM
740 -  striction- the routine to create the restriction
741 
742    Level: advanced
743 
744 .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellSetContext(), DMShellGetContext()
745 @*/
746 PetscErrorCode DMShellSetCreateRestriction(DM dm, PetscErrorCode (*restriction)(DM,DM,Mat*))
747 {
748   PetscErrorCode ierr;
749   PetscBool      isshell;
750 
751   PetscFunctionBegin;
752   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
753   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
754   if (!isshell) PetscFunctionReturn(0);
755   dm->ops->createrestriction = restriction;
756   PetscFunctionReturn(0);
757 }
758 
759 /*@C
760    DMShellSetCreateInjection - Set the routine used to create the injection operator
761 
762    Logically Collective on DM
763 
764    Input Arguments
765 +  dm - the shell DM
766 -  inject - the routine to create the injection
767 
768    Level: advanced
769 
770 .seealso: DMShellSetCreateInterpolation(), DMCreateInjection(), DMShellSetContext(), DMShellGetContext()
771 @*/
772 PetscErrorCode DMShellSetCreateInjection(DM dm, PetscErrorCode (*inject)(DM,DM,Mat*))
773 {
774   PetscErrorCode ierr;
775   PetscBool      isshell;
776 
777   PetscFunctionBegin;
778   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
779   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
780   if (!isshell) PetscFunctionReturn(0);
781   dm->ops->getinjection = inject;
782   PetscFunctionReturn(0);
783 }
784 
785 static PetscErrorCode DMHasCreateInjection_Shell(DM dm, PetscBool *flg)
786 {
787   PetscErrorCode ierr;
788   PetscBool      isshell;
789 
790   PetscFunctionBegin;
791   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
792   PetscValidPointer(flg,2);
793   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
794   if (!isshell) {
795     *flg = PETSC_FALSE;
796   } else {
797     *flg = dm->ops->getinjection ? PETSC_TRUE : PETSC_FALSE;
798   }
799   PetscFunctionReturn(0);
800 }
801 /*@C
802    DMShellSetCreateFieldDecomposition - Set the routine used to create a decomposition of fields for the shell DM
803 
804    Logically Collective on DM
805 
806    Input Arguments
807 +  dm - the shell DM
808 -  decomp - the routine to create the decomposition
809 
810    Level: advanced
811 
812 .seealso: DMCreateFieldDecomposition(), DMShellSetContext(), DMShellGetContext()
813 @*/
814 PetscErrorCode DMShellSetCreateFieldDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,DM**))
815 {
816   PetscErrorCode ierr;
817   PetscBool      isshell;
818 
819   PetscFunctionBegin;
820   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
821   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
822   if (!isshell) PetscFunctionReturn(0);
823   dm->ops->createfielddecomposition = decomp;
824   PetscFunctionReturn(0);
825 }
826 
827 /*@C
828    DMShellSetCreateDomainDecomposition - Set the routine used to create a domain decomposition for the shell DM
829 
830    Logically Collective on DM
831 
832    Input Arguments
833 +  dm - the shell DM
834 -  decomp - the routine to create the decomposition
835 
836    Level: advanced
837 
838 .seealso: DMCreateDomainDecomposition(), DMShellSetContext(), DMShellGetContext()
839 @*/
840 PetscErrorCode DMShellSetCreateDomainDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,IS**,DM**))
841 {
842   PetscErrorCode ierr;
843   PetscBool      isshell;
844 
845   PetscFunctionBegin;
846   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
847   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
848   if (!isshell) PetscFunctionReturn(0);
849   dm->ops->createdomaindecomposition = decomp;
850   PetscFunctionReturn(0);
851 }
852 
853 /*@C
854    DMShellSetCreateDomainDecompositionScatters - Set the routine used to create the scatter contexts for domain decomposition with a shell DM
855 
856    Logically Collective on DM
857 
858    Input Arguments
859 +  dm - the shell DM
860 -  scatter - the routine to create the scatters
861 
862    Level: advanced
863 
864 .seealso: DMCreateDomainDecompositionScatters(), DMShellSetContext(), DMShellGetContext()
865 @*/
866 PetscErrorCode DMShellSetCreateDomainDecompositionScatters(DM dm, PetscErrorCode (*scatter)(DM,PetscInt,DM*,VecScatter**,VecScatter**,VecScatter**))
867 {
868   PetscErrorCode ierr;
869   PetscBool      isshell;
870 
871   PetscFunctionBegin;
872   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
873   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
874   if (!isshell) PetscFunctionReturn(0);
875   dm->ops->createddscatters = scatter;
876   PetscFunctionReturn(0);
877 }
878 
879 /*@C
880    DMShellSetCreateSubDM - Set the routine used to create a sub DM from the shell DM
881 
882    Logically Collective on DM
883 
884    Input Arguments
885 +  dm - the shell DM
886 -  subdm - the routine to create the decomposition
887 
888    Level: advanced
889 
890 .seealso: DMCreateSubDM(), DMShellSetContext(), DMShellGetContext()
891 @*/
892 PetscErrorCode DMShellSetCreateSubDM(DM dm, PetscErrorCode (*subdm)(DM,PetscInt,const PetscInt[],IS*,DM*))
893 {
894   PetscErrorCode ierr;
895   PetscBool      isshell;
896 
897   PetscFunctionBegin;
898   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
899   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
900   if (!isshell) PetscFunctionReturn(0);
901   dm->ops->createsubdm = subdm;
902   PetscFunctionReturn(0);
903 }
904 
905 static PetscErrorCode DMDestroy_Shell(DM dm)
906 {
907   PetscErrorCode ierr;
908   DM_Shell       *shell = (DM_Shell*)dm->data;
909 
910   PetscFunctionBegin;
911   ierr = MatDestroy(&shell->A);CHKERRQ(ierr);
912   ierr = VecDestroy(&shell->Xglobal);CHKERRQ(ierr);
913   ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr);
914   ierr = VecScatterDestroy(&shell->gtol);CHKERRQ(ierr);
915   ierr = VecScatterDestroy(&shell->ltog);CHKERRQ(ierr);
916   ierr = VecScatterDestroy(&shell->ltol);CHKERRQ(ierr);
917   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
918   ierr = PetscFree(shell);CHKERRQ(ierr);
919   PetscFunctionReturn(0);
920 }
921 
922 static PetscErrorCode DMView_Shell(DM dm,PetscViewer v)
923 {
924   PetscErrorCode ierr;
925   DM_Shell       *shell = (DM_Shell*)dm->data;
926 
927   PetscFunctionBegin;
928   ierr = VecView(shell->Xglobal,v);CHKERRQ(ierr);
929   PetscFunctionReturn(0);
930 }
931 
932 static PetscErrorCode DMLoad_Shell(DM dm,PetscViewer v)
933 {
934   PetscErrorCode ierr;
935   DM_Shell       *shell = (DM_Shell*)dm->data;
936 
937   PetscFunctionBegin;
938   ierr = VecCreate(PetscObjectComm((PetscObject)dm),&shell->Xglobal);CHKERRQ(ierr);
939   ierr = VecLoad(shell->Xglobal,v);CHKERRQ(ierr);
940   PetscFunctionReturn(0);
941 }
942 
943 PetscErrorCode DMCreateSubDM_Shell(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
944 {
945   PetscErrorCode ierr;
946 
947   PetscFunctionBegin;
948   if (subdm) {ierr = DMShellCreate(PetscObjectComm((PetscObject) dm), subdm);CHKERRQ(ierr);}
949   ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
950   PetscFunctionReturn(0);
951 }
952 
953 PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
954 {
955   PetscErrorCode ierr;
956   DM_Shell       *shell;
957 
958   PetscFunctionBegin;
959   ierr     = PetscNewLog(dm,&shell);CHKERRQ(ierr);
960   dm->data = shell;
961 
962   ierr = PetscObjectChangeTypeName((PetscObject)dm,DMSHELL);CHKERRQ(ierr);
963 
964   dm->ops->destroy            = DMDestroy_Shell;
965   dm->ops->createglobalvector = DMCreateGlobalVector_Shell;
966   dm->ops->createlocalvector  = DMCreateLocalVector_Shell;
967   dm->ops->creatematrix       = DMCreateMatrix_Shell;
968   dm->ops->view               = DMView_Shell;
969   dm->ops->load               = DMLoad_Shell;
970   dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell;
971   dm->ops->globaltolocalend   = DMGlobalToLocalEndDefaultShell;
972   dm->ops->localtoglobalbegin = DMLocalToGlobalBeginDefaultShell;
973   dm->ops->localtoglobalend   = DMLocalToGlobalEndDefaultShell;
974   dm->ops->localtolocalbegin  = DMLocalToLocalBeginDefaultShell;
975   dm->ops->localtolocalend    = DMLocalToLocalEndDefaultShell;
976   dm->ops->createsubdm        = DMCreateSubDM_Shell;
977   dm->ops->hascreateinjection = DMHasCreateInjection_Shell;
978   PetscFunctionReturn(0);
979 }
980 
981 /*@
982     DMShellCreate - Creates a shell DM object, used to manage user-defined problem data
983 
984     Collective on MPI_Comm
985 
986     Input Parameter:
987 .   comm - the processors that will share the global vector
988 
989     Output Parameters:
990 .   shell - the shell DM
991 
992     Level: advanced
993 
994 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateLocalVector(), DMShellSetContext(), DMShellGetContext()
995 @*/
996 PetscErrorCode  DMShellCreate(MPI_Comm comm,DM *dm)
997 {
998   PetscErrorCode ierr;
999 
1000   PetscFunctionBegin;
1001   PetscValidPointer(dm,2);
1002   ierr = DMCreate(comm,dm);CHKERRQ(ierr);
1003   ierr = DMSetType(*dm,DMSHELL);CHKERRQ(ierr);
1004   ierr = DMSetUp(*dm);CHKERRQ(ierr);
1005   PetscFunctionReturn(0);
1006 }
1007 
1008