xref: /petsc/src/dm/impls/shell/dmshell.c (revision 36a9e3b9f6565ce1252c167e0dc4a4cf71b0f2ec)
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 - Returns the user-provided context associated to the 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) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
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:
516     If these functions are not provided but DMShellSetGlobalToLocalVecScatter() is called then
517    DMGlobalToLocalBeginDefaultShell()/DMGlobalToLocalEndDefaultShell() are used to to perform the transfers
518 
519    Level: advanced
520 
521 .seealso: DMShellSetLocalToGlobal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
522 @*/
523 PetscErrorCode DMShellSetGlobalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
524   PetscFunctionBegin;
525   dm->ops->globaltolocalbegin = begin;
526   dm->ops->globaltolocalend = end;
527   PetscFunctionReturn(0);
528 }
529 
530 /*@C
531    DMShellSetLocalToGlobal - Sets the routines used to perform a local to global scatter
532 
533    Logically Collective on DM
534 
535    Input Arguments
536 +  dm - the shell DM
537 .  begin - the routine that begins the local to global scatter
538 -  end - the routine that ends the local to global scatter
539 
540    Notes:
541     If these functions are not provided but DMShellSetLocalToGlobalVecScatter() is called then
542    DMLocalToGlobalBeginDefaultShell()/DMLocalToGlobalEndDefaultShell() are used to to perform the transfers
543 
544    Level: advanced
545 
546 .seealso: DMShellSetGlobalToLocal()
547 @*/
548 PetscErrorCode DMShellSetLocalToGlobal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
549   PetscFunctionBegin;
550   dm->ops->localtoglobalbegin = begin;
551   dm->ops->localtoglobalend = end;
552   PetscFunctionReturn(0);
553 }
554 
555 /*@C
556    DMShellSetLocalToLocal - Sets the routines used to perform a local to local scatter
557 
558    Logically Collective on DM
559 
560    Input Arguments
561 +  dm - the shell DM
562 .  begin - the routine that begins the local to local scatter
563 -  end - the routine that ends the local to local scatter
564 
565    Notes:
566     If these functions are not provided but DMShellSetLocalToLocalVecScatter() is called then
567    DMLocalToLocalBeginDefaultShell()/DMLocalToLocalEndDefaultShell() are used to to perform the transfers
568 
569    Level: advanced
570 
571 .seealso: DMShellSetGlobalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
572 @*/
573 PetscErrorCode DMShellSetLocalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec)) {
574   PetscFunctionBegin;
575   dm->ops->localtolocalbegin = begin;
576   dm->ops->localtolocalend = end;
577   PetscFunctionReturn(0);
578 }
579 
580 /*@
581    DMShellSetGlobalToLocalVecScatter - Sets a VecScatter context for global to local communication
582 
583    Logically Collective on DM
584 
585    Input Arguments
586 +  dm - the shell DM
587 -  gtol - the global to local VecScatter context
588 
589    Level: advanced
590 
591 .seealso: DMShellSetGlobalToLocal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
592 @*/
593 PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter gtol)
594 {
595   DM_Shell       *shell = (DM_Shell*)dm->data;
596   PetscErrorCode ierr;
597 
598   PetscFunctionBegin;
599   ierr = PetscObjectReference((PetscObject)gtol);CHKERRQ(ierr);
600   /* Call VecScatterDestroy() to avoid a memory leak in case of re-setting. */
601   ierr = VecScatterDestroy(&shell->gtol);CHKERRQ(ierr);
602   shell->gtol = gtol;
603   PetscFunctionReturn(0);
604 }
605 
606 /*@
607    DMShellSetLocalToGlobalVecScatter - Sets a VecScatter context for local to global communication
608 
609    Logically Collective on DM
610 
611    Input Arguments
612 +  dm - the shell DM
613 -  ltog - the local to global VecScatter context
614 
615    Level: advanced
616 
617 .seealso: DMShellSetLocalToGlobal(), DMLocalToGlobalBeginDefaultShell(), DMLocalToGlobalEndDefaultShell()
618 @*/
619 PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter ltog)
620 {
621   DM_Shell       *shell = (DM_Shell*)dm->data;
622   PetscErrorCode ierr;
623 
624   PetscFunctionBegin;
625   ierr = PetscObjectReference((PetscObject)ltog);CHKERRQ(ierr);
626   /* Call VecScatterDestroy() to avoid a memory leak in case of re-setting. */
627   ierr = VecScatterDestroy(&shell->ltog);CHKERRQ(ierr);
628   shell->ltog = ltog;
629   PetscFunctionReturn(0);
630 }
631 
632 /*@
633    DMShellSetLocalToLocalVecScatter - Sets a VecScatter context for local to local communication
634 
635    Logically Collective on DM
636 
637    Input Arguments
638 +  dm - the shell DM
639 -  ltol - the local to local VecScatter context
640 
641    Level: advanced
642 
643 .seealso: DMShellSetLocalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
644 @*/
645 PetscErrorCode DMShellSetLocalToLocalVecScatter(DM dm, VecScatter ltol)
646 {
647   DM_Shell       *shell = (DM_Shell*)dm->data;
648   PetscErrorCode ierr;
649 
650   PetscFunctionBegin;
651   ierr = PetscObjectReference((PetscObject)ltol);CHKERRQ(ierr);
652   /* Call VecScatterDestroy() to avoid a memory leak in case of re-setting. */
653   ierr = VecScatterDestroy(&shell->ltol);CHKERRQ(ierr);
654   shell->ltol = ltol;
655   PetscFunctionReturn(0);
656 }
657 
658 /*@C
659    DMShellSetCoarsen - Set the routine used to coarsen the shell DM
660 
661    Logically Collective on DM
662 
663    Input Arguments
664 +  dm - the shell DM
665 -  coarsen - the routine that coarsens the DM
666 
667    Level: advanced
668 
669 .seealso: DMShellSetRefine(), DMCoarsen(), DMShellGetCoarsen(), DMShellSetContext(), DMShellGetContext()
670 @*/
671 PetscErrorCode DMShellSetCoarsen(DM dm, PetscErrorCode (*coarsen)(DM,MPI_Comm,DM*))
672 {
673   PetscErrorCode ierr;
674   PetscBool      isshell;
675 
676   PetscFunctionBegin;
677   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
678   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
679   if (!isshell) PetscFunctionReturn(0);
680   dm->ops->coarsen = coarsen;
681   PetscFunctionReturn(0);
682 }
683 
684 /*@C
685    DMShellGetCoarsen - Get the routine used to coarsen the shell DM
686 
687    Logically Collective on DM
688 
689    Input Argument:
690 .  dm - the shell DM
691 
692    Output Argument:
693 .  coarsen - the routine that coarsens the DM
694 
695    Level: advanced
696 
697 .seealso: DMShellSetCoarsen(), DMCoarsen(), DMShellSetRefine(), DMRefine()
698 @*/
699 PetscErrorCode DMShellGetCoarsen(DM dm, PetscErrorCode (**coarsen)(DM,MPI_Comm,DM*))
700 {
701   PetscErrorCode ierr;
702   PetscBool      isshell;
703 
704   PetscFunctionBegin;
705   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
706   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
707   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
708   *coarsen = dm->ops->coarsen;
709   PetscFunctionReturn(0);
710 }
711 
712 /*@C
713    DMShellSetRefine - Set the routine used to refine the shell DM
714 
715    Logically Collective on DM
716 
717    Input Arguments
718 +  dm - the shell DM
719 -  refine - the routine that refines the DM
720 
721    Level: advanced
722 
723 .seealso: DMShellSetCoarsen(), DMRefine(), DMShellGetRefine(), DMShellSetContext(), DMShellGetContext()
724 @*/
725 PetscErrorCode DMShellSetRefine(DM dm, PetscErrorCode (*refine)(DM,MPI_Comm,DM*))
726 {
727   PetscErrorCode ierr;
728   PetscBool      isshell;
729 
730   PetscFunctionBegin;
731   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
732   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
733   if (!isshell) PetscFunctionReturn(0);
734   dm->ops->refine = refine;
735   PetscFunctionReturn(0);
736 }
737 
738 /*@C
739    DMShellGetRefine - Get the routine used to refine the shell DM
740 
741    Logically Collective on DM
742 
743    Input Argument:
744 .  dm - the shell DM
745 
746    Output Argument:
747 .  refine - the routine that refines the DM
748 
749    Level: advanced
750 
751 .seealso: DMShellSetCoarsen(), DMCoarsen(), DMShellSetRefine(), DMRefine()
752 @*/
753 PetscErrorCode DMShellGetRefine(DM dm, PetscErrorCode (**refine)(DM,MPI_Comm,DM*))
754 {
755   PetscErrorCode ierr;
756   PetscBool      isshell;
757 
758   PetscFunctionBegin;
759   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
760   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
761   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
762   *refine = dm->ops->refine;
763   PetscFunctionReturn(0);
764 }
765 
766 /*@C
767    DMShellSetCreateInterpolation - Set the routine used to create the interpolation operator
768 
769    Logically Collective on DM
770 
771    Input Arguments
772 +  dm - the shell DM
773 -  interp - the routine to create the interpolation
774 
775    Level: advanced
776 
777 .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateInterpolation(), DMShellSetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
778 @*/
779 PetscErrorCode DMShellSetCreateInterpolation(DM dm, PetscErrorCode (*interp)(DM,DM,Mat*,Vec*))
780 {
781   PetscErrorCode ierr;
782   PetscBool      isshell;
783 
784   PetscFunctionBegin;
785   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
786   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
787   if (!isshell) PetscFunctionReturn(0);
788   dm->ops->createinterpolation = interp;
789   PetscFunctionReturn(0);
790 }
791 
792 /*@C
793    DMShellGetCreateInterpolation - Get the routine used to create the interpolation operator
794 
795    Logically Collective on DM
796 
797    Input Argument:
798 +  dm - the shell DM
799 
800    Output Argument:
801 -  interp - the routine to create the interpolation
802 
803    Level: advanced
804 
805 .seealso: DMShellGetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
806 @*/
807 PetscErrorCode DMShellGetCreateInterpolation(DM dm, PetscErrorCode (**interp)(DM,DM,Mat*,Vec*))
808 {
809   PetscErrorCode ierr;
810   PetscBool      isshell;
811 
812   PetscFunctionBegin;
813   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
814   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
815   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
816   *interp = dm->ops->createinterpolation;
817   PetscFunctionReturn(0);
818 }
819 
820 /*@C
821    DMShellSetCreateRestriction - Set the routine used to create the restriction operator
822 
823    Logically Collective on DM
824 
825    Input Arguments
826 +  dm - the shell DM
827 -  striction- the routine to create the restriction
828 
829    Level: advanced
830 
831 .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
832 @*/
833 PetscErrorCode DMShellSetCreateRestriction(DM dm, PetscErrorCode (*restriction)(DM,DM,Mat*))
834 {
835   PetscErrorCode ierr;
836   PetscBool      isshell;
837 
838   PetscFunctionBegin;
839   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
840   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
841   if (!isshell) PetscFunctionReturn(0);
842   dm->ops->createrestriction = restriction;
843   PetscFunctionReturn(0);
844 }
845 
846 /*@C
847    DMShellGetCreateRestriction - Get the routine used to create the restriction operator
848 
849    Logically Collective on DM
850 
851    Input Argument:
852 +  dm - the shell DM
853 
854    Output Argument:
855 -  restriction - the routine to create the restriction
856 
857    Level: advanced
858 
859 .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellSetContext(), DMShellGetContext()
860 @*/
861 PetscErrorCode DMShellGetCreateRestriction(DM dm, PetscErrorCode (**restriction)(DM,DM,Mat*))
862 {
863   PetscErrorCode ierr;
864   PetscBool      isshell;
865 
866   PetscFunctionBegin;
867   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
868   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
869   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
870   *restriction = dm->ops->createrestriction;
871   PetscFunctionReturn(0);
872 }
873 
874 /*@C
875    DMShellSetCreateInjection - Set the routine used to create the injection operator
876 
877    Logically Collective on DM
878 
879    Input Arguments
880 +  dm - the shell DM
881 -  inject - the routine to create the injection
882 
883    Level: advanced
884 
885 .seealso: DMShellSetCreateInterpolation(), DMCreateInjection(), DMShellGetCreateInjection(), DMShellSetContext(), DMShellGetContext()
886 @*/
887 PetscErrorCode DMShellSetCreateInjection(DM dm, PetscErrorCode (*inject)(DM,DM,Mat*))
888 {
889   PetscErrorCode ierr;
890   PetscBool      isshell;
891 
892   PetscFunctionBegin;
893   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
894   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
895   if (!isshell) PetscFunctionReturn(0);
896   dm->ops->getinjection = inject;
897   PetscFunctionReturn(0);
898 }
899 
900 /*@C
901    DMShellGetCreateInjection - Get the routine used to create the injection operator
902 
903    Logically Collective on DM
904 
905    Input Argument:
906 +  dm - the shell DM
907 
908    Output Argument:
909 -  inject - the routine to create the injection
910 
911    Level: advanced
912 
913 .seealso: DMShellGetCreateInterpolation(), DMCreateInjection(), DMShellSetContext(), DMShellGetContext()
914 @*/
915 PetscErrorCode DMShellGetCreateInjection(DM dm, PetscErrorCode (**inject)(DM,DM,Mat*))
916 {
917   PetscErrorCode ierr;
918   PetscBool      isshell;
919 
920   PetscFunctionBegin;
921   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
922   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
923   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
924   *inject = dm->ops->getinjection;
925   PetscFunctionReturn(0);
926 }
927 
928 static PetscErrorCode DMHasCreateInjection_Shell(DM dm, PetscBool *flg)
929 {
930   PetscErrorCode ierr;
931   PetscBool      isshell;
932 
933   PetscFunctionBegin;
934   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
935   PetscValidPointer(flg,2);
936   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
937   if (!isshell) {
938     *flg = PETSC_FALSE;
939   } else {
940     *flg = dm->ops->getinjection ? PETSC_TRUE : PETSC_FALSE;
941   }
942   PetscFunctionReturn(0);
943 }
944 /*@C
945    DMShellSetCreateFieldDecomposition - Set the routine used to create a decomposition of fields for the shell DM
946 
947    Logically Collective on DM
948 
949    Input Arguments
950 +  dm - the shell DM
951 -  decomp - the routine to create the decomposition
952 
953    Level: advanced
954 
955 .seealso: DMCreateFieldDecomposition(), DMShellSetContext(), DMShellGetContext()
956 @*/
957 PetscErrorCode DMShellSetCreateFieldDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,DM**))
958 {
959   PetscErrorCode ierr;
960   PetscBool      isshell;
961 
962   PetscFunctionBegin;
963   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
964   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
965   if (!isshell) PetscFunctionReturn(0);
966   dm->ops->createfielddecomposition = decomp;
967   PetscFunctionReturn(0);
968 }
969 
970 /*@C
971    DMShellSetCreateDomainDecomposition - Set the routine used to create a domain decomposition for the shell DM
972 
973    Logically Collective on DM
974 
975    Input Arguments
976 +  dm - the shell DM
977 -  decomp - the routine to create the decomposition
978 
979    Level: advanced
980 
981 .seealso: DMCreateDomainDecomposition(), DMShellSetContext(), DMShellGetContext()
982 @*/
983 PetscErrorCode DMShellSetCreateDomainDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,IS**,DM**))
984 {
985   PetscErrorCode ierr;
986   PetscBool      isshell;
987 
988   PetscFunctionBegin;
989   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
990   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
991   if (!isshell) PetscFunctionReturn(0);
992   dm->ops->createdomaindecomposition = decomp;
993   PetscFunctionReturn(0);
994 }
995 
996 /*@C
997    DMShellSetCreateDomainDecompositionScatters - Set the routine used to create the scatter contexts for domain decomposition with a shell DM
998 
999    Logically Collective on DM
1000 
1001    Input Arguments
1002 +  dm - the shell DM
1003 -  scatter - the routine to create the scatters
1004 
1005    Level: advanced
1006 
1007 .seealso: DMCreateDomainDecompositionScatters(), DMShellSetContext(), DMShellGetContext()
1008 @*/
1009 PetscErrorCode DMShellSetCreateDomainDecompositionScatters(DM dm, PetscErrorCode (*scatter)(DM,PetscInt,DM*,VecScatter**,VecScatter**,VecScatter**))
1010 {
1011   PetscErrorCode ierr;
1012   PetscBool      isshell;
1013 
1014   PetscFunctionBegin;
1015   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1016   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
1017   if (!isshell) PetscFunctionReturn(0);
1018   dm->ops->createddscatters = scatter;
1019   PetscFunctionReturn(0);
1020 }
1021 
1022 /*@C
1023    DMShellSetCreateSubDM - Set the routine used to create a sub DM from the shell DM
1024 
1025    Logically Collective on DM
1026 
1027    Input Arguments
1028 +  dm - the shell DM
1029 -  subdm - the routine to create the decomposition
1030 
1031    Level: advanced
1032 
1033 .seealso: DMCreateSubDM(), DMShellGetCreateSubDM(), DMShellSetContext(), DMShellGetContext()
1034 @*/
1035 PetscErrorCode DMShellSetCreateSubDM(DM dm, PetscErrorCode (*subdm)(DM,PetscInt,const PetscInt[],IS*,DM*))
1036 {
1037   PetscErrorCode ierr;
1038   PetscBool      isshell;
1039 
1040   PetscFunctionBegin;
1041   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1042   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
1043   if (!isshell) PetscFunctionReturn(0);
1044   dm->ops->createsubdm = subdm;
1045   PetscFunctionReturn(0);
1046 }
1047 
1048 /*@C
1049    DMShellGetCreateSubDM - Get the routine used to create a sub DM from the shell DM
1050 
1051    Logically Collective on DM
1052 
1053    Input Argument:
1054 +  dm - the shell DM
1055 
1056    Output Argument:
1057 -  subdm - the routine to create the decomposition
1058 
1059    Level: advanced
1060 
1061 .seealso: DMCreateSubDM(), DMShellSetCreateSubDM(), DMShellSetContext(), DMShellGetContext()
1062 @*/
1063 PetscErrorCode DMShellGetCreateSubDM(DM dm, PetscErrorCode (**subdm)(DM,PetscInt,const PetscInt[],IS*,DM*))
1064 {
1065   PetscErrorCode ierr;
1066   PetscBool      isshell;
1067 
1068   PetscFunctionBegin;
1069   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1070   ierr = PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);CHKERRQ(ierr);
1071   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
1072   *subdm = dm->ops->createsubdm;
1073   PetscFunctionReturn(0);
1074 }
1075 
1076 static PetscErrorCode DMDestroy_Shell(DM dm)
1077 {
1078   PetscErrorCode ierr;
1079   DM_Shell       *shell = (DM_Shell*)dm->data;
1080 
1081   PetscFunctionBegin;
1082   ierr = MatDestroy(&shell->A);CHKERRQ(ierr);
1083   ierr = VecDestroy(&shell->Xglobal);CHKERRQ(ierr);
1084   ierr = VecDestroy(&shell->Xlocal);CHKERRQ(ierr);
1085   ierr = VecScatterDestroy(&shell->gtol);CHKERRQ(ierr);
1086   ierr = VecScatterDestroy(&shell->ltog);CHKERRQ(ierr);
1087   ierr = VecScatterDestroy(&shell->ltol);CHKERRQ(ierr);
1088   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1089   ierr = PetscFree(shell);CHKERRQ(ierr);
1090   PetscFunctionReturn(0);
1091 }
1092 
1093 static PetscErrorCode DMView_Shell(DM dm,PetscViewer v)
1094 {
1095   PetscErrorCode ierr;
1096   DM_Shell       *shell = (DM_Shell*)dm->data;
1097 
1098   PetscFunctionBegin;
1099   ierr = VecView(shell->Xglobal,v);CHKERRQ(ierr);
1100   PetscFunctionReturn(0);
1101 }
1102 
1103 static PetscErrorCode DMLoad_Shell(DM dm,PetscViewer v)
1104 {
1105   PetscErrorCode ierr;
1106   DM_Shell       *shell = (DM_Shell*)dm->data;
1107 
1108   PetscFunctionBegin;
1109   ierr = VecCreate(PetscObjectComm((PetscObject)dm),&shell->Xglobal);CHKERRQ(ierr);
1110   ierr = VecLoad(shell->Xglobal,v);CHKERRQ(ierr);
1111   PetscFunctionReturn(0);
1112 }
1113 
1114 PetscErrorCode DMCreateSubDM_Shell(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1115 {
1116   PetscErrorCode ierr;
1117 
1118   PetscFunctionBegin;
1119   if (subdm) {ierr = DMShellCreate(PetscObjectComm((PetscObject) dm), subdm);CHKERRQ(ierr);}
1120   ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1121   PetscFunctionReturn(0);
1122 }
1123 
1124 PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
1125 {
1126   PetscErrorCode ierr;
1127   DM_Shell       *shell;
1128 
1129   PetscFunctionBegin;
1130   ierr     = PetscNewLog(dm,&shell);CHKERRQ(ierr);
1131   dm->data = shell;
1132 
1133   ierr = PetscObjectChangeTypeName((PetscObject)dm,DMSHELL);CHKERRQ(ierr);
1134 
1135   dm->ops->destroy            = DMDestroy_Shell;
1136   dm->ops->createglobalvector = DMCreateGlobalVector_Shell;
1137   dm->ops->createlocalvector  = DMCreateLocalVector_Shell;
1138   dm->ops->creatematrix       = DMCreateMatrix_Shell;
1139   dm->ops->view               = DMView_Shell;
1140   dm->ops->load               = DMLoad_Shell;
1141   dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell;
1142   dm->ops->globaltolocalend   = DMGlobalToLocalEndDefaultShell;
1143   dm->ops->localtoglobalbegin = DMLocalToGlobalBeginDefaultShell;
1144   dm->ops->localtoglobalend   = DMLocalToGlobalEndDefaultShell;
1145   dm->ops->localtolocalbegin  = DMLocalToLocalBeginDefaultShell;
1146   dm->ops->localtolocalend    = DMLocalToLocalEndDefaultShell;
1147   dm->ops->createsubdm        = DMCreateSubDM_Shell;
1148   dm->ops->hascreateinjection = DMHasCreateInjection_Shell;
1149   PetscFunctionReturn(0);
1150 }
1151 
1152 /*@
1153     DMShellCreate - Creates a shell DM object, used to manage user-defined problem data
1154 
1155     Collective on MPI_Comm
1156 
1157     Input Parameter:
1158 .   comm - the processors that will share the global vector
1159 
1160     Output Parameters:
1161 .   shell - the shell DM
1162 
1163     Level: advanced
1164 
1165 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateLocalVector(), DMShellSetContext(), DMShellGetContext()
1166 @*/
1167 PetscErrorCode  DMShellCreate(MPI_Comm comm,DM *dm)
1168 {
1169   PetscErrorCode ierr;
1170 
1171   PetscFunctionBegin;
1172   PetscValidPointer(dm,2);
1173   ierr = DMCreate(comm,dm);CHKERRQ(ierr);
1174   ierr = DMSetType(*dm,DMSHELL);CHKERRQ(ierr);
1175   ierr = DMSetUp(*dm);CHKERRQ(ierr);
1176   PetscFunctionReturn(0);
1177 }
1178