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