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