xref: /petsc/src/dm/impls/composite/pack.c (revision 1b37a2a7cc4a4fb30c3e967db1c694c0a1013f51)
1 #include <../src/dm/impls/composite/packimpl.h> /*I  "petscdmcomposite.h"  I*/
2 #include <petsc/private/isimpl.h>
3 #include <petsc/private/glvisviewerimpl.h>
4 #include <petscds.h>
5 
6 /*@C
7   DMCompositeSetCoupling - Sets user provided routines that compute the coupling between the
8   separate components `DM` in a `DMCOMPOSITE` to build the correct matrix nonzero structure.
9 
10   Logically Collective; No Fortran Support
11 
12   Input Parameters:
13 + dm                  - the composite object
14 - FormCoupleLocations - routine to set the nonzero locations in the matrix
15 
16   Level: advanced
17 
18   Note:
19   See `DMSetApplicationContext()` and `DMGetApplicationContext()` for how to get user information into
20   this routine
21 
22 .seealso: `DMCOMPOSITE`, `DM`
23 @*/
24 PetscErrorCode DMCompositeSetCoupling(DM dm, PetscErrorCode (*FormCoupleLocations)(DM, Mat, PetscInt *, PetscInt *, PetscInt, PetscInt, PetscInt, PetscInt))
25 {
26   DM_Composite *com = (DM_Composite *)dm->data;
27   PetscBool     flg;
28 
29   PetscFunctionBegin;
30   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
31   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
32   com->FormCoupleLocations = FormCoupleLocations;
33   PetscFunctionReturn(PETSC_SUCCESS);
34 }
35 
36 static PetscErrorCode DMDestroy_Composite(DM dm)
37 {
38   struct DMCompositeLink *next, *prev;
39   DM_Composite           *com = (DM_Composite *)dm->data;
40 
41   PetscFunctionBegin;
42   next = com->next;
43   while (next) {
44     prev = next;
45     next = next->next;
46     PetscCall(DMDestroy(&prev->dm));
47     PetscCall(PetscFree(prev->grstarts));
48     PetscCall(PetscFree(prev));
49   }
50   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
51   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
52   PetscCall(PetscFree(com));
53   PetscFunctionReturn(PETSC_SUCCESS);
54 }
55 
56 static PetscErrorCode DMView_Composite(DM dm, PetscViewer v)
57 {
58   PetscBool     iascii;
59   DM_Composite *com = (DM_Composite *)dm->data;
60 
61   PetscFunctionBegin;
62   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
63   if (iascii) {
64     struct DMCompositeLink *lnk = com->next;
65     PetscInt                i;
66 
67     PetscCall(PetscViewerASCIIPrintf(v, "DM (%s)\n", ((PetscObject)dm)->prefix ? ((PetscObject)dm)->prefix : "no prefix"));
68     PetscCall(PetscViewerASCIIPrintf(v, "  contains %" PetscInt_FMT " DMs\n", com->nDM));
69     PetscCall(PetscViewerASCIIPushTab(v));
70     for (i = 0; lnk; lnk = lnk->next, i++) {
71       PetscCall(PetscViewerASCIIPrintf(v, "Link %" PetscInt_FMT ": DM of type %s\n", i, ((PetscObject)lnk->dm)->type_name));
72       PetscCall(PetscViewerASCIIPushTab(v));
73       PetscCall(DMView(lnk->dm, v));
74       PetscCall(PetscViewerASCIIPopTab(v));
75     }
76     PetscCall(PetscViewerASCIIPopTab(v));
77   }
78   PetscFunctionReturn(PETSC_SUCCESS);
79 }
80 
81 /* --------------------------------------------------------------------------------------*/
82 static PetscErrorCode DMSetUp_Composite(DM dm)
83 {
84   PetscInt                nprev = 0;
85   PetscMPIInt             rank, size;
86   DM_Composite           *com  = (DM_Composite *)dm->data;
87   struct DMCompositeLink *next = com->next;
88   PetscLayout             map;
89 
90   PetscFunctionBegin;
91   PetscCheck(!com->setup, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Packer has already been setup");
92   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &map));
93   PetscCall(PetscLayoutSetLocalSize(map, com->n));
94   PetscCall(PetscLayoutSetSize(map, PETSC_DETERMINE));
95   PetscCall(PetscLayoutSetBlockSize(map, 1));
96   PetscCall(PetscLayoutSetUp(map));
97   PetscCall(PetscLayoutGetSize(map, &com->N));
98   PetscCall(PetscLayoutGetRange(map, &com->rstart, NULL));
99   PetscCall(PetscLayoutDestroy(&map));
100 
101   /* now set the rstart for each linked vector */
102   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
103   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
104   while (next) {
105     next->rstart = nprev;
106     nprev += next->n;
107     next->grstart = com->rstart + next->rstart;
108     PetscCall(PetscMalloc1(size, &next->grstarts));
109     PetscCallMPI(MPI_Allgather(&next->grstart, 1, MPIU_INT, next->grstarts, 1, MPIU_INT, PetscObjectComm((PetscObject)dm)));
110     next = next->next;
111   }
112   com->setup = PETSC_TRUE;
113   PetscFunctionReturn(PETSC_SUCCESS);
114 }
115 
116 /* ----------------------------------------------------------------------------------*/
117 
118 /*@
119   DMCompositeGetNumberDM - Gets the number of `DM` objects in the `DMCOMPOSITE`
120   representation.
121 
122   Not Collective
123 
124   Input Parameter:
125 . dm - the `DMCOMPOSITE` object
126 
127   Output Parameter:
128 . nDM - the number of `DM`
129 
130   Level: beginner
131 
132 .seealso: `DMCOMPOSITE`, `DM`
133 @*/
134 PetscErrorCode DMCompositeGetNumberDM(DM dm, PetscInt *nDM)
135 {
136   DM_Composite *com = (DM_Composite *)dm->data;
137   PetscBool     flg;
138 
139   PetscFunctionBegin;
140   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
141   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
142   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
143   *nDM = com->nDM;
144   PetscFunctionReturn(PETSC_SUCCESS);
145 }
146 
147 /*@C
148   DMCompositeGetAccess - Allows one to access the individual packed vectors in their global
149   representation.
150 
151   Collective
152 
153   Input Parameters:
154 + dm   - the `DMCOMPOSITE` object
155 - gvec - the global vector
156 
157   Output Parameter:
158 . ... - the packed parallel vectors, `NULL` for those that are not needed
159 
160   Level: advanced
161 
162   Note:
163   Use `DMCompositeRestoreAccess()` to return the vectors when you no longer need them
164 
165   Fortran Notes:
166   Fortran callers must use numbered versions of this routine, e.g., DMCompositeGetAccess4(dm,gvec,vec1,vec2,vec3,vec4)
167   or use the alternative interface `DMCompositeGetAccessArray()`.
168 
169 .seealso: `DMCOMPOSITE`, `DM`, `DMCompositeGetEntries()`, `DMCompositeScatter()`
170 @*/
171 PetscErrorCode DMCompositeGetAccess(DM dm, Vec gvec, ...)
172 {
173   va_list                 Argp;
174   struct DMCompositeLink *next;
175   DM_Composite           *com = (DM_Composite *)dm->data;
176   PetscInt                readonly;
177   PetscBool               flg;
178 
179   PetscFunctionBegin;
180   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
181   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 2);
182   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
183   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
184   next = com->next;
185   if (!com->setup) PetscCall(DMSetUp(dm));
186 
187   PetscCall(VecLockGet(gvec, &readonly));
188   /* loop over packed objects, handling one at at time */
189   va_start(Argp, gvec);
190   while (next) {
191     Vec *vec;
192     vec = va_arg(Argp, Vec *);
193     if (vec) {
194       PetscCall(DMGetGlobalVector(next->dm, vec));
195       if (readonly) {
196         const PetscScalar *array;
197         PetscCall(VecGetArrayRead(gvec, &array));
198         PetscCall(VecPlaceArray(*vec, array + next->rstart));
199         PetscCall(VecLockReadPush(*vec));
200         PetscCall(VecRestoreArrayRead(gvec, &array));
201       } else {
202         PetscScalar *array;
203         PetscCall(VecGetArray(gvec, &array));
204         PetscCall(VecPlaceArray(*vec, array + next->rstart));
205         PetscCall(VecRestoreArray(gvec, &array));
206       }
207     }
208     next = next->next;
209   }
210   va_end(Argp);
211   PetscFunctionReturn(PETSC_SUCCESS);
212 }
213 
214 /*@C
215   DMCompositeGetAccessArray - Allows one to access the individual packed vectors in their global
216   representation.
217 
218   Collective
219 
220   Input Parameters:
221 + dm      - the `DMCOMPOSITE`
222 . pvec    - packed vector
223 . nwanted - number of vectors wanted
224 - wanted  - sorted array of vectors wanted, or NULL to get all vectors
225 
226   Output Parameter:
227 . vecs - array of requested global vectors (must be allocated)
228 
229   Level: advanced
230 
231   Note:
232   Use `DMCompositeRestoreAccessArray()` to return the vectors when you no longer need them
233 
234 .seealso: `DMCOMPOSITE`, `DM`, `DMCompositeGetAccess()`, `DMCompositeGetEntries()`, `DMCompositeScatter()`, `DMCompositeGather()`
235 @*/
236 PetscErrorCode DMCompositeGetAccessArray(DM dm, Vec pvec, PetscInt nwanted, const PetscInt *wanted, Vec *vecs)
237 {
238   struct DMCompositeLink *link;
239   PetscInt                i, wnum;
240   DM_Composite           *com = (DM_Composite *)dm->data;
241   PetscInt                readonly;
242   PetscBool               flg;
243 
244   PetscFunctionBegin;
245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
246   PetscValidHeaderSpecific(pvec, VEC_CLASSID, 2);
247   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
248   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
249   if (!com->setup) PetscCall(DMSetUp(dm));
250 
251   PetscCall(VecLockGet(pvec, &readonly));
252   for (i = 0, wnum = 0, link = com->next; link && wnum < nwanted; i++, link = link->next) {
253     if (!wanted || i == wanted[wnum]) {
254       Vec v;
255       PetscCall(DMGetGlobalVector(link->dm, &v));
256       if (readonly) {
257         const PetscScalar *array;
258         PetscCall(VecGetArrayRead(pvec, &array));
259         PetscCall(VecPlaceArray(v, array + link->rstart));
260         PetscCall(VecLockReadPush(v));
261         PetscCall(VecRestoreArrayRead(pvec, &array));
262       } else {
263         PetscScalar *array;
264         PetscCall(VecGetArray(pvec, &array));
265         PetscCall(VecPlaceArray(v, array + link->rstart));
266         PetscCall(VecRestoreArray(pvec, &array));
267       }
268       vecs[wnum++] = v;
269     }
270   }
271   PetscFunctionReturn(PETSC_SUCCESS);
272 }
273 
274 /*@C
275   DMCompositeGetLocalAccessArray - Allows one to access the individual
276   packed vectors in their local representation.
277 
278   Collective
279 
280   Input Parameters:
281 + dm      - the `DMCOMPOSITE`
282 . pvec    - packed vector
283 . nwanted - number of vectors wanted
284 - wanted  - sorted array of vectors wanted, or NULL to get all vectors
285 
286   Output Parameter:
287 . vecs - array of requested local vectors (must be allocated)
288 
289   Level: advanced
290 
291   Note:
292   Use `DMCompositeRestoreLocalAccessArray()` to return the vectors
293   when you no longer need them.
294 
295 .seealso: `DMCOMPOSITE`, `DM`, `DMCompositeRestoreLocalAccessArray()`, `DMCompositeGetAccess()`,
296           `DMCompositeGetEntries()`, `DMCompositeScatter()`, `DMCompositeGather()`
297 @*/
298 PetscErrorCode DMCompositeGetLocalAccessArray(DM dm, Vec pvec, PetscInt nwanted, const PetscInt *wanted, Vec *vecs)
299 {
300   struct DMCompositeLink *link;
301   PetscInt                i, wnum;
302   DM_Composite           *com = (DM_Composite *)dm->data;
303   PetscInt                readonly;
304   PetscInt                nlocal = 0;
305   PetscBool               flg;
306 
307   PetscFunctionBegin;
308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
309   PetscValidHeaderSpecific(pvec, VEC_CLASSID, 2);
310   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
311   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
312   if (!com->setup) PetscCall(DMSetUp(dm));
313 
314   PetscCall(VecLockGet(pvec, &readonly));
315   for (i = 0, wnum = 0, link = com->next; link && wnum < nwanted; i++, link = link->next) {
316     if (!wanted || i == wanted[wnum]) {
317       Vec v;
318       PetscCall(DMGetLocalVector(link->dm, &v));
319       if (readonly) {
320         const PetscScalar *array;
321         PetscCall(VecGetArrayRead(pvec, &array));
322         PetscCall(VecPlaceArray(v, array + nlocal));
323         // this method does not make sense. The local vectors are not updated with a global-to-local and the user can not do it because it is locked
324         PetscCall(VecLockReadPush(v));
325         PetscCall(VecRestoreArrayRead(pvec, &array));
326       } else {
327         PetscScalar *array;
328         PetscCall(VecGetArray(pvec, &array));
329         PetscCall(VecPlaceArray(v, array + nlocal));
330         PetscCall(VecRestoreArray(pvec, &array));
331       }
332       vecs[wnum++] = v;
333     }
334 
335     nlocal += link->nlocal;
336   }
337 
338   PetscFunctionReturn(PETSC_SUCCESS);
339 }
340 
341 /*@C
342   DMCompositeRestoreAccess - Returns the vectors obtained with `DMCompositeGetAccess()`
343   representation.
344 
345   Collective
346 
347   Input Parameters:
348 + dm   - the `DMCOMPOSITE` object
349 . gvec - the global vector
350 - ...  - the individual parallel vectors, `NULL` for those that are not needed
351 
352   Level: advanced
353 
354 .seealso: `DMCOMPOSITE`, `DM`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
355          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeScatter()`,
356          `DMCompositeGetAccess()`
357 @*/
358 PetscErrorCode DMCompositeRestoreAccess(DM dm, Vec gvec, ...)
359 {
360   va_list                 Argp;
361   struct DMCompositeLink *next;
362   DM_Composite           *com = (DM_Composite *)dm->data;
363   PetscInt                readonly;
364   PetscBool               flg;
365 
366   PetscFunctionBegin;
367   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
368   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 2);
369   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
370   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
371   next = com->next;
372   if (!com->setup) PetscCall(DMSetUp(dm));
373 
374   PetscCall(VecLockGet(gvec, &readonly));
375   /* loop over packed objects, handling one at at time */
376   va_start(Argp, gvec);
377   while (next) {
378     Vec *vec;
379     vec = va_arg(Argp, Vec *);
380     if (vec) {
381       PetscCall(VecResetArray(*vec));
382       if (readonly) PetscCall(VecLockReadPop(*vec));
383       PetscCall(DMRestoreGlobalVector(next->dm, vec));
384     }
385     next = next->next;
386   }
387   va_end(Argp);
388   PetscFunctionReturn(PETSC_SUCCESS);
389 }
390 
391 /*@C
392   DMCompositeRestoreAccessArray - Returns the vectors obtained with `DMCompositeGetAccessArray()`
393 
394   Collective
395 
396   Input Parameters:
397 + dm      - the `DMCOMPOSITE` object
398 . pvec    - packed vector
399 . nwanted - number of vectors wanted
400 . wanted  - sorted array of vectors wanted, or NULL to get all vectors
401 - vecs    - array of global vectors to return
402 
403   Level: advanced
404 
405 .seealso: `DMCOMPOSITE`, `DM`, `DMCompositeRestoreAccess()`, `DMCompositeRestoreEntries()`, `DMCompositeScatter()`, `DMCompositeGather()`
406 @*/
407 PetscErrorCode DMCompositeRestoreAccessArray(DM dm, Vec pvec, PetscInt nwanted, const PetscInt *wanted, Vec *vecs)
408 {
409   struct DMCompositeLink *link;
410   PetscInt                i, wnum;
411   DM_Composite           *com = (DM_Composite *)dm->data;
412   PetscInt                readonly;
413   PetscBool               flg;
414 
415   PetscFunctionBegin;
416   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
417   PetscValidHeaderSpecific(pvec, VEC_CLASSID, 2);
418   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
419   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
420   if (!com->setup) PetscCall(DMSetUp(dm));
421 
422   PetscCall(VecLockGet(pvec, &readonly));
423   for (i = 0, wnum = 0, link = com->next; link && wnum < nwanted; i++, link = link->next) {
424     if (!wanted || i == wanted[wnum]) {
425       PetscCall(VecResetArray(vecs[wnum]));
426       if (readonly) PetscCall(VecLockReadPop(vecs[wnum]));
427       PetscCall(DMRestoreGlobalVector(link->dm, &vecs[wnum]));
428       wnum++;
429     }
430   }
431   PetscFunctionReturn(PETSC_SUCCESS);
432 }
433 
434 /*@C
435   DMCompositeRestoreLocalAccessArray - Returns the vectors obtained with `DMCompositeGetLocalAccessArray()`.
436 
437   Collective
438 
439   Input Parameters:
440 + dm      - the `DMCOMPOSITE` object
441 . pvec    - packed vector
442 . nwanted - number of vectors wanted
443 . wanted  - sorted array of vectors wanted, or NULL to restore all vectors
444 - vecs    - array of local vectors to return
445 
446   Level: advanced
447 
448   Note:
449   nwanted and wanted must match the values given to `DMCompositeGetLocalAccessArray()`
450   otherwise the call will fail.
451 
452 .seealso: `DMCOMPOSITE`, `DM`, `DMCompositeGetLocalAccessArray()`, `DMCompositeRestoreAccessArray()`,
453           `DMCompositeRestoreAccess()`, `DMCompositeRestoreEntries()`,
454           `DMCompositeScatter()`, `DMCompositeGather()`
455 @*/
456 PetscErrorCode DMCompositeRestoreLocalAccessArray(DM dm, Vec pvec, PetscInt nwanted, const PetscInt *wanted, Vec *vecs)
457 {
458   struct DMCompositeLink *link;
459   PetscInt                i, wnum;
460   DM_Composite           *com = (DM_Composite *)dm->data;
461   PetscInt                readonly;
462   PetscBool               flg;
463 
464   PetscFunctionBegin;
465   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
466   PetscValidHeaderSpecific(pvec, VEC_CLASSID, 2);
467   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
468   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
469   if (!com->setup) PetscCall(DMSetUp(dm));
470 
471   PetscCall(VecLockGet(pvec, &readonly));
472   for (i = 0, wnum = 0, link = com->next; link && wnum < nwanted; i++, link = link->next) {
473     if (!wanted || i == wanted[wnum]) {
474       PetscCall(VecResetArray(vecs[wnum]));
475       if (readonly) PetscCall(VecLockReadPop(vecs[wnum]));
476       PetscCall(DMRestoreLocalVector(link->dm, &vecs[wnum]));
477       wnum++;
478     }
479   }
480   PetscFunctionReturn(PETSC_SUCCESS);
481 }
482 
483 /*@C
484   DMCompositeScatter - Scatters from a global packed vector into its individual local vectors
485 
486   Collective
487 
488   Input Parameters:
489 + dm   - the `DMCOMPOSITE` object
490 . gvec - the global vector
491 - ...  - the individual sequential vectors, `NULL` for those that are not needed
492 
493   Level: advanced
494 
495   Note:
496   `DMCompositeScatterArray()` is a non-variadic alternative that is often more convenient for library callers and is
497   accessible from Fortran.
498 
499 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
500          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
501          `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`
502          `DMCompositeScatterArray()`
503 @*/
504 PetscErrorCode DMCompositeScatter(DM dm, Vec gvec, ...)
505 {
506   va_list                 Argp;
507   struct DMCompositeLink *next;
508   PETSC_UNUSED PetscInt   cnt;
509   DM_Composite           *com = (DM_Composite *)dm->data;
510   PetscBool               flg;
511 
512   PetscFunctionBegin;
513   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
514   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 2);
515   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
516   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
517   if (!com->setup) PetscCall(DMSetUp(dm));
518 
519   /* loop over packed objects, handling one at at time */
520   va_start(Argp, gvec);
521   for (cnt = 3, next = com->next; next; cnt++, next = next->next) {
522     Vec local;
523     local = va_arg(Argp, Vec);
524     if (local) {
525       Vec                global;
526       const PetscScalar *array;
527       PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PetscValidHeaderSpecific(local, VEC_CLASSID, (int)cnt));
528       PetscCall(DMGetGlobalVector(next->dm, &global));
529       PetscCall(VecGetArrayRead(gvec, &array));
530       PetscCall(VecPlaceArray(global, array + next->rstart));
531       PetscCall(DMGlobalToLocalBegin(next->dm, global, INSERT_VALUES, local));
532       PetscCall(DMGlobalToLocalEnd(next->dm, global, INSERT_VALUES, local));
533       PetscCall(VecRestoreArrayRead(gvec, &array));
534       PetscCall(VecResetArray(global));
535       PetscCall(DMRestoreGlobalVector(next->dm, &global));
536     }
537   }
538   va_end(Argp);
539   PetscFunctionReturn(PETSC_SUCCESS);
540 }
541 
542 /*@
543   DMCompositeScatterArray - Scatters from a global packed vector into its individual local vectors
544 
545   Collective
546 
547   Input Parameters:
548 + dm    - the `DMCOMPOSITE` object
549 . gvec  - the global vector
550 - lvecs - array of local vectors, NULL for any that are not needed
551 
552   Level: advanced
553 
554   Note:
555   This is a non-variadic alternative to `DMCompositeScatter()`
556 
557 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`
558          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
559          `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`
560 @*/
561 PetscErrorCode DMCompositeScatterArray(DM dm, Vec gvec, Vec *lvecs)
562 {
563   struct DMCompositeLink *next;
564   PetscInt                i;
565   DM_Composite           *com = (DM_Composite *)dm->data;
566   PetscBool               flg;
567 
568   PetscFunctionBegin;
569   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
570   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 2);
571   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
572   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
573   if (!com->setup) PetscCall(DMSetUp(dm));
574 
575   /* loop over packed objects, handling one at at time */
576   for (i = 0, next = com->next; next; next = next->next, i++) {
577     if (lvecs[i]) {
578       Vec                global;
579       const PetscScalar *array;
580       PetscValidHeaderSpecific(lvecs[i], VEC_CLASSID, 3);
581       PetscCall(DMGetGlobalVector(next->dm, &global));
582       PetscCall(VecGetArrayRead(gvec, &array));
583       PetscCall(VecPlaceArray(global, (PetscScalar *)array + next->rstart));
584       PetscCall(DMGlobalToLocalBegin(next->dm, global, INSERT_VALUES, lvecs[i]));
585       PetscCall(DMGlobalToLocalEnd(next->dm, global, INSERT_VALUES, lvecs[i]));
586       PetscCall(VecRestoreArrayRead(gvec, &array));
587       PetscCall(VecResetArray(global));
588       PetscCall(DMRestoreGlobalVector(next->dm, &global));
589     }
590   }
591   PetscFunctionReturn(PETSC_SUCCESS);
592 }
593 
594 /*@C
595   DMCompositeGather - Gathers into a global packed vector from its individual local vectors
596 
597   Collective
598 
599   Input Parameters:
600 + dm    - the `DMCOMPOSITE` object
601 . imode - `INSERT_VALUES` or `ADD_VALUES`
602 . gvec  - the global vector
603 - ...   - the individual sequential vectors, `NULL` for any that are not needed
604 
605   Level: advanced
606 
607   Fortran Notes:
608   Fortran users should use `DMCompositeGatherArray()`
609 
610 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
611          `DMCompositeScatter()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
612          `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`
613 @*/
614 PetscErrorCode DMCompositeGather(DM dm, InsertMode imode, Vec gvec, ...)
615 {
616   va_list                 Argp;
617   struct DMCompositeLink *next;
618   DM_Composite           *com = (DM_Composite *)dm->data;
619   PETSC_UNUSED PetscInt   cnt;
620   PetscBool               flg;
621 
622   PetscFunctionBegin;
623   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
624   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 3);
625   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
626   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
627   if (!com->setup) PetscCall(DMSetUp(dm));
628 
629   /* loop over packed objects, handling one at at time */
630   va_start(Argp, gvec);
631   for (cnt = 3, next = com->next; next; cnt++, next = next->next) {
632     Vec local;
633     local = va_arg(Argp, Vec);
634     if (local) {
635       PetscScalar *array;
636       Vec          global;
637       PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PetscValidHeaderSpecific(local, VEC_CLASSID, (int)cnt));
638       PetscCall(DMGetGlobalVector(next->dm, &global));
639       PetscCall(VecGetArray(gvec, &array));
640       PetscCall(VecPlaceArray(global, array + next->rstart));
641       PetscCall(DMLocalToGlobalBegin(next->dm, local, imode, global));
642       PetscCall(DMLocalToGlobalEnd(next->dm, local, imode, global));
643       PetscCall(VecRestoreArray(gvec, &array));
644       PetscCall(VecResetArray(global));
645       PetscCall(DMRestoreGlobalVector(next->dm, &global));
646     }
647   }
648   va_end(Argp);
649   PetscFunctionReturn(PETSC_SUCCESS);
650 }
651 
652 /*@
653   DMCompositeGatherArray - Gathers into a global packed vector from its individual local vectors
654 
655   Collective
656 
657   Input Parameters:
658 + dm    - the `DMCOMPOSITE` object
659 . gvec  - the global vector
660 . imode - `INSERT_VALUES` or `ADD_VALUES`
661 - lvecs - the individual sequential vectors, NULL for any that are not needed
662 
663   Level: advanced
664 
665   Note:
666   This is a non-variadic alternative to `DMCompositeGather()`.
667 
668 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
669          `DMCompositeScatter()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
670          `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`,
671 @*/
672 PetscErrorCode DMCompositeGatherArray(DM dm, InsertMode imode, Vec gvec, Vec *lvecs)
673 {
674   struct DMCompositeLink *next;
675   DM_Composite           *com = (DM_Composite *)dm->data;
676   PetscInt                i;
677   PetscBool               flg;
678 
679   PetscFunctionBegin;
680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
681   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 3);
682   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
683   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
684   if (!com->setup) PetscCall(DMSetUp(dm));
685 
686   /* loop over packed objects, handling one at at time */
687   for (next = com->next, i = 0; next; next = next->next, i++) {
688     if (lvecs[i]) {
689       PetscScalar *array;
690       Vec          global;
691       PetscValidHeaderSpecific(lvecs[i], VEC_CLASSID, 4);
692       PetscCall(DMGetGlobalVector(next->dm, &global));
693       PetscCall(VecGetArray(gvec, &array));
694       PetscCall(VecPlaceArray(global, array + next->rstart));
695       PetscCall(DMLocalToGlobalBegin(next->dm, lvecs[i], imode, global));
696       PetscCall(DMLocalToGlobalEnd(next->dm, lvecs[i], imode, global));
697       PetscCall(VecRestoreArray(gvec, &array));
698       PetscCall(VecResetArray(global));
699       PetscCall(DMRestoreGlobalVector(next->dm, &global));
700     }
701   }
702   PetscFunctionReturn(PETSC_SUCCESS);
703 }
704 
705 /*@
706   DMCompositeAddDM - adds a `DM` vector to a `DMCOMPOSITE`
707 
708   Collective
709 
710   Input Parameters:
711 + dmc - the  `DMCOMPOSITE` object
712 - dm  - the `DM` object
713 
714   Level: advanced
715 
716 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeGather()`, `DMCreateGlobalVector()`,
717          `DMCompositeScatter()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
718          `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`
719 @*/
720 PetscErrorCode DMCompositeAddDM(DM dmc, DM dm)
721 {
722   PetscInt                n, nlocal;
723   struct DMCompositeLink *mine, *next;
724   Vec                     global, local;
725   DM_Composite           *com = (DM_Composite *)dmc->data;
726   PetscBool               flg;
727 
728   PetscFunctionBegin;
729   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
730   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
731   PetscCall(PetscObjectTypeCompare((PetscObject)dmc, DMCOMPOSITE, &flg));
732   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
733   next = com->next;
734   PetscCheck(!com->setup, PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONGSTATE, "Cannot add a DM once you have used the DMComposite");
735 
736   /* create new link */
737   PetscCall(PetscNew(&mine));
738   PetscCall(PetscObjectReference((PetscObject)dm));
739   PetscCall(DMGetGlobalVector(dm, &global));
740   PetscCall(VecGetLocalSize(global, &n));
741   PetscCall(DMRestoreGlobalVector(dm, &global));
742   PetscCall(DMGetLocalVector(dm, &local));
743   PetscCall(VecGetSize(local, &nlocal));
744   PetscCall(DMRestoreLocalVector(dm, &local));
745 
746   mine->n      = n;
747   mine->nlocal = nlocal;
748   mine->dm     = dm;
749   mine->next   = NULL;
750   com->n += n;
751   com->nghost += nlocal;
752 
753   /* add to end of list */
754   if (!next) com->next = mine;
755   else {
756     while (next->next) next = next->next;
757     next->next = mine;
758   }
759   com->nDM++;
760   com->nmine++;
761   PetscFunctionReturn(PETSC_SUCCESS);
762 }
763 
764 #include <petscdraw.h>
765 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
766 static PetscErrorCode       VecView_DMComposite(Vec gvec, PetscViewer viewer)
767 {
768   DM                      dm;
769   struct DMCompositeLink *next;
770   PetscBool               isdraw;
771   DM_Composite           *com;
772 
773   PetscFunctionBegin;
774   PetscCall(VecGetDM(gvec, &dm));
775   PetscCheck(dm, PetscObjectComm((PetscObject)gvec), PETSC_ERR_ARG_WRONG, "Vector not generated from a DMComposite");
776   com  = (DM_Composite *)dm->data;
777   next = com->next;
778 
779   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
780   if (!isdraw) {
781     /* do I really want to call this? */
782     PetscCall(VecView_MPI(gvec, viewer));
783   } else {
784     PetscInt cnt = 0;
785 
786     /* loop over packed objects, handling one at at time */
787     while (next) {
788       Vec                vec;
789       const PetscScalar *array;
790       PetscInt           bs;
791 
792       /* Should use VecGetSubVector() eventually, but would need to forward the DM for that to work */
793       PetscCall(DMGetGlobalVector(next->dm, &vec));
794       PetscCall(VecGetArrayRead(gvec, &array));
795       PetscCall(VecPlaceArray(vec, (PetscScalar *)array + next->rstart));
796       PetscCall(VecRestoreArrayRead(gvec, &array));
797       PetscCall(VecView(vec, viewer));
798       PetscCall(VecResetArray(vec));
799       PetscCall(VecGetBlockSize(vec, &bs));
800       PetscCall(DMRestoreGlobalVector(next->dm, &vec));
801       PetscCall(PetscViewerDrawBaseAdd(viewer, bs));
802       cnt += bs;
803       next = next->next;
804     }
805     PetscCall(PetscViewerDrawBaseAdd(viewer, -cnt));
806   }
807   PetscFunctionReturn(PETSC_SUCCESS);
808 }
809 
810 static PetscErrorCode DMCreateGlobalVector_Composite(DM dm, Vec *gvec)
811 {
812   DM_Composite *com = (DM_Composite *)dm->data;
813 
814   PetscFunctionBegin;
815   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
816   PetscCall(DMSetFromOptions(dm));
817   PetscCall(DMSetUp(dm));
818   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), gvec));
819   PetscCall(VecSetType(*gvec, dm->vectype));
820   PetscCall(VecSetSizes(*gvec, com->n, com->N));
821   PetscCall(VecSetDM(*gvec, dm));
822   PetscCall(VecSetOperation(*gvec, VECOP_VIEW, (void (*)(void))VecView_DMComposite));
823   PetscFunctionReturn(PETSC_SUCCESS);
824 }
825 
826 static PetscErrorCode DMCreateLocalVector_Composite(DM dm, Vec *lvec)
827 {
828   DM_Composite *com = (DM_Composite *)dm->data;
829 
830   PetscFunctionBegin;
831   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
832   if (!com->setup) {
833     PetscCall(DMSetFromOptions(dm));
834     PetscCall(DMSetUp(dm));
835   }
836   PetscCall(VecCreate(PETSC_COMM_SELF, lvec));
837   PetscCall(VecSetType(*lvec, dm->vectype));
838   PetscCall(VecSetSizes(*lvec, com->nghost, PETSC_DECIDE));
839   PetscCall(VecSetDM(*lvec, dm));
840   PetscFunctionReturn(PETSC_SUCCESS);
841 }
842 
843 /*@C
844   DMCompositeGetISLocalToGlobalMappings - gets an `ISLocalToGlobalMapping` for each `DM` in the `DMCOMPOSITE`, maps to the composite global space
845 
846   Collective; No Fortran Support
847 
848   Input Parameter:
849 . dm - the `DMCOMPOSITE` object
850 
851   Output Parameter:
852 . ltogs - the individual mappings for each packed vector. Note that this includes
853            all the ghost points that individual ghosted `DMDA` may have.
854 
855   Level: advanced
856 
857   Note:
858   Each entry of ltogs should be destroyed with `ISLocalToGlobalMappingDestroy()`, the ltogs array should be freed with `PetscFree()`.
859 
860 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
861          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetAccess()`, `DMCompositeScatter()`,
862          `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`
863 @*/
864 PetscErrorCode DMCompositeGetISLocalToGlobalMappings(DM dm, ISLocalToGlobalMapping **ltogs)
865 {
866   PetscInt                i, *idx, n, cnt;
867   struct DMCompositeLink *next;
868   PetscMPIInt             rank;
869   DM_Composite           *com = (DM_Composite *)dm->data;
870   PetscBool               flg;
871 
872   PetscFunctionBegin;
873   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
874   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
875   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
876   PetscCall(DMSetUp(dm));
877   PetscCall(PetscMalloc1(com->nDM, ltogs));
878   next = com->next;
879   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
880 
881   /* loop over packed objects, handling one at at time */
882   cnt = 0;
883   while (next) {
884     ISLocalToGlobalMapping ltog;
885     PetscMPIInt            size;
886     const PetscInt        *suboff, *indices;
887     Vec                    global;
888 
889     /* Get sub-DM global indices for each local dof */
890     PetscCall(DMGetLocalToGlobalMapping(next->dm, &ltog));
891     PetscCall(ISLocalToGlobalMappingGetSize(ltog, &n));
892     PetscCall(ISLocalToGlobalMappingGetIndices(ltog, &indices));
893     PetscCall(PetscMalloc1(n, &idx));
894 
895     /* Get the offsets for the sub-DM global vector */
896     PetscCall(DMGetGlobalVector(next->dm, &global));
897     PetscCall(VecGetOwnershipRanges(global, &suboff));
898     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)global), &size));
899 
900     /* Shift the sub-DM definition of the global space to the composite global space */
901     for (i = 0; i < n; i++) {
902       PetscInt subi = indices[i], lo = 0, hi = size, t;
903       /* There's no consensus on what a negative index means,
904          except for skipping when setting the values in vectors and matrices */
905       if (subi < 0) {
906         idx[i] = subi - next->grstarts[rank];
907         continue;
908       }
909       /* Binary search to find which rank owns subi */
910       while (hi - lo > 1) {
911         t = lo + (hi - lo) / 2;
912         if (suboff[t] > subi) hi = t;
913         else lo = t;
914       }
915       idx[i] = subi - suboff[lo] + next->grstarts[lo];
916     }
917     PetscCall(ISLocalToGlobalMappingRestoreIndices(ltog, &indices));
918     PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), 1, n, idx, PETSC_OWN_POINTER, &(*ltogs)[cnt]));
919     PetscCall(DMRestoreGlobalVector(next->dm, &global));
920     next = next->next;
921     cnt++;
922   }
923   PetscFunctionReturn(PETSC_SUCCESS);
924 }
925 
926 /*@C
927   DMCompositeGetLocalISs - Gets index sets for each component of a composite local vector
928 
929   Not Collective; No Fortran Support
930 
931   Input Parameter:
932 . dm - the `DMCOMPOSITE`
933 
934   Output Parameter:
935 . is - array of serial index sets for each each component of the `DMCOMPOSITE`
936 
937   Level: intermediate
938 
939   Notes:
940   At present, a composite local vector does not normally exist.  This function is used to provide index sets for
941   `MatGetLocalSubMatrix()`.  In the future, the scatters for each entry in the `DMCOMPOSITE` may be be merged into a single
942   scatter to a composite local vector.  The user should not typically need to know which is being done.
943 
944   To get the composite global indices at all local points (including ghosts), use `DMCompositeGetISLocalToGlobalMappings()`.
945 
946   To get index sets for pieces of the composite global vector, use `DMCompositeGetGlobalISs()`.
947 
948   Each returned `IS` should be destroyed with `ISDestroy()`, the array should be freed with `PetscFree()`.
949 
950 .seealso: `DMCOMPOSITE`, `DM`, `DMCompositeGetGlobalISs()`, `DMCompositeGetISLocalToGlobalMappings()`, `MatGetLocalSubMatrix()`, `MatCreateLocalRef()`
951 @*/
952 PetscErrorCode DMCompositeGetLocalISs(DM dm, IS **is)
953 {
954   DM_Composite           *com = (DM_Composite *)dm->data;
955   struct DMCompositeLink *link;
956   PetscInt                cnt, start;
957   PetscBool               flg;
958 
959   PetscFunctionBegin;
960   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
961   PetscAssertPointer(is, 2);
962   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
963   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
964   PetscCall(PetscMalloc1(com->nmine, is));
965   for (cnt = 0, start = 0, link = com->next; link; start += link->nlocal, cnt++, link = link->next) {
966     PetscInt bs;
967     PetscCall(ISCreateStride(PETSC_COMM_SELF, link->nlocal, start, 1, &(*is)[cnt]));
968     PetscCall(DMGetBlockSize(link->dm, &bs));
969     PetscCall(ISSetBlockSize((*is)[cnt], bs));
970   }
971   PetscFunctionReturn(PETSC_SUCCESS);
972 }
973 
974 /*@C
975   DMCompositeGetGlobalISs - Gets the index sets for each composed object in a `DMCOMPOSITE`
976 
977   Collective
978 
979   Input Parameter:
980 . dm - the `DMCOMPOSITE` object
981 
982   Output Parameter:
983 . is - the array of index sets
984 
985   Level: advanced
986 
987   Notes:
988   The is entries should be destroyed with `ISDestroy()`, the is array should be freed with `PetscFree()`
989 
990   These could be used to extract a subset of vector entries for a "multi-physics" preconditioner
991 
992   Use `DMCompositeGetLocalISs()` for index sets in the packed local numbering, and
993   `DMCompositeGetISLocalToGlobalMappings()` for to map local sub-`DM` (including ghost) indices to packed global
994   indices.
995 
996   Fortran Notes:
997   The output argument 'is' must be an allocated array of sufficient length, which can be learned using `DMCompositeGetNumberDM()`.
998 
999 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
1000          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetAccess()`, `DMCompositeScatter()`,
1001          `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`
1002 @*/
1003 PetscErrorCode DMCompositeGetGlobalISs(DM dm, IS *is[])
1004 {
1005   PetscInt                cnt = 0;
1006   struct DMCompositeLink *next;
1007   PetscMPIInt             rank;
1008   DM_Composite           *com = (DM_Composite *)dm->data;
1009   PetscBool               flg;
1010 
1011   PetscFunctionBegin;
1012   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1013   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
1014   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
1015   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Must call DMSetUp() before");
1016   PetscCall(PetscMalloc1(com->nDM, is));
1017   next = com->next;
1018   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1019 
1020   /* loop over packed objects, handling one at at time */
1021   while (next) {
1022     PetscDS prob;
1023 
1024     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)dm), next->n, next->grstart, 1, &(*is)[cnt]));
1025     PetscCall(DMGetDS(dm, &prob));
1026     if (prob) {
1027       MatNullSpace space;
1028       Mat          pmat;
1029       PetscObject  disc;
1030       PetscInt     Nf;
1031 
1032       PetscCall(PetscDSGetNumFields(prob, &Nf));
1033       if (cnt < Nf) {
1034         PetscCall(PetscDSGetDiscretization(prob, cnt, &disc));
1035         PetscCall(PetscObjectQuery(disc, "nullspace", (PetscObject *)&space));
1036         if (space) PetscCall(PetscObjectCompose((PetscObject)(*is)[cnt], "nullspace", (PetscObject)space));
1037         PetscCall(PetscObjectQuery(disc, "nearnullspace", (PetscObject *)&space));
1038         if (space) PetscCall(PetscObjectCompose((PetscObject)(*is)[cnt], "nearnullspace", (PetscObject)space));
1039         PetscCall(PetscObjectQuery(disc, "pmat", (PetscObject *)&pmat));
1040         if (pmat) PetscCall(PetscObjectCompose((PetscObject)(*is)[cnt], "pmat", (PetscObject)pmat));
1041       }
1042     }
1043     cnt++;
1044     next = next->next;
1045   }
1046   PetscFunctionReturn(PETSC_SUCCESS);
1047 }
1048 
1049 static PetscErrorCode DMCreateFieldIS_Composite(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1050 {
1051   PetscInt nDM;
1052   DM      *dms;
1053   PetscInt i;
1054 
1055   PetscFunctionBegin;
1056   PetscCall(DMCompositeGetNumberDM(dm, &nDM));
1057   if (numFields) *numFields = nDM;
1058   PetscCall(DMCompositeGetGlobalISs(dm, fields));
1059   if (fieldNames) {
1060     PetscCall(PetscMalloc1(nDM, &dms));
1061     PetscCall(PetscMalloc1(nDM, fieldNames));
1062     PetscCall(DMCompositeGetEntriesArray(dm, dms));
1063     for (i = 0; i < nDM; i++) {
1064       char        buf[256];
1065       const char *splitname;
1066 
1067       /* Split naming precedence: object name, prefix, number */
1068       splitname = ((PetscObject)dm)->name;
1069       if (!splitname) {
1070         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dms[i], &splitname));
1071         if (splitname) {
1072           size_t len;
1073           PetscCall(PetscStrncpy(buf, splitname, sizeof(buf)));
1074           buf[sizeof(buf) - 1] = 0;
1075           PetscCall(PetscStrlen(buf, &len));
1076           if (buf[len - 1] == '_') buf[len - 1] = 0; /* Remove trailing underscore if it was used */
1077           splitname = buf;
1078         }
1079       }
1080       if (!splitname) {
1081         PetscCall(PetscSNPrintf(buf, sizeof(buf), "%" PetscInt_FMT, i));
1082         splitname = buf;
1083       }
1084       PetscCall(PetscStrallocpy(splitname, &(*fieldNames)[i]));
1085     }
1086     PetscCall(PetscFree(dms));
1087   }
1088   PetscFunctionReturn(PETSC_SUCCESS);
1089 }
1090 
1091 /*
1092  This could take over from DMCreateFieldIS(), as it is more general,
1093  making DMCreateFieldIS() a special case -- calling with dmlist == NULL;
1094  At this point it's probably best to be less intrusive, however.
1095  */
1096 static PetscErrorCode DMCreateFieldDecomposition_Composite(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1097 {
1098   PetscInt nDM;
1099   PetscInt i;
1100 
1101   PetscFunctionBegin;
1102   PetscCall(DMCreateFieldIS_Composite(dm, len, namelist, islist));
1103   if (dmlist) {
1104     PetscCall(DMCompositeGetNumberDM(dm, &nDM));
1105     PetscCall(PetscMalloc1(nDM, dmlist));
1106     PetscCall(DMCompositeGetEntriesArray(dm, *dmlist));
1107     for (i = 0; i < nDM; i++) PetscCall(PetscObjectReference((PetscObject)((*dmlist)[i])));
1108   }
1109   PetscFunctionReturn(PETSC_SUCCESS);
1110 }
1111 
1112 /* -------------------------------------------------------------------------------------*/
1113 /*@C
1114   DMCompositeGetLocalVectors - Gets local vectors for each part of a `DMCOMPOSITE`
1115   Use `DMCompositeRestoreLocalVectors()` to return them.
1116 
1117   Not Collective; No Fortran Support
1118 
1119   Input Parameter:
1120 . dm - the `DMCOMPOSITE` object
1121 
1122   Output Parameter:
1123 . ... - the individual sequential `Vec`s
1124 
1125   Level: advanced
1126 
1127 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
1128          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
1129          `DMCompositeRestoreLocalVectors()`, `DMCompositeScatter()`, `DMCompositeGetEntries()`
1130 @*/
1131 PetscErrorCode DMCompositeGetLocalVectors(DM dm, ...)
1132 {
1133   va_list                 Argp;
1134   struct DMCompositeLink *next;
1135   DM_Composite           *com = (DM_Composite *)dm->data;
1136   PetscBool               flg;
1137 
1138   PetscFunctionBegin;
1139   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1140   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
1141   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
1142   next = com->next;
1143   /* loop over packed objects, handling one at at time */
1144   va_start(Argp, dm);
1145   while (next) {
1146     Vec *vec;
1147     vec = va_arg(Argp, Vec *);
1148     if (vec) PetscCall(DMGetLocalVector(next->dm, vec));
1149     next = next->next;
1150   }
1151   va_end(Argp);
1152   PetscFunctionReturn(PETSC_SUCCESS);
1153 }
1154 
1155 /*@C
1156   DMCompositeRestoreLocalVectors - Restores local vectors for each part of a `DMCOMPOSITE`
1157 
1158   Not Collective; No Fortran Support
1159 
1160   Input Parameter:
1161 . dm - the `DMCOMPOSITE` object
1162 
1163   Output Parameter:
1164 . ... - the individual sequential `Vec`
1165 
1166   Level: advanced
1167 
1168 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`,
1169          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
1170          `DMCompositeGetLocalVectors()`, `DMCompositeScatter()`, `DMCompositeGetEntries()`
1171 @*/
1172 PetscErrorCode DMCompositeRestoreLocalVectors(DM dm, ...)
1173 {
1174   va_list                 Argp;
1175   struct DMCompositeLink *next;
1176   DM_Composite           *com = (DM_Composite *)dm->data;
1177   PetscBool               flg;
1178 
1179   PetscFunctionBegin;
1180   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1181   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
1182   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
1183   next = com->next;
1184   /* loop over packed objects, handling one at at time */
1185   va_start(Argp, dm);
1186   while (next) {
1187     Vec *vec;
1188     vec = va_arg(Argp, Vec *);
1189     if (vec) PetscCall(DMRestoreLocalVector(next->dm, vec));
1190     next = next->next;
1191   }
1192   va_end(Argp);
1193   PetscFunctionReturn(PETSC_SUCCESS);
1194 }
1195 
1196 /* -------------------------------------------------------------------------------------*/
1197 /*@C
1198   DMCompositeGetEntries - Gets the `DM` for each entry in a `DMCOMPOSITE`.
1199 
1200   Not Collective
1201 
1202   Input Parameter:
1203 . dm - the `DMCOMPOSITE` object
1204 
1205   Output Parameter:
1206 . ... - the individual entries `DM`
1207 
1208   Level: advanced
1209 
1210   Fortran Notes:
1211   Available as `DMCompositeGetEntries()` for one output `DM`, DMCompositeGetEntries2() for 2, etc
1212 
1213 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`, `DMCompositeGetEntriesArray()`
1214          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
1215          `DMCompositeRestoreLocalVectors()`, `DMCompositeGetLocalVectors()`, `DMCompositeScatter()`
1216 @*/
1217 PetscErrorCode DMCompositeGetEntries(DM dm, ...)
1218 {
1219   va_list                 Argp;
1220   struct DMCompositeLink *next;
1221   DM_Composite           *com = (DM_Composite *)dm->data;
1222   PetscBool               flg;
1223 
1224   PetscFunctionBegin;
1225   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1226   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
1227   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
1228   next = com->next;
1229   /* loop over packed objects, handling one at at time */
1230   va_start(Argp, dm);
1231   while (next) {
1232     DM *dmn;
1233     dmn = va_arg(Argp, DM *);
1234     if (dmn) *dmn = next->dm;
1235     next = next->next;
1236   }
1237   va_end(Argp);
1238   PetscFunctionReturn(PETSC_SUCCESS);
1239 }
1240 
1241 /*@C
1242   DMCompositeGetEntriesArray - Gets the DM for each entry in a `DMCOMPOSITE`
1243 
1244   Not Collective
1245 
1246   Input Parameter:
1247 . dm - the `DMCOMPOSITE` object
1248 
1249   Output Parameter:
1250 . dms - array of sufficient length (see `DMCompositeGetNumberDM()`) to hold the individual `DM`
1251 
1252   Level: advanced
1253 
1254 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCreateGlobalVector()`, `DMCompositeGetEntries()`
1255          `DMCompositeGather()`, `DMCompositeCreate()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`,
1256          `DMCompositeRestoreLocalVectors()`, `DMCompositeGetLocalVectors()`, `DMCompositeScatter()`
1257 @*/
1258 PetscErrorCode DMCompositeGetEntriesArray(DM dm, DM dms[])
1259 {
1260   struct DMCompositeLink *next;
1261   DM_Composite           *com = (DM_Composite *)dm->data;
1262   PetscInt                i;
1263   PetscBool               flg;
1264 
1265   PetscFunctionBegin;
1266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1267   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMCOMPOSITE, &flg));
1268   PetscCheck(flg, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for type %s", ((PetscObject)dm)->type_name);
1269   /* loop over packed objects, handling one at at time */
1270   for (next = com->next, i = 0; next; next = next->next, i++) dms[i] = next->dm;
1271   PetscFunctionReturn(PETSC_SUCCESS);
1272 }
1273 
1274 typedef struct {
1275   DM           dm;
1276   PetscViewer *subv;
1277   Vec         *vecs;
1278 } GLVisViewerCtx;
1279 
1280 static PetscErrorCode DestroyGLVisViewerCtx_Private(void *vctx)
1281 {
1282   GLVisViewerCtx *ctx = (GLVisViewerCtx *)vctx;
1283   PetscInt        i, n;
1284 
1285   PetscFunctionBegin;
1286   PetscCall(DMCompositeGetNumberDM(ctx->dm, &n));
1287   for (i = 0; i < n; i++) PetscCall(PetscViewerDestroy(&ctx->subv[i]));
1288   PetscCall(PetscFree2(ctx->subv, ctx->vecs));
1289   PetscCall(DMDestroy(&ctx->dm));
1290   PetscCall(PetscFree(ctx));
1291   PetscFunctionReturn(PETSC_SUCCESS);
1292 }
1293 
1294 static PetscErrorCode DMCompositeSampleGLVisFields_Private(PetscObject oX, PetscInt nf, PetscObject oXfield[], void *vctx)
1295 {
1296   Vec             X   = (Vec)oX;
1297   GLVisViewerCtx *ctx = (GLVisViewerCtx *)vctx;
1298   PetscInt        i, n, cumf;
1299 
1300   PetscFunctionBegin;
1301   PetscCall(DMCompositeGetNumberDM(ctx->dm, &n));
1302   PetscCall(DMCompositeGetAccessArray(ctx->dm, X, n, NULL, ctx->vecs));
1303   for (i = 0, cumf = 0; i < n; i++) {
1304     PetscErrorCode (*g2l)(PetscObject, PetscInt, PetscObject[], void *);
1305     void    *fctx;
1306     PetscInt nfi;
1307 
1308     PetscCall(PetscViewerGLVisGetFields_Internal(ctx->subv[i], &nfi, NULL, NULL, &g2l, NULL, &fctx));
1309     if (!nfi) continue;
1310     if (g2l) PetscCall((*g2l)((PetscObject)ctx->vecs[i], nfi, oXfield + cumf, fctx));
1311     else PetscCall(VecCopy(ctx->vecs[i], (Vec)(oXfield[cumf])));
1312     cumf += nfi;
1313   }
1314   PetscCall(DMCompositeRestoreAccessArray(ctx->dm, X, n, NULL, ctx->vecs));
1315   PetscFunctionReturn(PETSC_SUCCESS);
1316 }
1317 
1318 static PetscErrorCode DMSetUpGLVisViewer_Composite(PetscObject odm, PetscViewer viewer)
1319 {
1320   DM              dm = (DM)odm, *dms;
1321   Vec            *Ufds;
1322   GLVisViewerCtx *ctx;
1323   PetscInt        i, n, tnf, *sdim;
1324   char          **fecs;
1325 
1326   PetscFunctionBegin;
1327   PetscCall(PetscNew(&ctx));
1328   PetscCall(PetscObjectReference((PetscObject)dm));
1329   ctx->dm = dm;
1330   PetscCall(DMCompositeGetNumberDM(dm, &n));
1331   PetscCall(PetscMalloc1(n, &dms));
1332   PetscCall(DMCompositeGetEntriesArray(dm, dms));
1333   PetscCall(PetscMalloc2(n, &ctx->subv, n, &ctx->vecs));
1334   for (i = 0, tnf = 0; i < n; i++) {
1335     PetscInt nf;
1336 
1337     PetscCall(PetscViewerCreate(PetscObjectComm(odm), &ctx->subv[i]));
1338     PetscCall(PetscViewerSetType(ctx->subv[i], PETSCVIEWERGLVIS));
1339     PetscCall(PetscViewerGLVisSetDM_Internal(ctx->subv[i], (PetscObject)dms[i]));
1340     PetscCall(PetscViewerGLVisGetFields_Internal(ctx->subv[i], &nf, NULL, NULL, NULL, NULL, NULL));
1341     tnf += nf;
1342   }
1343   PetscCall(PetscFree(dms));
1344   PetscCall(PetscMalloc3(tnf, &fecs, tnf, &sdim, tnf, &Ufds));
1345   for (i = 0, tnf = 0; i < n; i++) {
1346     PetscInt    *sd, nf, f;
1347     const char **fec;
1348     Vec         *Uf;
1349 
1350     PetscCall(PetscViewerGLVisGetFields_Internal(ctx->subv[i], &nf, &fec, &sd, NULL, (PetscObject **)&Uf, NULL));
1351     for (f = 0; f < nf; f++) {
1352       PetscCall(PetscStrallocpy(fec[f], &fecs[tnf + f]));
1353       Ufds[tnf + f] = Uf[f];
1354       sdim[tnf + f] = sd[f];
1355     }
1356     tnf += nf;
1357   }
1358   PetscCall(PetscViewerGLVisSetFields(viewer, tnf, (const char **)fecs, sdim, DMCompositeSampleGLVisFields_Private, (PetscObject *)Ufds, ctx, DestroyGLVisViewerCtx_Private));
1359   for (i = 0; i < tnf; i++) PetscCall(PetscFree(fecs[i]));
1360   PetscCall(PetscFree3(fecs, sdim, Ufds));
1361   PetscFunctionReturn(PETSC_SUCCESS);
1362 }
1363 
1364 static PetscErrorCode DMRefine_Composite(DM dmi, MPI_Comm comm, DM *fine)
1365 {
1366   struct DMCompositeLink *next;
1367   DM_Composite           *com = (DM_Composite *)dmi->data;
1368   DM                      dm;
1369 
1370   PetscFunctionBegin;
1371   PetscValidHeaderSpecific(dmi, DM_CLASSID, 1);
1372   if (comm == MPI_COMM_NULL) PetscCall(PetscObjectGetComm((PetscObject)dmi, &comm));
1373   PetscCall(DMSetUp(dmi));
1374   next = com->next;
1375   PetscCall(DMCompositeCreate(comm, fine));
1376 
1377   /* loop over packed objects, handling one at at time */
1378   while (next) {
1379     PetscCall(DMRefine(next->dm, comm, &dm));
1380     PetscCall(DMCompositeAddDM(*fine, dm));
1381     PetscCall(PetscObjectDereference((PetscObject)dm));
1382     next = next->next;
1383   }
1384   PetscFunctionReturn(PETSC_SUCCESS);
1385 }
1386 
1387 static PetscErrorCode DMCoarsen_Composite(DM dmi, MPI_Comm comm, DM *fine)
1388 {
1389   struct DMCompositeLink *next;
1390   DM_Composite           *com = (DM_Composite *)dmi->data;
1391   DM                      dm;
1392 
1393   PetscFunctionBegin;
1394   PetscValidHeaderSpecific(dmi, DM_CLASSID, 1);
1395   PetscCall(DMSetUp(dmi));
1396   if (comm == MPI_COMM_NULL) PetscCall(PetscObjectGetComm((PetscObject)dmi, &comm));
1397   next = com->next;
1398   PetscCall(DMCompositeCreate(comm, fine));
1399 
1400   /* loop over packed objects, handling one at at time */
1401   while (next) {
1402     PetscCall(DMCoarsen(next->dm, comm, &dm));
1403     PetscCall(DMCompositeAddDM(*fine, dm));
1404     PetscCall(PetscObjectDereference((PetscObject)dm));
1405     next = next->next;
1406   }
1407   PetscFunctionReturn(PETSC_SUCCESS);
1408 }
1409 
1410 static PetscErrorCode DMCreateInterpolation_Composite(DM coarse, DM fine, Mat *A, Vec *v)
1411 {
1412   PetscInt                m, n, M, N, nDM, i;
1413   struct DMCompositeLink *nextc;
1414   struct DMCompositeLink *nextf;
1415   Vec                     gcoarse, gfine, *vecs;
1416   DM_Composite           *comcoarse = (DM_Composite *)coarse->data;
1417   DM_Composite           *comfine   = (DM_Composite *)fine->data;
1418   Mat                    *mats;
1419 
1420   PetscFunctionBegin;
1421   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
1422   PetscValidHeaderSpecific(fine, DM_CLASSID, 2);
1423   PetscCall(DMSetUp(coarse));
1424   PetscCall(DMSetUp(fine));
1425   /* use global vectors only for determining matrix layout */
1426   PetscCall(DMGetGlobalVector(coarse, &gcoarse));
1427   PetscCall(DMGetGlobalVector(fine, &gfine));
1428   PetscCall(VecGetLocalSize(gcoarse, &n));
1429   PetscCall(VecGetLocalSize(gfine, &m));
1430   PetscCall(VecGetSize(gcoarse, &N));
1431   PetscCall(VecGetSize(gfine, &M));
1432   PetscCall(DMRestoreGlobalVector(coarse, &gcoarse));
1433   PetscCall(DMRestoreGlobalVector(fine, &gfine));
1434 
1435   nDM = comfine->nDM;
1436   PetscCheck(nDM == comcoarse->nDM, PetscObjectComm((PetscObject)fine), PETSC_ERR_ARG_INCOMP, "Fine DMComposite has %" PetscInt_FMT " entries, but coarse has %" PetscInt_FMT, nDM, comcoarse->nDM);
1437   PetscCall(PetscCalloc1(nDM * nDM, &mats));
1438   if (v) PetscCall(PetscCalloc1(nDM, &vecs));
1439 
1440   /* loop over packed objects, handling one at at time */
1441   for (nextc = comcoarse->next, nextf = comfine->next, i = 0; nextc; nextc = nextc->next, nextf = nextf->next, i++) {
1442     if (!v) PetscCall(DMCreateInterpolation(nextc->dm, nextf->dm, &mats[i * nDM + i], NULL));
1443     else PetscCall(DMCreateInterpolation(nextc->dm, nextf->dm, &mats[i * nDM + i], &vecs[i]));
1444   }
1445   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)fine), nDM, NULL, nDM, NULL, mats, A));
1446   if (v) PetscCall(VecCreateNest(PetscObjectComm((PetscObject)fine), nDM, NULL, vecs, v));
1447   for (i = 0; i < nDM * nDM; i++) PetscCall(MatDestroy(&mats[i]));
1448   PetscCall(PetscFree(mats));
1449   if (v) {
1450     for (i = 0; i < nDM; i++) PetscCall(VecDestroy(&vecs[i]));
1451     PetscCall(PetscFree(vecs));
1452   }
1453   PetscFunctionReturn(PETSC_SUCCESS);
1454 }
1455 
1456 static PetscErrorCode DMGetLocalToGlobalMapping_Composite(DM dm)
1457 {
1458   DM_Composite           *com = (DM_Composite *)dm->data;
1459   ISLocalToGlobalMapping *ltogs;
1460   PetscInt                i;
1461 
1462   PetscFunctionBegin;
1463   /* Set the ISLocalToGlobalMapping on the new matrix */
1464   PetscCall(DMCompositeGetISLocalToGlobalMappings(dm, &ltogs));
1465   PetscCall(ISLocalToGlobalMappingConcatenate(PetscObjectComm((PetscObject)dm), com->nDM, ltogs, &dm->ltogmap));
1466   for (i = 0; i < com->nDM; i++) PetscCall(ISLocalToGlobalMappingDestroy(&ltogs[i]));
1467   PetscCall(PetscFree(ltogs));
1468   PetscFunctionReturn(PETSC_SUCCESS);
1469 }
1470 
1471 static PetscErrorCode DMCreateColoring_Composite(DM dm, ISColoringType ctype, ISColoring *coloring)
1472 {
1473   PetscInt         n, i, cnt;
1474   ISColoringValue *colors;
1475   PetscBool        dense  = PETSC_FALSE;
1476   ISColoringValue  maxcol = 0;
1477   DM_Composite    *com    = (DM_Composite *)dm->data;
1478 
1479   PetscFunctionBegin;
1480   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1481   PetscCheck(ctype != IS_COLORING_LOCAL, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only global coloring supported");
1482   if (ctype == IS_COLORING_GLOBAL) {
1483     n = com->n;
1484   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Unknown ISColoringType");
1485   PetscCall(PetscMalloc1(n, &colors)); /* freed in ISColoringDestroy() */
1486 
1487   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dmcomposite_dense_jacobian", &dense, NULL));
1488   if (dense) {
1489     for (i = 0; i < n; i++) colors[i] = (ISColoringValue)(com->rstart + i);
1490     maxcol = com->N;
1491   } else {
1492     struct DMCompositeLink *next = com->next;
1493     PetscMPIInt             rank;
1494 
1495     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1496     cnt = 0;
1497     while (next) {
1498       ISColoring lcoloring;
1499 
1500       PetscCall(DMCreateColoring(next->dm, IS_COLORING_GLOBAL, &lcoloring));
1501       for (i = 0; i < lcoloring->N; i++) colors[cnt++] = maxcol + lcoloring->colors[i];
1502       maxcol += lcoloring->n;
1503       PetscCall(ISColoringDestroy(&lcoloring));
1504       next = next->next;
1505     }
1506   }
1507   PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)dm), maxcol, n, colors, PETSC_OWN_POINTER, coloring));
1508   PetscFunctionReturn(PETSC_SUCCESS);
1509 }
1510 
1511 static PetscErrorCode DMGlobalToLocalBegin_Composite(DM dm, Vec gvec, InsertMode mode, Vec lvec)
1512 {
1513   struct DMCompositeLink *next;
1514   PetscScalar            *garray, *larray;
1515   DM_Composite           *com = (DM_Composite *)dm->data;
1516 
1517   PetscFunctionBegin;
1518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1519   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 2);
1520 
1521   if (!com->setup) PetscCall(DMSetUp(dm));
1522 
1523   PetscCall(VecGetArray(gvec, &garray));
1524   PetscCall(VecGetArray(lvec, &larray));
1525 
1526   /* loop over packed objects, handling one at at time */
1527   next = com->next;
1528   while (next) {
1529     Vec      local, global;
1530     PetscInt N;
1531 
1532     PetscCall(DMGetGlobalVector(next->dm, &global));
1533     PetscCall(VecGetLocalSize(global, &N));
1534     PetscCall(VecPlaceArray(global, garray));
1535     PetscCall(DMGetLocalVector(next->dm, &local));
1536     PetscCall(VecPlaceArray(local, larray));
1537     PetscCall(DMGlobalToLocalBegin(next->dm, global, mode, local));
1538     PetscCall(DMGlobalToLocalEnd(next->dm, global, mode, local));
1539     PetscCall(VecResetArray(global));
1540     PetscCall(VecResetArray(local));
1541     PetscCall(DMRestoreGlobalVector(next->dm, &global));
1542     PetscCall(DMRestoreLocalVector(next->dm, &local));
1543 
1544     larray += next->nlocal;
1545     garray += next->n;
1546     next = next->next;
1547   }
1548 
1549   PetscCall(VecRestoreArray(gvec, NULL));
1550   PetscCall(VecRestoreArray(lvec, NULL));
1551   PetscFunctionReturn(PETSC_SUCCESS);
1552 }
1553 
1554 static PetscErrorCode DMGlobalToLocalEnd_Composite(DM dm, Vec gvec, InsertMode mode, Vec lvec)
1555 {
1556   PetscFunctionBegin;
1557   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1558   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 2);
1559   PetscValidHeaderSpecific(lvec, VEC_CLASSID, 4);
1560   PetscFunctionReturn(PETSC_SUCCESS);
1561 }
1562 
1563 static PetscErrorCode DMLocalToGlobalBegin_Composite(DM dm, Vec lvec, InsertMode mode, Vec gvec)
1564 {
1565   struct DMCompositeLink *next;
1566   PetscScalar            *larray, *garray;
1567   DM_Composite           *com = (DM_Composite *)dm->data;
1568 
1569   PetscFunctionBegin;
1570   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1571   PetscValidHeaderSpecific(lvec, VEC_CLASSID, 2);
1572   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 4);
1573 
1574   if (!com->setup) PetscCall(DMSetUp(dm));
1575 
1576   PetscCall(VecGetArray(lvec, &larray));
1577   PetscCall(VecGetArray(gvec, &garray));
1578 
1579   /* loop over packed objects, handling one at at time */
1580   next = com->next;
1581   while (next) {
1582     Vec global, local;
1583 
1584     PetscCall(DMGetLocalVector(next->dm, &local));
1585     PetscCall(VecPlaceArray(local, larray));
1586     PetscCall(DMGetGlobalVector(next->dm, &global));
1587     PetscCall(VecPlaceArray(global, garray));
1588     PetscCall(DMLocalToGlobalBegin(next->dm, local, mode, global));
1589     PetscCall(DMLocalToGlobalEnd(next->dm, local, mode, global));
1590     PetscCall(VecResetArray(local));
1591     PetscCall(VecResetArray(global));
1592     PetscCall(DMRestoreGlobalVector(next->dm, &global));
1593     PetscCall(DMRestoreLocalVector(next->dm, &local));
1594 
1595     garray += next->n;
1596     larray += next->nlocal;
1597     next = next->next;
1598   }
1599 
1600   PetscCall(VecRestoreArray(gvec, NULL));
1601   PetscCall(VecRestoreArray(lvec, NULL));
1602 
1603   PetscFunctionReturn(PETSC_SUCCESS);
1604 }
1605 
1606 static PetscErrorCode DMLocalToGlobalEnd_Composite(DM dm, Vec lvec, InsertMode mode, Vec gvec)
1607 {
1608   PetscFunctionBegin;
1609   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1610   PetscValidHeaderSpecific(lvec, VEC_CLASSID, 2);
1611   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 4);
1612   PetscFunctionReturn(PETSC_SUCCESS);
1613 }
1614 
1615 static PetscErrorCode DMLocalToLocalBegin_Composite(DM dm, Vec vec1, InsertMode mode, Vec vec2)
1616 {
1617   struct DMCompositeLink *next;
1618   PetscScalar            *array1, *array2;
1619   DM_Composite           *com = (DM_Composite *)dm->data;
1620 
1621   PetscFunctionBegin;
1622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1623   PetscValidHeaderSpecific(vec1, VEC_CLASSID, 2);
1624   PetscValidHeaderSpecific(vec2, VEC_CLASSID, 4);
1625 
1626   if (!com->setup) PetscCall(DMSetUp(dm));
1627 
1628   PetscCall(VecGetArray(vec1, &array1));
1629   PetscCall(VecGetArray(vec2, &array2));
1630 
1631   /* loop over packed objects, handling one at at time */
1632   next = com->next;
1633   while (next) {
1634     Vec local1, local2;
1635 
1636     PetscCall(DMGetLocalVector(next->dm, &local1));
1637     PetscCall(VecPlaceArray(local1, array1));
1638     PetscCall(DMGetLocalVector(next->dm, &local2));
1639     PetscCall(VecPlaceArray(local2, array2));
1640     PetscCall(DMLocalToLocalBegin(next->dm, local1, mode, local2));
1641     PetscCall(DMLocalToLocalEnd(next->dm, local1, mode, local2));
1642     PetscCall(VecResetArray(local2));
1643     PetscCall(DMRestoreLocalVector(next->dm, &local2));
1644     PetscCall(VecResetArray(local1));
1645     PetscCall(DMRestoreLocalVector(next->dm, &local1));
1646 
1647     array1 += next->nlocal;
1648     array2 += next->nlocal;
1649     next = next->next;
1650   }
1651 
1652   PetscCall(VecRestoreArray(vec1, NULL));
1653   PetscCall(VecRestoreArray(vec2, NULL));
1654 
1655   PetscFunctionReturn(PETSC_SUCCESS);
1656 }
1657 
1658 static PetscErrorCode DMLocalToLocalEnd_Composite(DM dm, Vec lvec, InsertMode mode, Vec gvec)
1659 {
1660   PetscFunctionBegin;
1661   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1662   PetscValidHeaderSpecific(lvec, VEC_CLASSID, 2);
1663   PetscValidHeaderSpecific(gvec, VEC_CLASSID, 4);
1664   PetscFunctionReturn(PETSC_SUCCESS);
1665 }
1666 
1667 /*MC
1668    DMCOMPOSITE = "composite" - A `DM` object that is used to manage data for a collection of `DM`
1669 
1670   Level: intermediate
1671 
1672 .seealso: `DMType`, `DM`, `DMDACreate()`, `DMCreate()`, `DMSetType()`, `DMCompositeCreate()`
1673 M*/
1674 
1675 PETSC_EXTERN PetscErrorCode DMCreate_Composite(DM p)
1676 {
1677   DM_Composite *com;
1678 
1679   PetscFunctionBegin;
1680   PetscCall(PetscNew(&com));
1681   p->data     = com;
1682   com->n      = 0;
1683   com->nghost = 0;
1684   com->next   = NULL;
1685   com->nDM    = 0;
1686 
1687   p->ops->createglobalvector       = DMCreateGlobalVector_Composite;
1688   p->ops->createlocalvector        = DMCreateLocalVector_Composite;
1689   p->ops->getlocaltoglobalmapping  = DMGetLocalToGlobalMapping_Composite;
1690   p->ops->createfieldis            = DMCreateFieldIS_Composite;
1691   p->ops->createfielddecomposition = DMCreateFieldDecomposition_Composite;
1692   p->ops->refine                   = DMRefine_Composite;
1693   p->ops->coarsen                  = DMCoarsen_Composite;
1694   p->ops->createinterpolation      = DMCreateInterpolation_Composite;
1695   p->ops->creatematrix             = DMCreateMatrix_Composite;
1696   p->ops->getcoloring              = DMCreateColoring_Composite;
1697   p->ops->globaltolocalbegin       = DMGlobalToLocalBegin_Composite;
1698   p->ops->globaltolocalend         = DMGlobalToLocalEnd_Composite;
1699   p->ops->localtoglobalbegin       = DMLocalToGlobalBegin_Composite;
1700   p->ops->localtoglobalend         = DMLocalToGlobalEnd_Composite;
1701   p->ops->localtolocalbegin        = DMLocalToLocalBegin_Composite;
1702   p->ops->localtolocalend          = DMLocalToLocalEnd_Composite;
1703   p->ops->destroy                  = DMDestroy_Composite;
1704   p->ops->view                     = DMView_Composite;
1705   p->ops->setup                    = DMSetUp_Composite;
1706 
1707   PetscCall(PetscObjectComposeFunction((PetscObject)p, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Composite));
1708   PetscFunctionReturn(PETSC_SUCCESS);
1709 }
1710 
1711 /*@
1712   DMCompositeCreate - Creates a `DMCOMPOSITE`, used to generate "composite"
1713   vectors made up of several subvectors.
1714 
1715   Collective
1716 
1717   Input Parameter:
1718 . comm - the processors that will share the global vector
1719 
1720   Output Parameter:
1721 . packer - the `DMCOMPOSITE` object
1722 
1723   Level: advanced
1724 
1725 .seealso: `DMCOMPOSITE`, `DM`, `DMDestroy()`, `DMCompositeAddDM()`, `DMCompositeScatter()`, `DMCreate()`
1726           `DMCompositeGather()`, `DMCreateGlobalVector()`, `DMCompositeGetISLocalToGlobalMappings()`, `DMCompositeGetAccess()`
1727           `DMCompositeGetLocalVectors()`, `DMCompositeRestoreLocalVectors()`, `DMCompositeGetEntries()`
1728 @*/
1729 PetscErrorCode DMCompositeCreate(MPI_Comm comm, DM *packer)
1730 {
1731   PetscFunctionBegin;
1732   PetscAssertPointer(packer, 2);
1733   PetscCall(DMCreate(comm, packer));
1734   PetscCall(DMSetType(*packer, DMCOMPOSITE));
1735   PetscFunctionReturn(PETSC_SUCCESS);
1736 }
1737