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