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