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;
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: PetscErrorCode DMCreateGlobalVector_Shell(DM dm, Vec *gvec)
201: {
202:   DM_Shell *shell = (DM_Shell *)dm->data;
203:   Vec       X;

205:   PetscFunctionBegin;
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: PetscErrorCode DMCreateLocalVector_Shell(DM dm, Vec *gvec)
219: {
220:   DM_Shell *shell = (DM_Shell *)dm->data;
221:   Vec       X;

223:   PetscFunctionBegin;
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: /*@
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 Note:
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:   PetscFunctionReturn(PETSC_SUCCESS);
415: }

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

420:    Not Collective

422:    Input Parameters:
423: +  dm - `DMSHELL`
424: -  X - template vector

426:    Level: advanced

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

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

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

447:    Logically Collective

449:    Input Parameters:
450: +  dm - the `DMSHELL`
451: -  func - the creation routine

453:    Level: advanced

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

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

468:    Logically Collective

470:    Input Parameters:
471: +  dm - `DMSHELL`
472: -  X - template vector

474:    Level: advanced

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

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

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

510:    Logically Collective

512:    Input Parameters:
513: +  dm - the `DMSHELL`
514: -  func - the creation routine

516:    Level: advanced

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

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

531:    Logically Collective on dm

533:    Input Parameters
534: +  dm - the `DMSHELL`
535: .  begin - the routine that begins the global to local scatter
536: -  end - the routine that ends the global to local scatter

538:    Level: advanced

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

544: .seealso: `DM`, `DMSHELL`, `DMShellSetLocalToGlobal()`, `DMGlobalToLocalBeginDefaultShell()`, `DMGlobalToLocalEndDefaultShell()`
545: @*/
546: PetscErrorCode DMShellSetGlobalToLocal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec))
547: {
548:   PetscFunctionBegin;
550:   dm->ops->globaltolocalbegin = begin;
551:   dm->ops->globaltolocalend   = end;
552:   PetscFunctionReturn(PETSC_SUCCESS);
553: }

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

558:    Logically Collective on dm

560:    Input Parameters
561: +  dm - the `DMSHELL`
562: .  begin - the routine that begins the local to global scatter
563: -  end - the routine that ends the local to global scatter

565:    Level: advanced

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

571: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalToLocal()`
572: @*/
573: PetscErrorCode DMShellSetLocalToGlobal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec))
574: {
575:   PetscFunctionBegin;
577:   dm->ops->localtoglobalbegin = begin;
578:   dm->ops->localtoglobalend   = end;
579:   PetscFunctionReturn(PETSC_SUCCESS);
580: }

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

585:    Logically Collective on dm

587:    Input Parameters
588: +  dm - the `DMSHELL`
589: .  begin - the routine that begins the local to local scatter
590: -  end - the routine that ends the local to local scatter

592:    Level: advanced

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

598: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalToLocal()`, `DMLocalToLocalBeginDefaultShell()`, `DMLocalToLocalEndDefaultShell()`
599: @*/
600: PetscErrorCode DMShellSetLocalToLocal(DM dm, PetscErrorCode (*begin)(DM, Vec, InsertMode, Vec), PetscErrorCode (*end)(DM, Vec, InsertMode, Vec))
601: {
602:   PetscFunctionBegin;
604:   dm->ops->localtolocalbegin = begin;
605:   dm->ops->localtolocalend   = end;
606:   PetscFunctionReturn(PETSC_SUCCESS);
607: }

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

612:    Logically Collective on dm

614:    Input Parameters
615: +  dm - the `DMSHELL`
616: -  gtol - the global to local `VecScatter` context

618:    Level: advanced

620: .seealso: `DM`, `DMSHELL`, `DMShellSetGlobalToLocal()`, `DMGlobalToLocalBeginDefaultShell()`, `DMGlobalToLocalEndDefaultShell()`
621: @*/
622: PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter gtol)
623: {
624:   DM_Shell *shell = (DM_Shell *)dm->data;

626:   PetscFunctionBegin;
629:   PetscCall(PetscObjectReference((PetscObject)gtol));
630:   PetscCall(VecScatterDestroy(&shell->gtol));
631:   shell->gtol = gtol;
632:   PetscFunctionReturn(PETSC_SUCCESS);
633: }

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

638:    Logically Collective on dm

640:    Input Parameters
641: +  dm - the `DMSHELL`
642: -  ltog - the local to global `VecScatter` context

644:    Level: advanced

646: .seealso: `DM`, `DMSHELL`, `DMShellSetLocalToGlobal()`, `DMLocalToGlobalBeginDefaultShell()`, `DMLocalToGlobalEndDefaultShell()`
647: @*/
648: PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter ltog)
649: {
650:   DM_Shell *shell = (DM_Shell *)dm->data;

652:   PetscFunctionBegin;
655:   PetscCall(PetscObjectReference((PetscObject)ltog));
656:   PetscCall(VecScatterDestroy(&shell->ltog));
657:   shell->ltog = ltog;
658:   PetscFunctionReturn(PETSC_SUCCESS);
659: }

661: /*@
662:    DMShellSetLocalToLocalVecScatter - Sets a `VecScatter` context for local to local communication

664:    Logically Collective

666:    Input Parameters
667: +  dm - the `DMSHELL`
668: -  ltol - the local to local `VecScatter` context

670:    Level: advanced

672: .seealso: `DM`, `DMSHELL`, `DMShellSetLocalToLocal()`, `DMLocalToLocalBeginDefaultShell()`, `DMLocalToLocalEndDefaultShell()`
673: @*/
674: PetscErrorCode DMShellSetLocalToLocalVecScatter(DM dm, VecScatter ltol)
675: {
676:   DM_Shell *shell = (DM_Shell *)dm->data;

678:   PetscFunctionBegin;
681:   PetscCall(PetscObjectReference((PetscObject)ltol));
682:   PetscCall(VecScatterDestroy(&shell->ltol));
683:   shell->ltol = ltol;
684:   PetscFunctionReturn(PETSC_SUCCESS);
685: }

687: /*@C
688:    DMShellSetCoarsen - Set the routine used to coarsen the `DMSHELL`

690:    Logically Collective

692:    Input Parameters
693: +  dm - the `DMSHELL`
694: -  coarsen - the routine that coarsens the `DM`

696:    Level: advanced

698: .seealso: `DM`, `DMSHELL`, `DMShellSetRefine()`, `DMCoarsen()`, `DMShellGetCoarsen()`, `DMShellSetContext()`, `DMShellGetContext()`
699: @*/
700: PetscErrorCode DMShellSetCoarsen(DM dm, PetscErrorCode (*coarsen)(DM, MPI_Comm, DM *))
701: {
702:   PetscBool isshell;

704:   PetscFunctionBegin;
706:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
707:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
708:   dm->ops->coarsen = coarsen;
709:   PetscFunctionReturn(PETSC_SUCCESS);
710: }

712: /*@C
713:    DMShellGetCoarsen - Get the routine used to coarsen the `DMSHELL`

715:    Logically Collective

717:    Input Parameter:
718: .  dm - the `DMSHELL`

720:    Output Parameter:
721: .  coarsen - the routine that coarsens the `DM`

723:    Level: advanced

725: .seealso: `DM`, `DMSHELL`, `DMShellSetCoarsen()`, `DMCoarsen()`, `DMShellSetRefine()`, `DMRefine()`
726: @*/
727: PetscErrorCode DMShellGetCoarsen(DM dm, PetscErrorCode (**coarsen)(DM, MPI_Comm, DM *))
728: {
729:   PetscBool isshell;

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

739: /*@C
740:    DMShellSetRefine - Set the routine used to refine the `DMSHELL`

742:    Logically Collective

744:    Input Parameters
745: +  dm - the `DMSHELL`
746: -  refine - the routine that refines the `DM`

748:    Level: advanced

750: .seealso: `DM`, `DMSHELL`, `DMShellSetCoarsen()`, `DMRefine()`, `DMShellGetRefine()`, `DMShellSetContext()`, `DMShellGetContext()`
751: @*/
752: PetscErrorCode DMShellSetRefine(DM dm, PetscErrorCode (*refine)(DM, MPI_Comm, DM *))
753: {
754:   PetscBool isshell;

756:   PetscFunctionBegin;
758:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
759:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
760:   dm->ops->refine = refine;
761:   PetscFunctionReturn(PETSC_SUCCESS);
762: }

764: /*@C
765:    DMShellGetRefine - Get the routine used to refine the `DMSHELL`

767:    Logically Collective

769:    Input Parameter:
770: .  dm - the `DMSHELL`

772:    Output Parameter:
773: .  refine - the routine that refines the `DM`

775:    Level: advanced

777: .seealso: `DM`, `DMSHELL`, `DMShellSetCoarsen()`, `DMCoarsen()`, `DMShellSetRefine()`, `DMRefine()`
778: @*/
779: PetscErrorCode DMShellGetRefine(DM dm, PetscErrorCode (**refine)(DM, MPI_Comm, DM *))
780: {
781:   PetscBool isshell;

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

791: /*@C
792:    DMShellSetCreateInterpolation - Set the routine used to create the interpolation operator

794:    Logically Collective

796:    Input Parameters
797: +  dm - the `DMSHELL`
798: -  interp - the routine to create the interpolation

800:    Level: advanced

802: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateInterpolation()`, `DMShellSetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()`
803: @*/
804: PetscErrorCode DMShellSetCreateInterpolation(DM dm, PetscErrorCode (*interp)(DM, DM, Mat *, Vec *))
805: {
806:   PetscBool isshell;

808:   PetscFunctionBegin;
810:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
811:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
812:   dm->ops->createinterpolation = interp;
813:   PetscFunctionReturn(PETSC_SUCCESS);
814: }

816: /*@C
817:    DMShellGetCreateInterpolation - Get the routine used to create the interpolation operator

819:    Logically Collective

821:    Input Parameter:
822: .  dm - the `DMSHELL`

824:    Output Parameter:
825: .  interp - the routine to create the interpolation

827:    Level: advanced

829: .seealso: `DM`, `DMSHELL`, `DMShellGetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()`
830: @*/
831: PetscErrorCode DMShellGetCreateInterpolation(DM dm, PetscErrorCode (**interp)(DM, DM, Mat *, Vec *))
832: {
833:   PetscBool isshell;

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

843: /*@C
844:    DMShellSetCreateRestriction - Set the routine used to create the restriction operator

846:    Logically Collective

848:    Input Parameters
849: +  dm - the `DMSHELL`
850: -  striction- the routine to create the restriction

852:    Level: advanced

854: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellGetCreateRestriction()`, `DMShellSetContext()`, `DMShellGetContext()`
855: @*/
856: PetscErrorCode DMShellSetCreateRestriction(DM dm, PetscErrorCode (*restriction)(DM, DM, Mat *))
857: {
858:   PetscBool isshell;

860:   PetscFunctionBegin;
862:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
863:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
864:   dm->ops->createrestriction = restriction;
865:   PetscFunctionReturn(PETSC_SUCCESS);
866: }

868: /*@C
869:    DMShellGetCreateRestriction - Get the routine used to create the restriction operator

871:    Logically Collective

873:    Input Parameter:
874: .  dm - the `DMSHELL`

876:    Output Parameter:
877: .  restriction - the routine to create the restriction

879:    Level: advanced

881: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInjection()`, `DMCreateInterpolation()`, `DMShellSetContext()`, `DMShellGetContext()`
882: @*/
883: PetscErrorCode DMShellGetCreateRestriction(DM dm, PetscErrorCode (**restriction)(DM, DM, Mat *))
884: {
885:   PetscBool isshell;

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

895: /*@C
896:    DMShellSetCreateInjection - Set the routine used to create the injection operator

898:    Logically Collective

900:    Input Parameters:
901: +  dm - the `DMSHELL`
902: -  inject - the routine to create the injection

904:    Level: advanced

906: .seealso: `DM`, `DMSHELL`, `DMShellSetCreateInterpolation()`, `DMCreateInjection()`, `DMShellGetCreateInjection()`, `DMShellSetContext()`, `DMShellGetContext()`
907: @*/
908: PetscErrorCode DMShellSetCreateInjection(DM dm, PetscErrorCode (*inject)(DM, DM, Mat *))
909: {
910:   PetscBool isshell;

912:   PetscFunctionBegin;
914:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
915:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
916:   dm->ops->createinjection = inject;
917:   PetscFunctionReturn(PETSC_SUCCESS);
918: }

920: /*@C
921:    DMShellGetCreateInjection - Get the routine used to create the injection operator

923:    Logically Collective

925:    Input Parameter:
926: .  dm - the `DMSHELL`

928:    Output Parameter:
929: .  inject - the routine to create the injection

931:    Level: advanced

933: .seealso: `DM`, `DMSHELL`, `DMShellGetCreateInterpolation()`, `DMCreateInjection()`, `DMShellSetContext()`, `DMShellGetContext()`
934: @*/
935: PetscErrorCode DMShellGetCreateInjection(DM dm, PetscErrorCode (**inject)(DM, DM, Mat *))
936: {
937:   PetscBool isshell;

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

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

950:    Logically Collective

952:    Input Parameters:
953: +  dm - the `DMSHELL`
954: -  decomp - the routine to create the decomposition

956:    Level: advanced

958: .seealso: `DM`, `DMSHELL`, `DMCreateFieldDecomposition()`, `DMShellSetContext()`, `DMShellGetContext()`
959: @*/
960: PetscErrorCode DMShellSetCreateFieldDecomposition(DM dm, PetscErrorCode (*decomp)(DM, PetscInt *, char ***, IS **, DM **))
961: {
962:   PetscBool isshell;

964:   PetscFunctionBegin;
966:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
967:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
968:   dm->ops->createfielddecomposition = decomp;
969:   PetscFunctionReturn(PETSC_SUCCESS);
970: }

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

975:    Logically Collective

977:    Input Parameters:
978: +  dm - the `DMSHELL`
979: -  decomp - the routine to create the decomposition

981:    Level: advanced

983: .seealso: `DM`, `DMSHELL`, `DMCreateDomainDecomposition()`, `DMShellSetContext()`, `DMShellGetContext()`
984: @*/
985: PetscErrorCode DMShellSetCreateDomainDecomposition(DM dm, PetscErrorCode (*decomp)(DM, PetscInt *, char ***, IS **, IS **, DM **))
986: {
987:   PetscBool isshell;

989:   PetscFunctionBegin;
991:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
992:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
993:   dm->ops->createdomaindecomposition = decomp;
994:   PetscFunctionReturn(PETSC_SUCCESS);
995: }

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

1000:    Logically Collective

1002:    Input Parameters:
1003: +  dm - the `DMSHELL`
1004: -  scatter - the routine to create the scatters

1006:    Level: advanced

1008: .seealso: `DM`, `DMSHELL`, `DMCreateDomainDecompositionScatters()`, `DMShellSetContext()`, `DMShellGetContext()`
1009: @*/
1010: PetscErrorCode DMShellSetCreateDomainDecompositionScatters(DM dm, PetscErrorCode (*scatter)(DM, PetscInt, DM *, VecScatter **, VecScatter **, VecScatter **))
1011: {
1012:   PetscBool isshell;

1014:   PetscFunctionBegin;
1016:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
1017:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
1018:   dm->ops->createddscatters = scatter;
1019:   PetscFunctionReturn(PETSC_SUCCESS);
1020: }

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

1025:    Logically Collective

1027:    Input Parameters:
1028: +  dm - the `DMSHELL`
1029: -  subdm - the routine to create the decomposition

1031:    Level: advanced

1033: .seealso: `DM`, `DMSHELL`, `DMCreateSubDM()`, `DMShellGetCreateSubDM()`, `DMShellSetContext()`, `DMShellGetContext()`
1034: @*/
1035: PetscErrorCode DMShellSetCreateSubDM(DM dm, PetscErrorCode (*subdm)(DM, PetscInt, const PetscInt[], IS *, DM *))
1036: {
1037:   PetscBool isshell;

1039:   PetscFunctionBegin;
1041:   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMSHELL, &isshell));
1042:   if (!isshell) PetscFunctionReturn(PETSC_SUCCESS);
1043:   dm->ops->createsubdm = subdm;
1044:   PetscFunctionReturn(PETSC_SUCCESS);
1045: }

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

1050:    Logically Collective

1052:    Input Parameter:
1053: .  dm - the `DMSHELL`

1055:    Output Parameter:
1056: .  subdm - the routine to create the decomposition

1058:    Level: advanced

1060: .seealso: `DM`, `DMSHELL`, `DMCreateSubDM()`, `DMShellSetCreateSubDM()`, `DMShellSetContext()`, `DMShellGetContext()`
1061: @*/
1062: PetscErrorCode DMShellGetCreateSubDM(DM dm, PetscErrorCode (**subdm)(DM, PetscInt, const PetscInt[], IS *, DM *))
1063: {
1064:   PetscBool isshell;

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

1074: static PetscErrorCode DMDestroy_Shell(DM dm)
1075: {
1076:   DM_Shell *shell = (DM_Shell *)dm->data;

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

1091: static PetscErrorCode DMView_Shell(DM dm, PetscViewer v)
1092: {
1093:   DM_Shell *shell = (DM_Shell *)dm->data;

1095:   PetscFunctionBegin;
1096:   if (shell->Xglobal) PetscCall(VecView(shell->Xglobal, v));
1097:   PetscFunctionReturn(PETSC_SUCCESS);
1098: }

1100: static PetscErrorCode DMLoad_Shell(DM dm, PetscViewer v)
1101: {
1102:   DM_Shell *shell = (DM_Shell *)dm->data;

1104:   PetscFunctionBegin;
1105:   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &shell->Xglobal));
1106:   PetscCall(VecLoad(shell->Xglobal, v));
1107:   PetscFunctionReturn(PETSC_SUCCESS);
1108: }

1110: PetscErrorCode DMCreateSubDM_Shell(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1111: {
1112:   PetscFunctionBegin;
1113:   if (subdm) PetscCall(DMShellCreate(PetscObjectComm((PetscObject)dm), subdm));
1114:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
1115:   PetscFunctionReturn(PETSC_SUCCESS);
1116: }

1118: PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
1119: {
1120:   DM_Shell *shell;

1122:   PetscFunctionBegin;
1123:   PetscCall(PetscNew(&shell));
1124:   dm->data = shell;

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

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

1146:     Collective

1148:     Input Parameter:
1149: .   comm - the processors that will share the global vector

1151:     Output Parameter:
1152: .   shell - the `DMSHELL`

1154:     Level: advanced

1156: .seealso `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`, `DMShellSetContext()`, `DMShellGetContext()`
1157: @*/
1158: PetscErrorCode DMShellCreate(MPI_Comm comm, DM *dm)
1159: {
1160:   PetscFunctionBegin;
1162:   PetscCall(DMCreate(comm, dm));
1163:   PetscCall(DMSetType(*dm, DMSHELL));
1164:   PetscCall(DMSetUp(*dm));
1165:   PetscFunctionReturn(PETSC_SUCCESS);
1166: }