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