Actual source code: dmshell.c

  1: #include <petscdmshell.h>
  2: #include <petscmat.h>
  3: #include <petsc/private/dmimpl.h>

  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;

 16: /*@
 17:   DMGlobalToLocalBeginDefaultShell - Uses the GlobalToLocal `VecScatter` context set by the user to begin a global to local scatter

 19:   Collective

 21:   Input Parameters:
 22: + dm   - `DMSHELL`
 23: . g    - global vector
 24: . mode - `InsertMode`
 25: - l    - local vector

 27:   Level: advanced

 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.

 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;

 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: }

 44: /*@
 45:   DMGlobalToLocalEndDefaultShell - Uses the GlobalToLocal `VecScatter` context set by the user to end a global to local scatter
 46:   Collective

 48:   Input Parameters:
 49: + dm   - `DMSHELL`
 50: . g    - global vector
 51: . mode - `InsertMode`
 52: - l    - local vector

 54:   Level: advanced

 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;

 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: }

 68: /*@
 69:   DMLocalToGlobalBeginDefaultShell - Uses the LocalToGlobal `VecScatter` context set by the user to begin a local to global scatter
 70:   Collective

 72:   Input Parameters:
 73: + dm   - `DMSHELL`
 74: . l    - local vector
 75: . mode - `InsertMode`
 76: - g    - global vector

 78:   Level: advanced

 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.

 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;

 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: }

 95: /*@
 96:   DMLocalToGlobalEndDefaultShell - Uses the LocalToGlobal `VecScatter` context set by the user to end a local to global scatter
 97:   Collective

 99:   Input Parameters:
100: + dm   - `DMSHELL`
101: . l    - local vector
102: . mode - `InsertMode`
103: - g    - global vector

105:   Level: advanced

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;

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: }

119: /*@
120:   DMLocalToLocalBeginDefaultShell - Uses the LocalToLocal `VecScatter` context set by the user to begin a local to local scatter
121:   Collective

123:   Input Parameters:
124: + dm   - `DMSHELL`
125: . g    - the original local vector
126: - mode - `InsertMode`

128:   Output Parameter:
129: . l - the local vector with correct ghost values

131:   Level: advanced

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.

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;

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: }

148: /*@
149:   DMLocalToLocalEndDefaultShell - Uses the LocalToLocal `VecScatter` context set by the user to end a local to local scatter
150:   Collective

152:   Input Parameters:
153: + dm   - `DMSHELL`
154: . g    - the original local vector
155: - mode - `InsertMode`

157:   Output Parameter:
158: . l - the local vector with correct ghost values

160:   Level: advanced

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;

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: }

174: static PetscErrorCode DMCreateMatrix_Shell(DM dm, Mat *J)
175: {
176:   DM_Shell *shell = (DM_Shell *)dm->data;
177:   Mat       A;

179:   PetscFunctionBegin;
181:   PetscAssertPointer(J, 2);
182:   if (!shell->A) {
183:     if (shell->Xglobal) {
184:       PetscInt m, M;
185:       PetscCall(PetscInfo(dm, "Naively creating matrix using global vector distribution without preallocation\n"));
186:       PetscCall(VecGetSize(shell->Xglobal, &M));
187:       PetscCall(VecGetLocalSize(shell->Xglobal, &m));
188:       PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), &shell->A));
189:       PetscCall(MatSetSizes(shell->A, m, m, M, M));
190:       PetscCall(MatSetType(shell->A, dm->mattype));
191:       PetscCall(MatSetUp(shell->A));
192:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Must call DMShellSetMatrix(), DMShellSetCreateMatrix(), or provide a vector");
193:   }
194:   A = shell->A;
195:   PetscCall(MatDuplicate(A, MAT_SHARE_NONZERO_PATTERN, J));
196:   PetscCall(MatSetDM(*J, dm));
197:   PetscFunctionReturn(PETSC_SUCCESS);
198: }

200: static PetscErrorCode DMCreateGlobalVector_Shell(DM dm, Vec *gvec)
201: {
202:   DM_Shell *shell = (DM_Shell *)dm->data;
203:   Vec       X;

205:   PetscFunctionBegin;
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: }

218: static PetscErrorCode DMCreateLocalVector_Shell(DM dm, Vec *gvec)
219: {
220:   DM_Shell *shell = (DM_Shell *)dm->data;
221:   Vec       X;

223:   PetscFunctionBegin;
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: }

236: /*@C
237:   DMShellSetDestroyContext - set a function that destroys the context provided with `DMShellSetContext()`

239:   Collective

241:   Input Parameters:
242: + dm         - the `DM` to attach the `destroyctx()` function to
243: - destroyctx - the function that destroys the context

245:   Level: advanced

247: .seealso: `DM`, `DMSHELL`, `DMShellSetContext()`, `DMShellGetContext()`
248: @*/
249: PetscErrorCode DMShellSetDestroyContext(DM dm, PetscErrorCode (*destroyctx)(void *))
250: {
251:   DM_Shell *shell = (DM_Shell *)dm->data;
252:   PetscBool isshell;

254:   PetscFunctionBegin;
256:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
257:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
258:   shell->destroyctx = destroyctx;
259:   PetscFunctionReturn(PETSC_SUCCESS);
260: }

262: /*@
263:   DMShellSetContext - set some data to be usable by this `DMSHELL`

265:   Collective

267:   Input Parameters:
268: + dm  - `DMSHELL`
269: - ctx - the context

271:   Level: advanced

273: .seealso: `DM`, `DMSHELL`, `DMCreateMatrix()`, `DMShellGetContext()`
274: @*/
275: PetscErrorCode DMShellSetContext(DM dm, void *ctx)
276: {
277:   DM_Shell *shell = (DM_Shell *)dm->data;
278:   PetscBool isshell;

280:   PetscFunctionBegin;
282:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
283:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
284:   shell->ctx = ctx;
285:   PetscFunctionReturn(PETSC_SUCCESS);
286: }

288: /*@
289:   DMShellGetContext - Returns the user-provided context associated to the `DMSHELL`

291:   Collective

293:   Input Parameter:
294: . dm - `DMSHELL`

296:   Output Parameter:
297: . ctx - the context

299:   Level: advanced

301: .seealso: `DM`, `DMSHELL`, `DMCreateMatrix()`, `DMShellSetContext()`
302: @*/
303: PetscErrorCode DMShellGetContext(DM dm, void *ctx)
304: {
305:   DM_Shell *shell = (DM_Shell *)dm->data;
306:   PetscBool isshell;

308:   PetscFunctionBegin;
310:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
311:   PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs");
312:   *(void **)ctx = shell->ctx;
313:   PetscFunctionReturn(PETSC_SUCCESS);
314: }

316: /*@
317:   DMShellSetMatrix - sets a template matrix associated with the `DMSHELL`

319:   Collective

321:   Input Parameters:
322: + dm - `DMSHELL`
323: - J  - template matrix

325:   Level: advanced

327:   Developer Notes:
328:   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.

330: .seealso: `DM`, `DMSHELL`, `DMCreateMatrix()`, `DMShellSetCreateMatrix()`, `DMShellSetContext()`, `DMShellGetContext()`
331: @*/
332: PetscErrorCode DMShellSetMatrix(DM dm, Mat J)
333: {
334:   DM_Shell *shell = (DM_Shell *)dm->data;
335:   PetscBool isshell;
336:   DM        mdm;

338:   PetscFunctionBegin;
341:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
342:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
343:   if (J == shell->A) PetscFunctionReturn(PETSC_SUCCESS);
344:   PetscCall(MatGetDM(J, &mdm));
345:   PetscCall(PetscObjectReference((PetscObject)J));
346:   PetscCall(MatDestroy(&shell->A));
347:   if (mdm == dm) {
348:     PetscCall(MatDuplicate(J, MAT_SHARE_NONZERO_PATTERN, &shell->A));
349:     PetscCall(MatSetDM(shell->A, NULL));
350:   } else shell->A = J;
351:   PetscFunctionReturn(PETSC_SUCCESS);
352: }

354: /*@C
355:   DMShellSetCreateMatrix - sets the routine to create a matrix associated with the `DMSHELL`

357:   Logically Collective

359:   Input Parameters:
360: + dm   - the `DMSHELL`
361: - func - the function to create a matrix

363:   Level: advanced

365: .seealso: `DM`, `DMSHELL`, `DMCreateMatrix()`, `DMShellSetMatrix()`, `DMShellSetContext()`, `DMShellGetContext()`
366: @*/
367: PetscErrorCode DMShellSetCreateMatrix(DM dm, PetscErrorCode (*func)(DM, Mat *))
368: {
369:   PetscFunctionBegin;
371:   dm->ops->creatematrix = func;
372:   PetscFunctionReturn(PETSC_SUCCESS);
373: }

375: /*@
376:   DMShellSetGlobalVector - sets a template global vector associated with the `DMSHELL`

378:   Logically Collective

380:   Input Parameters:
381: + dm - `DMSHELL`
382: - X  - template vector

384:   Level: advanced

386: .seealso: `DM`, `DMSHELL`, `DMCreateGlobalVector()`, `DMShellSetMatrix()`, `DMShellSetCreateGlobalVector()`
387: @*/
388: PetscErrorCode DMShellSetGlobalVector(DM dm, Vec X)
389: {
390:   DM_Shell *shell = (DM_Shell *)dm->data;
391:   PetscBool isshell;
392:   DM        vdm;

394:   PetscFunctionBegin;
397:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
398:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
399:   PetscCall(VecGetDM(X, &vdm));
400:   /*
401:       if the vector proposed as the new base global vector for the DM is a DM vector associated
402:       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
403:       we get a circular dependency that prevents the DM from being destroy when it should be.
404:       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
405:       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
406:       to set its input vector (which is associated with the DM) as the base global vector.
407:       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
408:       for pointing out the problem.
409:    */
410:   if (vdm == dm) PetscFunctionReturn(PETSC_SUCCESS);
411:   PetscCall(PetscObjectReference((PetscObject)X));
412:   PetscCall(VecDestroy(&shell->Xglobal));
413:   shell->Xglobal = X;
414:   PetscCall(DMClearGlobalVectors(dm));
415:   PetscCall(DMClearNamedGlobalVectors(dm));
416:   PetscFunctionReturn(PETSC_SUCCESS);
417: }

419: /*@
420:   DMShellGetGlobalVector - Returns the template global vector associated with the `DMSHELL`, or `NULL` if it was not set

422:   Not Collective

424:   Input Parameters:
425: + dm - `DMSHELL`
426: - X  - template vector

428:   Level: advanced

430: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalVector()`, `DMShellSetCreateGlobalVector()`, `DMCreateGlobalVector()`
431: @*/
432: PetscErrorCode DMShellGetGlobalVector(DM dm, Vec *X)
433: {
434:   DM_Shell *shell = (DM_Shell *)dm->data;
435:   PetscBool isshell;

437:   PetscFunctionBegin;
439:   PetscAssertPointer(X, 2);
440:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
441:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
442:   *X = shell->Xglobal;
443:   PetscFunctionReturn(PETSC_SUCCESS);
444: }

446: /*@C
447:   DMShellSetCreateGlobalVector - sets the routine to create a global vector associated with the `DMSHELL`

449:   Logically Collective

451:   Input Parameters:
452: + dm   - the `DMSHELL`
453: - func - the creation routine

455:   Level: advanced

457: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalVector()`, `DMShellSetCreateMatrix()`, `DMShellSetContext()`, `DMShellGetContext()`
458: @*/
459: PetscErrorCode DMShellSetCreateGlobalVector(DM dm, PetscErrorCode (*func)(DM, Vec *))
460: {
461:   PetscFunctionBegin;
463:   dm->ops->createglobalvector = func;
464:   PetscFunctionReturn(PETSC_SUCCESS);
465: }

467: /*@
468:   DMShellSetLocalVector - sets a template local vector associated with the `DMSHELL`

470:   Logically Collective

472:   Input Parameters:
473: + dm - `DMSHELL`
474: - X  - template vector

476:   Level: advanced

478: .seealso: `DM`, `DMSHELL`, `DMCreateLocalVector()`, `DMShellSetMatrix()`, `DMShellSetCreateLocalVector()`
479: @*/
480: PetscErrorCode DMShellSetLocalVector(DM dm, Vec X)
481: {
482:   DM_Shell *shell = (DM_Shell *)dm->data;
483:   PetscBool isshell;
484:   DM        vdm;

486:   PetscFunctionBegin;
489:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
490:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
491:   PetscCall(VecGetDM(X, &vdm));
492:   /*
493:       if the vector proposed as the new base global vector for the DM is a DM vector associated
494:       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
495:       we get a circular dependency that prevents the DM from being destroy when it should be.
496:       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
497:       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
498:       to set its input vector (which is associated with the DM) as the base global vector.
499:       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
500:       for pointing out the problem.
501:    */
502:   if (vdm == dm) PetscFunctionReturn(PETSC_SUCCESS);
503:   PetscCall(PetscObjectReference((PetscObject)X));
504:   PetscCall(VecDestroy(&shell->Xlocal));
505:   shell->Xlocal = X;
506:   PetscCall(DMClearLocalVectors(dm));
507:   PetscCall(DMClearNamedLocalVectors(dm));
508:   PetscFunctionReturn(PETSC_SUCCESS);
509: }

511: /*@C
512:   DMShellSetCreateLocalVector - sets the routine to create a local vector associated with the `DMSHELL`

514:   Logically Collective

516:   Input Parameters:
517: + dm   - the `DMSHELL`
518: - func - the creation routine

520:   Level: advanced

522: .seealso: `DM`, `DMSHELL`, `DMShellSetLocalVector()`, `DMShellSetCreateMatrix()`, `DMShellSetContext()`, `DMShellGetContext()`
523: @*/
524: PetscErrorCode DMShellSetCreateLocalVector(DM dm, PetscErrorCode (*func)(DM, Vec *))
525: {
526:   PetscFunctionBegin;
528:   dm->ops->createlocalvector = func;
529:   PetscFunctionReturn(PETSC_SUCCESS);
530: }

532: /*@C
533:   DMShellSetGlobalToLocal - Sets the routines used to perform a global to local scatter

535:   Logically Collective

537:   Input Parameters:
538: + dm    - the `DMSHELL`
539: . begin - the routine that begins the global to local scatter
540: - end   - the routine that ends the global to local scatter

542:   Level: advanced

544:   Note:
545:   If these functions are not provided but `DMShellSetGlobalToLocalVecScatter()` is called then
546:   `DMGlobalToLocalBeginDefaultShell()`/`DMGlobalToLocalEndDefaultShell()` are used to perform the transfers

548: .seealso: `DM`, `DMSHELL`, `DMShellSetLocalToGlobal()`, `DMGlobalToLocalBeginDefaultShell()`, `DMGlobalToLocalEndDefaultShell()`
549: @*/
550: PetscErrorCode DMShellSetGlobalToLocal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec))
551: {
552:   PetscFunctionBegin;
554:   dm->ops->globaltolocalbegin = begin;
555:   dm->ops->globaltolocalend   = end;
556:   PetscFunctionReturn(PETSC_SUCCESS);
557: }

559: /*@C
560:   DMShellSetLocalToGlobal - Sets the routines used to perform a local to global scatter

562:   Logically Collective

564:   Input Parameters:
565: + dm    - the `DMSHELL`
566: . begin - the routine that begins the local to global scatter
567: - end   - the routine that ends the local to global scatter

569:   Level: advanced

571:   Note:
572:   If these functions are not provided but `DMShellSetLocalToGlobalVecScatter()` is called then
573:   `DMLocalToGlobalBeginDefaultShell()`/`DMLocalToGlobalEndDefaultShell()` are used to perform the transfers

575: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalToLocal()`
576: @*/
577: PetscErrorCode DMShellSetLocalToGlobal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec))
578: {
579:   PetscFunctionBegin;
581:   dm->ops->localtoglobalbegin = begin;
582:   dm->ops->localtoglobalend   = end;
583:   PetscFunctionReturn(PETSC_SUCCESS);
584: }

586: /*@C
587:   DMShellSetLocalToLocal - Sets the routines used to perform a local to local scatter

589:   Logically Collective

591:   Input Parameters:
592: + dm    - the `DMSHELL`
593: . begin - the routine that begins the local to local scatter
594: - end   - the routine that ends the local to local scatter

596:   Level: advanced

598:   Note:
599:   If these functions are not provided but `DMShellSetLocalToLocalVecScatter()` is called then
600:   `DMLocalToLocalBeginDefaultShell()`/`DMLocalToLocalEndDefaultShell()` are used to perform the transfers

602: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalToLocal()`, `DMLocalToLocalBeginDefaultShell()`, `DMLocalToLocalEndDefaultShell()`
603: @*/
604: PetscErrorCode DMShellSetLocalToLocal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec))
605: {
606:   PetscFunctionBegin;
608:   dm->ops->localtolocalbegin = begin;
609:   dm->ops->localtolocalend   = end;
610:   PetscFunctionReturn(PETSC_SUCCESS);
611: }

613: /*@
614:   DMShellSetGlobalToLocalVecScatter - Sets a `VecScatter` context for global to local communication

616:   Logically Collective

618:   Input Parameters:
619: + dm   - the `DMSHELL`
620: - gtol - the global to local `VecScatter` context

622:   Level: advanced

624: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalToLocal()`, `DMGlobalToLocalBeginDefaultShell()`, `DMGlobalToLocalEndDefaultShell()`
625: @*/
626: PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter gtol)
627: {
628:   DM_Shell *shell = (DM_Shell *)dm->data;

630:   PetscFunctionBegin;
633:   PetscCall(PetscObjectReference((PetscObject)gtol));
634:   PetscCall(VecScatterDestroy(&shell->gtol));
635:   shell->gtol = gtol;
636:   PetscFunctionReturn(PETSC_SUCCESS);
637: }

639: /*@
640:   DMShellSetLocalToGlobalVecScatter - Sets a` VecScatter` context for local to global communication

642:   Logically Collective

644:   Input Parameters:
645: + dm   - the `DMSHELL`
646: - ltog - the local to global `VecScatter` context

648:   Level: advanced

650: .seealso: `DM`, `DMSHELL`, `DMShellSetLocalToGlobal()`, `DMLocalToGlobalBeginDefaultShell()`, `DMLocalToGlobalEndDefaultShell()`
651: @*/
652: PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter ltog)
653: {
654:   DM_Shell *shell = (DM_Shell *)dm->data;

656:   PetscFunctionBegin;
659:   PetscCall(PetscObjectReference((PetscObject)ltog));
660:   PetscCall(VecScatterDestroy(&shell->ltog));
661:   shell->ltog = ltog;
662:   PetscFunctionReturn(PETSC_SUCCESS);
663: }

665: /*@
666:   DMShellSetLocalToLocalVecScatter - Sets a `VecScatter` context for local to local communication

668:   Logically Collective

670:   Input Parameters:
671: + dm   - the `DMSHELL`
672: - ltol - the local to local `VecScatter` context

674:   Level: advanced

676: .seealso: `DM`, `DMSHELL`, `DMShellSetLocalToLocal()`, `DMLocalToLocalBeginDefaultShell()`, `DMLocalToLocalEndDefaultShell()`
677: @*/
678: PetscErrorCode DMShellSetLocalToLocalVecScatter(DM dm, VecScatter ltol)
679: {
680:   DM_Shell *shell = (DM_Shell *)dm->data;

682:   PetscFunctionBegin;
685:   PetscCall(PetscObjectReference((PetscObject)ltol));
686:   PetscCall(VecScatterDestroy(&shell->ltol));
687:   shell->ltol = ltol;
688:   PetscFunctionReturn(PETSC_SUCCESS);
689: }

691: /*@C
692:   DMShellSetCoarsen - Set the routine used to coarsen the `DMSHELL`

694:   Logically Collective

696:   Input Parameters:
697: + dm      - the `DMSHELL`
698: - coarsen - the routine that coarsens the `DM`

700:   Level: advanced

702: .seealso: `DM`, `DMSHELL`, `DMShellSetRefine()`, `DMCoarsen()`, `DMShellGetCoarsen()`, `DMShellSetContext()`, `DMShellGetContext()`
703: @*/
704: PetscErrorCode DMShellSetCoarsen(DM dm, PetscErrorCode (*coarsen)(DM, MPI_Comm, DM *))
705: {
706:   PetscBool isshell;

708:   PetscFunctionBegin;
710:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
711:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
712:   dm->ops->coarsen = coarsen;
713:   PetscFunctionReturn(PETSC_SUCCESS);
714: }

716: /*@C
717:   DMShellGetCoarsen - Get the routine used to coarsen the `DMSHELL`

719:   Logically Collective

721:   Input Parameter:
722: . dm - the `DMSHELL`

724:   Output Parameter:
725: . coarsen - the routine that coarsens the `DM`

727:   Level: advanced

729: .seealso: `DM`, `DMSHELL`, `DMShellSetCoarsen()`, `DMCoarsen()`, `DMShellSetRefine()`, `DMRefine()`
730: @*/
731: PetscErrorCode DMShellGetCoarsen(DM dm, PetscErrorCode (**coarsen)(DM, MPI_Comm, DM *))
732: {
733:   PetscBool isshell;

735:   PetscFunctionBegin;
737:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
738:   PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs");
739:   *coarsen = dm->ops->coarsen;
740:   PetscFunctionReturn(PETSC_SUCCESS);
741: }

743: /*@C
744:   DMShellSetRefine - Set the routine used to refine the `DMSHELL`

746:   Logically Collective

748:   Input Parameters:
749: + dm     - the `DMSHELL`
750: - refine - the routine that refines the `DM`

752:   Level: advanced

754: .seealso: `DM`, `DMSHELL`, `DMShellSetCoarsen()`, `DMRefine()`, `DMShellGetRefine()`, `DMShellSetContext()`, `DMShellGetContext()`
755: @*/
756: PetscErrorCode DMShellSetRefine(DM dm, PetscErrorCode (*refine)(DM, MPI_Comm, DM *))
757: {
758:   PetscBool isshell;

760:   PetscFunctionBegin;
762:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
763:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
764:   dm->ops->refine = refine;
765:   PetscFunctionReturn(PETSC_SUCCESS);
766: }

768: /*@C
769:   DMShellGetRefine - Get the routine used to refine the `DMSHELL`

771:   Logically Collective

773:   Input Parameter:
774: . dm - the `DMSHELL`

776:   Output Parameter:
777: . refine - the routine that refines the `DM`

779:   Level: advanced

781: .seealso: `DM`, `DMSHELL`, `DMShellSetCoarsen()`, `DMCoarsen()`, `DMShellSetRefine()`, `DMRefine()`
782: @*/
783: PetscErrorCode DMShellGetRefine(DM dm, PetscErrorCode (**refine)(DM, MPI_Comm, DM *))
784: {
785:   PetscBool isshell;

787:   PetscFunctionBegin;
789:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
790:   PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs");
791:   *refine = dm->ops->refine;
792:   PetscFunctionReturn(PETSC_SUCCESS);
793: }

795: /*@C
796:   DMShellSetCreateInterpolation - Set the routine used to create the interpolation operator

798:   Logically Collective

800:   Input Parameters:
801: + dm     - the `DMSHELL`
802: - interp - the routine to create the interpolation

804:   Level: advanced

806: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateInterpolation()`, `DMShellSetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()`
807: @*/
808: PetscErrorCode DMShellSetCreateInterpolation(DM dm, PetscErrorCode (*interp)(DM, DM, Mat *, Vec *))
809: {
810:   PetscBool isshell;

812:   PetscFunctionBegin;
814:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
815:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
816:   dm->ops->createinterpolation = interp;
817:   PetscFunctionReturn(PETSC_SUCCESS);
818: }

820: /*@C
821:   DMShellGetCreateInterpolation - Get the routine used to create the interpolation operator

823:   Logically Collective

825:   Input Parameter:
826: . dm - the `DMSHELL`

828:   Output Parameter:
829: . interp - the routine to create the interpolation

831:   Level: advanced

833: .seealso: `DM`, `DMSHELL`, `DMShellGetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()`
834: @*/
835: PetscErrorCode DMShellGetCreateInterpolation(DM dm, PetscErrorCode (**interp)(DM, DM, Mat *, Vec *))
836: {
837:   PetscBool isshell;

839:   PetscFunctionBegin;
841:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
842:   PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs");
843:   *interp = dm->ops->createinterpolation;
844:   PetscFunctionReturn(PETSC_SUCCESS);
845: }

847: /*@C
848:   DMShellSetCreateRestriction - Set the routine used to create the restriction operator

850:   Logically Collective

852:   Input Parameters:
853: + dm          - the `DMSHELL`
854: - restriction - the routine to create the restriction

856:   Level: advanced

858: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()`
859: @*/
860: PetscErrorCode DMShellSetCreateRestriction(DM dm, PetscErrorCode (*restriction)(DM, DM, Mat *))
861: {
862:   PetscBool isshell;

864:   PetscFunctionBegin;
866:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
867:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
868:   dm->ops->createrestriction = restriction;
869:   PetscFunctionReturn(PETSC_SUCCESS);
870: }

872: /*@C
873:   DMShellGetCreateRestriction - Get the routine used to create the restriction operator

875:   Logically Collective

877:   Input Parameter:
878: . dm - the `DMSHELL`

880:   Output Parameter:
881: . restriction - the routine to create the restriction

883:   Level: advanced

885: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellSetContext()`, `DMShellGetContext()`
886: @*/
887: PetscErrorCode DMShellGetCreateRestriction(DM dm, PetscErrorCode (**restriction)(DM, DM, Mat *))
888: {
889:   PetscBool isshell;

891:   PetscFunctionBegin;
893:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
894:   PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs");
895:   *restriction = dm->ops->createrestriction;
896:   PetscFunctionReturn(PETSC_SUCCESS);
897: }

899: /*@C
900:   DMShellSetCreateInjection - Set the routine used to create the injection operator

902:   Logically Collective

904:   Input Parameters:
905: + dm     - the `DMSHELL`
906: - inject - the routine to create the injection

908:   Level: advanced

910: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInterpolation()`, `DMCreateInjection()`, `DMShellGetCreateInjection()`, `DMShellSetContext()`, `DMShellGetContext()`
911: @*/
912: PetscErrorCode DMShellSetCreateInjection(DM dm, PetscErrorCode (*inject)(DM, DM, Mat *))
913: {
914:   PetscBool isshell;

916:   PetscFunctionBegin;
918:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
919:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
920:   dm->ops->createinjection = inject;
921:   PetscFunctionReturn(PETSC_SUCCESS);
922: }

924: /*@C
925:   DMShellGetCreateInjection - Get the routine used to create the injection operator

927:   Logically Collective

929:   Input Parameter:
930: . dm - the `DMSHELL`

932:   Output Parameter:
933: . inject - the routine to create the injection

935:   Level: advanced

937: .seealso: `DM`, `DMSHELL`, `DMShellGetCreateInterpolation()`, `DMCreateInjection()`, `DMShellSetContext()`, `DMShellGetContext()`
938: @*/
939: PetscErrorCode DMShellGetCreateInjection(DM dm, PetscErrorCode (**inject)(DM, DM, Mat *))
940: {
941:   PetscBool isshell;

943:   PetscFunctionBegin;
945:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
946:   PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs");
947:   *inject = dm->ops->createinjection;
948:   PetscFunctionReturn(PETSC_SUCCESS);
949: }

951: /*@C
952:   DMShellSetCreateFieldDecomposition - Set the routine used to create a decomposition of fields for the `DMSHELL`

954:   Logically Collective

956:   Input Parameters:
957: + dm     - the `DMSHELL`
958: - decomp - the routine to create the decomposition

960:   Level: advanced

962: .seealso: `DM`, `DMSHELL`, `DMCreateFieldDecomposition()`, `DMShellSetContext()`, `DMShellGetContext()`
963: @*/
964: PetscErrorCode DMShellSetCreateFieldDecomposition(DM dm, PetscErrorCode (*decomp)(DM, PetscInt *, char ***, IS **, DM **))
965: {
966:   PetscBool isshell;

968:   PetscFunctionBegin;
970:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
971:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
972:   dm->ops->createfielddecomposition = decomp;
973:   PetscFunctionReturn(PETSC_SUCCESS);
974: }

976: /*@C
977:   DMShellSetCreateDomainDecomposition - Set the routine used to create a domain decomposition for the `DMSHELL`

979:   Logically Collective

981:   Input Parameters:
982: + dm     - the `DMSHELL`
983: - decomp - the routine to create the decomposition

985:   Level: advanced

987: .seealso: `DM`, `DMSHELL`, `DMCreateDomainDecomposition()`, `DMShellSetContext()`, `DMShellGetContext()`
988: @*/
989: PetscErrorCode DMShellSetCreateDomainDecomposition(DM dm, PetscErrorCode (*decomp)(DM, PetscInt *, char ***, IS **, IS **, DM **))
990: {
991:   PetscBool isshell;

993:   PetscFunctionBegin;
995:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
996:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
997:   dm->ops->createdomaindecomposition = decomp;
998:   PetscFunctionReturn(PETSC_SUCCESS);
999: }

1001: /*@C
1002:   DMShellSetCreateDomainDecompositionScatters - Set the routine used to create the scatter contexts for domain decomposition with a `DMSHELL`

1004:   Logically Collective

1006:   Input Parameters:
1007: + dm      - the `DMSHELL`
1008: - scatter - the routine to create the scatters

1010:   Level: advanced

1012: .seealso: `DM`, `DMSHELL`, `DMCreateDomainDecompositionScatters()`, `DMShellSetContext()`, `DMShellGetContext()`
1013: @*/
1014: PetscErrorCode DMShellSetCreateDomainDecompositionScatters(DM dm, PetscErrorCode (*scatter)(DM, PetscInt, DM *, VecScatter **, VecScatter **, VecScatter **))
1015: {
1016:   PetscBool isshell;

1018:   PetscFunctionBegin;
1020:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
1021:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
1022:   dm->ops->createddscatters = scatter;
1023:   PetscFunctionReturn(PETSC_SUCCESS);
1024: }

1026: /*@C
1027:   DMShellSetCreateSubDM - Set the routine used to create a sub `DM` from the `DMSHELL`

1029:   Logically Collective

1031:   Input Parameters:
1032: + dm    - the `DMSHELL`
1033: - subdm - the routine to create the decomposition

1035:   Level: advanced

1037: .seealso: `DM`, `DMSHELL`, `DMCreateSubDM()`, `DMShellGetCreateSubDM()`, `DMShellSetContext()`, `DMShellGetContext()`
1038: @*/
1039: PetscErrorCode DMShellSetCreateSubDM(DM dm, PetscErrorCode (*subdm)(DM, PetscInt, const PetscInt[], IS *, DM *))
1040: {
1041:   PetscBool isshell;

1043:   PetscFunctionBegin;
1045:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
1046:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
1047:   dm->ops->createsubdm = subdm;
1048:   PetscFunctionReturn(PETSC_SUCCESS);
1049: }

1051: /*@C
1052:   DMShellGetCreateSubDM - Get the routine used to create a sub DM from the `DMSHELL`

1054:   Logically Collective

1056:   Input Parameter:
1057: . dm - the `DMSHELL`

1059:   Output Parameter:
1060: . subdm - the routine to create the decomposition

1062:   Level: advanced

1064: .seealso: `DM`, `DMSHELL`, `DMCreateSubDM()`, `DMShellSetCreateSubDM()`, `DMShellSetContext()`, `DMShellGetContext()`
1065: @*/
1066: PetscErrorCode DMShellGetCreateSubDM(DM dm, PetscErrorCode (**subdm)(DM, PetscInt, const PetscInt[], IS *, DM *))
1067: {
1068:   PetscBool isshell;

1070:   PetscFunctionBegin;
1072:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
1073:   PetscCheck(isshell, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Can only use with DMSHELL type DMs");
1074:   *subdm = dm->ops->createsubdm;
1075:   PetscFunctionReturn(PETSC_SUCCESS);
1076: }

1078: static PetscErrorCode DMDestroy_Shell(DM dm)
1079: {
1080:   DM_Shell *shell = (DM_Shell *)dm->data;

1082:   PetscFunctionBegin;
1083:   if (shell->destroyctx) PetscCallBack("Destroy Context", (*shell->destroyctx)(shell->ctx));
1084:   PetscCall(MatDestroy(&shell->A));
1085:   PetscCall(VecDestroy(&shell->Xglobal));
1086:   PetscCall(VecDestroy(&shell->Xlocal));
1087:   PetscCall(VecScatterDestroy(&shell->gtol));
1088:   PetscCall(VecScatterDestroy(&shell->ltog));
1089:   PetscCall(VecScatterDestroy(&shell->ltol));
1090:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1091:   PetscCall(PetscFree(shell));
1092:   PetscFunctionReturn(PETSC_SUCCESS);
1093: }

1095: static PetscErrorCode DMView_Shell(DM dm, PetscViewer v)
1096: {
1097:   DM_Shell *shell = (DM_Shell *)dm->data;

1099:   PetscFunctionBegin;
1100:   if (shell->Xglobal) PetscCall(VecView(shell->Xglobal, v));
1101:   PetscFunctionReturn(PETSC_SUCCESS);
1102: }

1104: static PetscErrorCode DMLoad_Shell(DM dm, PetscViewer v)
1105: {
1106:   DM_Shell *shell = (DM_Shell *)dm->data;

1108:   PetscFunctionBegin;
1109:   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &shell->Xglobal));
1110:   PetscCall(VecLoad(shell->Xglobal, v));
1111:   PetscFunctionReturn(PETSC_SUCCESS);
1112: }

1114: static PetscErrorCode DMCreateSubDM_Shell(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1115: {
1116:   PetscFunctionBegin;
1117:   if (subdm) PetscCall(DMShellCreate(PetscObjectComm((PetscObject)dm), subdm));
1118:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
1119:   PetscFunctionReturn(PETSC_SUCCESS);
1120: }

1122: PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
1123: {
1124:   DM_Shell *shell;

1126:   PetscFunctionBegin;
1127:   PetscCall(PetscNew(&shell));
1128:   dm->data = shell;

1130:   dm->ops->destroy            = DMDestroy_Shell;
1131:   dm->ops->createglobalvector = DMCreateGlobalVector_Shell;
1132:   dm->ops->createlocalvector  = DMCreateLocalVector_Shell;
1133:   dm->ops->creatematrix       = DMCreateMatrix_Shell;
1134:   dm->ops->view               = DMView_Shell;
1135:   dm->ops->load               = DMLoad_Shell;
1136:   dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell;
1137:   dm->ops->globaltolocalend   = DMGlobalToLocalEndDefaultShell;
1138:   dm->ops->localtoglobalbegin = DMLocalToGlobalBeginDefaultShell;
1139:   dm->ops->localtoglobalend   = DMLocalToGlobalEndDefaultShell;
1140:   dm->ops->localtolocalbegin  = DMLocalToLocalBeginDefaultShell;
1141:   dm->ops->localtolocalend    = DMLocalToLocalEndDefaultShell;
1142:   dm->ops->createsubdm        = DMCreateSubDM_Shell;
1143:   PetscCall(DMSetMatType(dm, MATDENSE));
1144:   PetscFunctionReturn(PETSC_SUCCESS);
1145: }

1147: /*@
1148:   DMShellCreate - Creates a `DMSHELL` object, used to manage user-defined problem data

1150:   Collective

1152:   Input Parameter:
1153: . comm - the processors that will share the global vector

1155:   Output Parameter:
1156: . dm - the `DMSHELL`

1158:   Level: advanced

1160: .seealso: `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`, `DMShellSetContext()`, `DMShellGetContext()`
1161: @*/
1162: PetscErrorCode DMShellCreate(MPI_Comm comm, DM *dm)
1163: {
1164:   PetscFunctionBegin;
1165:   PetscAssertPointer(dm, 2);
1166:   PetscCall(DMCreate(comm, dm));
1167:   PetscCall(DMSetType(*dm, DMSHELL));
1168:   PetscCall(DMSetUp(*dm));
1169:   PetscFunctionReturn(PETSC_SUCCESS);
1170: }