xref: /petsc/src/dm/label/dmlabel.c (revision dc53bc9b0b05270b2a8c3f2c464d77b884bdfab3)
1c58f1c22SToby Isaac #include <petsc/private/dmlabelimpl.h>   /*I      "petscdmlabel.h"   I*/
2c58f1c22SToby Isaac #include <petsc/private/isimpl.h>        /*I      "petscis.h"        I*/
3c58f1c22SToby Isaac #include <petscsf.h>
4c58f1c22SToby Isaac 
5c58f1c22SToby Isaac #undef __FUNCT__
6c58f1c22SToby Isaac #define __FUNCT__ "DMLabelCreate"
7c58f1c22SToby Isaac /*@C
8c58f1c22SToby Isaac   DMLabelCreate - Create a DMLabel object, which is a multimap
9c58f1c22SToby Isaac 
10c58f1c22SToby Isaac   Input parameter:
11c58f1c22SToby Isaac . name - The label name
12c58f1c22SToby Isaac 
13c58f1c22SToby Isaac   Output parameter:
14c58f1c22SToby Isaac . label - The DMLabel
15c58f1c22SToby Isaac 
16c58f1c22SToby Isaac   Level: beginner
17c58f1c22SToby Isaac 
18c58f1c22SToby Isaac .seealso: DMLabelDestroy()
19c58f1c22SToby Isaac @*/
20c58f1c22SToby Isaac PetscErrorCode DMLabelCreate(const char name[], DMLabel *label)
21c58f1c22SToby Isaac {
22c58f1c22SToby Isaac   PetscErrorCode ierr;
23c58f1c22SToby Isaac 
24c58f1c22SToby Isaac   PetscFunctionBegin;
25c58f1c22SToby Isaac   ierr = PetscNew(label);CHKERRQ(ierr);
26c58f1c22SToby Isaac   ierr = PetscStrallocpy(name, &(*label)->name);CHKERRQ(ierr);
27c58f1c22SToby Isaac 
28c58f1c22SToby Isaac   (*label)->refct          = 1;
29c58f1c22SToby Isaac   (*label)->state          = -1;
30c58f1c22SToby Isaac   (*label)->numStrata      = 0;
315aa44df4SToby Isaac   (*label)->defaultValue   = -1;
32c58f1c22SToby Isaac   (*label)->stratumValues  = NULL;
33c58f1c22SToby Isaac   (*label)->arrayValid     = NULL;
34c58f1c22SToby Isaac   (*label)->stratumSizes   = NULL;
35c58f1c22SToby Isaac   (*label)->points         = NULL;
36c58f1c22SToby Isaac   (*label)->ht             = NULL;
37c58f1c22SToby Isaac   (*label)->pStart         = -1;
38c58f1c22SToby Isaac   (*label)->pEnd           = -1;
39c58f1c22SToby Isaac   (*label)->bt             = NULL;
40c58f1c22SToby Isaac   PetscFunctionReturn(0);
41c58f1c22SToby Isaac }
42c58f1c22SToby Isaac 
43c58f1c22SToby Isaac #undef __FUNCT__
44c58f1c22SToby Isaac #define __FUNCT__ "DMLabelMakeValid_Private"
45c58f1c22SToby Isaac /*
46c58f1c22SToby Isaac   DMLabelMakeValid_Private - Transfer stratum data from the hash format to the sorted list format
47c58f1c22SToby Isaac 
48c58f1c22SToby Isaac   Input parameter:
49c58f1c22SToby Isaac + label - The DMLabel
50c58f1c22SToby Isaac - v - The stratum value
51c58f1c22SToby Isaac 
52c58f1c22SToby Isaac   Output parameter:
53c58f1c22SToby Isaac . label - The DMLabel with stratum in sorted list format
54c58f1c22SToby Isaac 
55c58f1c22SToby Isaac   Level: developer
56c58f1c22SToby Isaac 
57c58f1c22SToby Isaac .seealso: DMLabelCreate()
58c58f1c22SToby Isaac */
59c58f1c22SToby Isaac static PetscErrorCode DMLabelMakeValid_Private(DMLabel label, PetscInt v)
60c58f1c22SToby Isaac {
61c58f1c22SToby Isaac   PetscInt       off;
62c58f1c22SToby Isaac   PetscErrorCode ierr;
63c58f1c22SToby Isaac 
64c58f1c22SToby Isaac   if (label->arrayValid[v]) return 0;
65c58f1c22SToby Isaac   if (v >= label->numStrata) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %D in DMLabelMakeValid_Private\n", v);
66c58f1c22SToby Isaac   PetscFunctionBegin;
67c58f1c22SToby Isaac   PetscHashISize(label->ht[v], label->stratumSizes[v]);
68c58f1c22SToby Isaac 
69c58f1c22SToby Isaac   ierr = PetscMalloc1(label->stratumSizes[v], &label->points[v]);CHKERRQ(ierr);
70c58f1c22SToby Isaac   off = 0;
71c58f1c22SToby Isaac   ierr = PetscHashIGetKeys(label->ht[v], &off, &(label->points[v][0]));CHKERRQ(ierr);
72c58f1c22SToby Isaac   if (off != label->stratumSizes[v]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of contributed points %D from value %D should be %D", off, label->stratumValues[v], label->stratumSizes[v]);
73c58f1c22SToby Isaac   PetscHashIClear(label->ht[v]);
74c58f1c22SToby Isaac   ierr = PetscSortInt(label->stratumSizes[v], label->points[v]);CHKERRQ(ierr);
75c58f1c22SToby Isaac   if (label->bt) {
76c58f1c22SToby Isaac     PetscInt p;
77c58f1c22SToby Isaac 
78c58f1c22SToby Isaac     for (p = 0; p < label->stratumSizes[v]; ++p) {
79c58f1c22SToby Isaac       const PetscInt point = label->points[v][p];
80c58f1c22SToby Isaac 
81c58f1c22SToby Isaac       if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
82c58f1c22SToby Isaac       ierr = PetscBTSet(label->bt, point - label->pStart);CHKERRQ(ierr);
83c58f1c22SToby Isaac     }
84c58f1c22SToby Isaac   }
85c58f1c22SToby Isaac   label->arrayValid[v] = PETSC_TRUE;
86c58f1c22SToby Isaac   ++label->state;
87c58f1c22SToby Isaac   PetscFunctionReturn(0);
88c58f1c22SToby Isaac }
89c58f1c22SToby Isaac 
90c58f1c22SToby Isaac #undef __FUNCT__
91c58f1c22SToby Isaac #define __FUNCT__ "DMLabelMakeAllValid_Private"
92c58f1c22SToby Isaac /*
93c58f1c22SToby Isaac   DMLabelMakeAllValid_Private - Transfer all strata from the hash format to the sorted list format
94c58f1c22SToby Isaac 
95c58f1c22SToby Isaac   Input parameter:
96c58f1c22SToby Isaac . label - The DMLabel
97c58f1c22SToby Isaac 
98c58f1c22SToby Isaac   Output parameter:
99c58f1c22SToby Isaac . label - The DMLabel with all strata in sorted list format
100c58f1c22SToby Isaac 
101c58f1c22SToby Isaac   Level: developer
102c58f1c22SToby Isaac 
103c58f1c22SToby Isaac .seealso: DMLabelCreate()
104c58f1c22SToby Isaac */
105c58f1c22SToby Isaac static PetscErrorCode DMLabelMakeAllValid_Private(DMLabel label)
106c58f1c22SToby Isaac {
107c58f1c22SToby Isaac   PetscInt       v;
108c58f1c22SToby Isaac   PetscErrorCode ierr;
109c58f1c22SToby Isaac 
110c58f1c22SToby Isaac   PetscFunctionBegin;
111c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; v++){
112c58f1c22SToby Isaac     ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
113c58f1c22SToby Isaac   }
114c58f1c22SToby Isaac   PetscFunctionReturn(0);
115c58f1c22SToby Isaac }
116c58f1c22SToby Isaac 
117c58f1c22SToby Isaac #undef __FUNCT__
118c58f1c22SToby Isaac #define __FUNCT__ "DMLabelMakeInvalid_Private"
119c58f1c22SToby Isaac /*
120c58f1c22SToby Isaac   DMLabelMakeInvalid_Private - Transfer stratum data from the sorted list format to the hash format
121c58f1c22SToby Isaac 
122c58f1c22SToby Isaac   Input parameter:
123c58f1c22SToby Isaac + label - The DMLabel
124c58f1c22SToby Isaac - v - The stratum value
125c58f1c22SToby Isaac 
126c58f1c22SToby Isaac   Output parameter:
127c58f1c22SToby Isaac . label - The DMLabel with stratum in hash format
128c58f1c22SToby Isaac 
129c58f1c22SToby Isaac   Level: developer
130c58f1c22SToby Isaac 
131c58f1c22SToby Isaac .seealso: DMLabelCreate()
132c58f1c22SToby Isaac */
133c58f1c22SToby Isaac static PetscErrorCode DMLabelMakeInvalid_Private(DMLabel label, PetscInt v)
134c58f1c22SToby Isaac {
135c58f1c22SToby Isaac   PETSC_UNUSED PetscHashIIter ret, iter;
136c58f1c22SToby Isaac   PetscInt                    p;
137c58f1c22SToby Isaac   PetscErrorCode ierr;
138c58f1c22SToby Isaac 
139c58f1c22SToby Isaac   PetscFunctionBegin;
140c58f1c22SToby Isaac   if (!label->arrayValid[v]) PetscFunctionReturn(0);
141c58f1c22SToby Isaac   for (p = 0; p < label->stratumSizes[v]; ++p) PetscHashIPut(label->ht[v], label->points[v][p], ret, iter);
142c58f1c22SToby Isaac   ierr = PetscFree(label->points[v]);CHKERRQ(ierr);
143c58f1c22SToby Isaac   label->arrayValid[v] = PETSC_FALSE;
144c58f1c22SToby Isaac   PetscFunctionReturn(0);
145c58f1c22SToby Isaac }
146c58f1c22SToby Isaac 
147c58f1c22SToby Isaac #undef __FUNCT__
148c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetState"
149c58f1c22SToby Isaac PetscErrorCode DMLabelGetState(DMLabel label, PetscObjectState *state)
150c58f1c22SToby Isaac {
151c58f1c22SToby Isaac   PetscFunctionBegin;
152c58f1c22SToby Isaac   PetscValidPointer(state, 2);
153c58f1c22SToby Isaac   *state = label->state;
154c58f1c22SToby Isaac   PetscFunctionReturn(0);
155c58f1c22SToby Isaac }
156c58f1c22SToby Isaac 
157c58f1c22SToby Isaac #undef __FUNCT__
158c58f1c22SToby Isaac #define __FUNCT__ "DMLabelAddStratum"
159c58f1c22SToby Isaac PetscErrorCode DMLabelAddStratum(DMLabel label, PetscInt value)
160c58f1c22SToby Isaac {
161c58f1c22SToby Isaac   PetscInt    v, *tmpV, *tmpS, **tmpP;
162c58f1c22SToby Isaac   PetscHashI *tmpH;
163c58f1c22SToby Isaac   PetscBool  *tmpB;
164c58f1c22SToby Isaac   PetscErrorCode ierr;
165c58f1c22SToby Isaac 
166c58f1c22SToby Isaac   PetscFunctionBegin;
167c58f1c22SToby Isaac 
168c58f1c22SToby Isaac   ierr = PetscMalloc1((label->numStrata+1), &tmpV);CHKERRQ(ierr);
169c58f1c22SToby Isaac   ierr = PetscMalloc1((label->numStrata+1), &tmpS);CHKERRQ(ierr);
170c58f1c22SToby Isaac   ierr = PetscMalloc1((label->numStrata+1), &tmpH);CHKERRQ(ierr);
171c58f1c22SToby Isaac   ierr = PetscMalloc1((label->numStrata+1), &tmpP);CHKERRQ(ierr);
172c58f1c22SToby Isaac   ierr = PetscMalloc1((label->numStrata+1), &tmpB);CHKERRQ(ierr);
173c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
174c58f1c22SToby Isaac     tmpV[v] = label->stratumValues[v];
175c58f1c22SToby Isaac     tmpS[v] = label->stratumSizes[v];
176c58f1c22SToby Isaac     tmpH[v] = label->ht[v];
177c58f1c22SToby Isaac     tmpP[v] = label->points[v];
178c58f1c22SToby Isaac     tmpB[v] = label->arrayValid[v];
179c58f1c22SToby Isaac   }
180c58f1c22SToby Isaac   tmpV[v] = value;
181c58f1c22SToby Isaac   tmpS[v] = 0;
182c58f1c22SToby Isaac   PetscHashICreate(tmpH[v]);
183c58f1c22SToby Isaac   tmpP[v] = NULL;
184c58f1c22SToby Isaac   tmpB[v] = PETSC_TRUE;
185c58f1c22SToby Isaac   ++label->numStrata;
186c58f1c22SToby Isaac   ierr = PetscFree(label->stratumValues);CHKERRQ(ierr);
187c58f1c22SToby Isaac   ierr = PetscFree(label->stratumSizes);CHKERRQ(ierr);
188c58f1c22SToby Isaac   ierr = PetscFree(label->ht);CHKERRQ(ierr);
189c58f1c22SToby Isaac   ierr = PetscFree(label->points);CHKERRQ(ierr);
190c58f1c22SToby Isaac   ierr = PetscFree(label->arrayValid);CHKERRQ(ierr);
191c58f1c22SToby Isaac   label->stratumValues = tmpV;
192c58f1c22SToby Isaac   label->stratumSizes  = tmpS;
193c58f1c22SToby Isaac   label->ht            = tmpH;
194c58f1c22SToby Isaac   label->points        = tmpP;
195c58f1c22SToby Isaac   label->arrayValid    = tmpB;
196c58f1c22SToby Isaac 
197c58f1c22SToby Isaac   PetscFunctionReturn(0);
198c58f1c22SToby Isaac }
199c58f1c22SToby Isaac 
200c58f1c22SToby Isaac #undef __FUNCT__
201c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetName"
202c58f1c22SToby Isaac /*@C
203c58f1c22SToby Isaac   DMLabelGetName - Return the name of a DMLabel object
204c58f1c22SToby Isaac 
205c58f1c22SToby Isaac   Input parameter:
206c58f1c22SToby Isaac . label - The DMLabel
207c58f1c22SToby Isaac 
208c58f1c22SToby Isaac   Output parameter:
209c58f1c22SToby Isaac . name - The label name
210c58f1c22SToby Isaac 
211c58f1c22SToby Isaac   Level: beginner
212c58f1c22SToby Isaac 
213c58f1c22SToby Isaac .seealso: DMLabelCreate()
214c58f1c22SToby Isaac @*/
215c58f1c22SToby Isaac PetscErrorCode DMLabelGetName(DMLabel label, const char **name)
216c58f1c22SToby Isaac {
217c58f1c22SToby Isaac   PetscFunctionBegin;
218c58f1c22SToby Isaac   PetscValidPointer(name, 2);
219c58f1c22SToby Isaac   *name = label->name;
220c58f1c22SToby Isaac   PetscFunctionReturn(0);
221c58f1c22SToby Isaac }
222c58f1c22SToby Isaac 
223c58f1c22SToby Isaac #undef __FUNCT__
224c58f1c22SToby Isaac #define __FUNCT__ "DMLabelView_Ascii"
225c58f1c22SToby Isaac static PetscErrorCode DMLabelView_Ascii(DMLabel label, PetscViewer viewer)
226c58f1c22SToby Isaac {
227c58f1c22SToby Isaac   PetscInt       v;
228c58f1c22SToby Isaac   PetscMPIInt    rank;
229c58f1c22SToby Isaac   PetscErrorCode ierr;
230c58f1c22SToby Isaac 
231c58f1c22SToby Isaac   PetscFunctionBegin;
232c58f1c22SToby Isaac   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);CHKERRQ(ierr);
233c58f1c22SToby Isaac   ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
234c58f1c22SToby Isaac   if (label) {
235c58f1c22SToby Isaac     ierr = PetscViewerASCIIPrintf(viewer, "Label '%s':\n", label->name);CHKERRQ(ierr);
236c58f1c22SToby Isaac     if (label->bt) {ierr = PetscViewerASCIIPrintf(viewer, "  Index has been calculated in [%D, %D)\n", label->pStart, label->pEnd);CHKERRQ(ierr);}
237c58f1c22SToby Isaac     for (v = 0; v < label->numStrata; ++v) {
238c58f1c22SToby Isaac       const PetscInt value = label->stratumValues[v];
239c58f1c22SToby Isaac       PetscInt       p;
240c58f1c22SToby Isaac 
241c58f1c22SToby Isaac       for (p = 0; p < label->stratumSizes[v]; ++p) {
242c58f1c22SToby Isaac         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D (%D)\n", rank, label->points[v][p], value);CHKERRQ(ierr);
243c58f1c22SToby Isaac       }
244c58f1c22SToby Isaac     }
245c58f1c22SToby Isaac   }
246c58f1c22SToby Isaac   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
247c58f1c22SToby Isaac   ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
248c58f1c22SToby Isaac   PetscFunctionReturn(0);
249c58f1c22SToby Isaac }
250c58f1c22SToby Isaac 
251c58f1c22SToby Isaac #undef __FUNCT__
252c58f1c22SToby Isaac #define __FUNCT__ "DMLabelView"
253c58f1c22SToby Isaac /*@C
254c58f1c22SToby Isaac   DMLabelView - View the label
255c58f1c22SToby Isaac 
256c58f1c22SToby Isaac   Input Parameters:
257c58f1c22SToby Isaac + label - The DMLabel
258c58f1c22SToby Isaac - viewer - The PetscViewer
259c58f1c22SToby Isaac 
260c58f1c22SToby Isaac   Level: intermediate
261c58f1c22SToby Isaac 
262c58f1c22SToby Isaac .seealso: DMLabelCreate(), DMLabelDestroy()
263c58f1c22SToby Isaac @*/
264c58f1c22SToby Isaac PetscErrorCode DMLabelView(DMLabel label, PetscViewer viewer)
265c58f1c22SToby Isaac {
266c58f1c22SToby Isaac   PetscBool      iascii;
267c58f1c22SToby Isaac   PetscErrorCode ierr;
268c58f1c22SToby Isaac 
269c58f1c22SToby Isaac   PetscFunctionBegin;
270c58f1c22SToby Isaac   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
271c58f1c22SToby Isaac   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
272c58f1c22SToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
273c58f1c22SToby Isaac   if (iascii) {
274c58f1c22SToby Isaac     ierr = DMLabelView_Ascii(label, viewer);CHKERRQ(ierr);
275c58f1c22SToby Isaac   }
276c58f1c22SToby Isaac   PetscFunctionReturn(0);
277c58f1c22SToby Isaac }
278c58f1c22SToby Isaac 
279c58f1c22SToby Isaac #undef __FUNCT__
280c58f1c22SToby Isaac #define __FUNCT__ "DMLabelDestroy"
281c58f1c22SToby Isaac PetscErrorCode DMLabelDestroy(DMLabel *label)
282c58f1c22SToby Isaac {
283c58f1c22SToby Isaac   PetscInt       v;
284c58f1c22SToby Isaac   PetscErrorCode ierr;
285c58f1c22SToby Isaac 
286c58f1c22SToby Isaac   PetscFunctionBegin;
287c58f1c22SToby Isaac   if (!(*label)) PetscFunctionReturn(0);
288c58f1c22SToby Isaac   if (--(*label)->refct > 0) PetscFunctionReturn(0);
289c58f1c22SToby Isaac   ierr = PetscFree((*label)->name);CHKERRQ(ierr);
290c58f1c22SToby Isaac   ierr = PetscFree((*label)->stratumValues);CHKERRQ(ierr);
291c58f1c22SToby Isaac   ierr = PetscFree((*label)->stratumSizes);CHKERRQ(ierr);
292c58f1c22SToby Isaac   for (v = 0; v < (*label)->numStrata; ++v) {ierr = PetscFree((*label)->points[v]);CHKERRQ(ierr);}
293c58f1c22SToby Isaac   ierr = PetscFree((*label)->points);CHKERRQ(ierr);
294c58f1c22SToby Isaac   ierr = PetscFree((*label)->arrayValid);CHKERRQ(ierr);
295c58f1c22SToby Isaac   if ((*label)->ht) {
296c58f1c22SToby Isaac     for (v = 0; v < (*label)->numStrata; ++v) {PetscHashIDestroy((*label)->ht[v]);}
297c58f1c22SToby Isaac     ierr = PetscFree((*label)->ht);CHKERRQ(ierr);
298c58f1c22SToby Isaac   }
299c58f1c22SToby Isaac   ierr = PetscBTDestroy(&(*label)->bt);CHKERRQ(ierr);
300c58f1c22SToby Isaac   ierr = PetscFree(*label);CHKERRQ(ierr);
301c58f1c22SToby Isaac   PetscFunctionReturn(0);
302c58f1c22SToby Isaac }
303c58f1c22SToby Isaac 
304c58f1c22SToby Isaac #undef __FUNCT__
305c58f1c22SToby Isaac #define __FUNCT__ "DMLabelDuplicate"
306c58f1c22SToby Isaac PetscErrorCode DMLabelDuplicate(DMLabel label, DMLabel *labelnew)
307c58f1c22SToby Isaac {
308c58f1c22SToby Isaac   PetscInt       v, q;
309c58f1c22SToby Isaac   PetscErrorCode ierr;
310c58f1c22SToby Isaac 
311c58f1c22SToby Isaac   PetscFunctionBegin;
312c58f1c22SToby Isaac   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
313c58f1c22SToby Isaac   ierr = PetscNew(labelnew);CHKERRQ(ierr);
314c58f1c22SToby Isaac   ierr = PetscStrallocpy(label->name, &(*labelnew)->name);CHKERRQ(ierr);
315c58f1c22SToby Isaac 
316c58f1c22SToby Isaac   (*labelnew)->refct        = 1;
317c58f1c22SToby Isaac   (*labelnew)->numStrata    = label->numStrata;
3185aa44df4SToby Isaac   (*labelnew)->defaultValue = label->defaultValue;
319c58f1c22SToby Isaac   if (label->numStrata) {
320c58f1c22SToby Isaac     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->stratumValues);CHKERRQ(ierr);
321c58f1c22SToby Isaac     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->stratumSizes);CHKERRQ(ierr);
322c58f1c22SToby Isaac     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->ht);CHKERRQ(ierr);
323c58f1c22SToby Isaac     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->points);CHKERRQ(ierr);
324c58f1c22SToby Isaac     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->arrayValid);CHKERRQ(ierr);
325c58f1c22SToby Isaac     /* Could eliminate unused space here */
326c58f1c22SToby Isaac     for (v = 0; v < label->numStrata; ++v) {
327c58f1c22SToby Isaac       ierr = PetscMalloc1(label->stratumSizes[v], &(*labelnew)->points[v]);CHKERRQ(ierr);
328c58f1c22SToby Isaac       PetscHashICreate((*labelnew)->ht[v]);
329c58f1c22SToby Isaac       (*labelnew)->arrayValid[v]     = PETSC_TRUE;
330c58f1c22SToby Isaac       (*labelnew)->stratumValues[v]  = label->stratumValues[v];
331c58f1c22SToby Isaac       (*labelnew)->stratumSizes[v]   = label->stratumSizes[v];
332c58f1c22SToby Isaac       for (q = 0; q < label->stratumSizes[v]; ++q) {
333c58f1c22SToby Isaac         (*labelnew)->points[v][q] = label->points[v][q];
334c58f1c22SToby Isaac       }
335c58f1c22SToby Isaac     }
336c58f1c22SToby Isaac   }
337c58f1c22SToby Isaac   (*labelnew)->pStart = -1;
338c58f1c22SToby Isaac   (*labelnew)->pEnd   = -1;
339c58f1c22SToby Isaac   (*labelnew)->bt     = NULL;
340c58f1c22SToby Isaac   PetscFunctionReturn(0);
341c58f1c22SToby Isaac }
342c58f1c22SToby Isaac 
343c58f1c22SToby Isaac #undef __FUNCT__
344c58f1c22SToby Isaac #define __FUNCT__ "DMLabelCreateIndex"
345c58f1c22SToby Isaac /* This can be hooked into SetValue(),  ClearValue(), etc. for updating */
346c58f1c22SToby Isaac PetscErrorCode DMLabelCreateIndex(DMLabel label, PetscInt pStart, PetscInt pEnd)
347c58f1c22SToby Isaac {
348c58f1c22SToby Isaac   PetscInt       v;
349c58f1c22SToby Isaac   PetscErrorCode ierr;
350c58f1c22SToby Isaac 
351c58f1c22SToby Isaac   PetscFunctionBegin;
352c58f1c22SToby Isaac   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
353c58f1c22SToby Isaac   if (label->bt) {ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);}
354c58f1c22SToby Isaac   label->pStart = pStart;
355c58f1c22SToby Isaac   label->pEnd   = pEnd;
356c58f1c22SToby Isaac   ierr = PetscBTCreate(pEnd - pStart, &label->bt);CHKERRQ(ierr);
357c58f1c22SToby Isaac   ierr = PetscBTMemzero(pEnd - pStart, label->bt);CHKERRQ(ierr);
358c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
359c58f1c22SToby Isaac     PetscInt i;
360c58f1c22SToby Isaac 
361c58f1c22SToby Isaac     for (i = 0; i < label->stratumSizes[v]; ++i) {
362c58f1c22SToby Isaac       const PetscInt point = label->points[v][i];
363c58f1c22SToby Isaac 
364c58f1c22SToby Isaac       if ((point < pStart) || (point >= pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, pStart, pEnd);
365c58f1c22SToby Isaac       ierr = PetscBTSet(label->bt, point - pStart);CHKERRQ(ierr);
366c58f1c22SToby Isaac     }
367c58f1c22SToby Isaac   }
368c58f1c22SToby Isaac   PetscFunctionReturn(0);
369c58f1c22SToby Isaac }
370c58f1c22SToby Isaac 
371c58f1c22SToby Isaac #undef __FUNCT__
372c58f1c22SToby Isaac #define __FUNCT__ "DMLabelDestroyIndex"
373c58f1c22SToby Isaac PetscErrorCode DMLabelDestroyIndex(DMLabel label)
374c58f1c22SToby Isaac {
375c58f1c22SToby Isaac   PetscErrorCode ierr;
376c58f1c22SToby Isaac 
377c58f1c22SToby Isaac   PetscFunctionBegin;
378c58f1c22SToby Isaac   label->pStart = -1;
379c58f1c22SToby Isaac   label->pEnd   = -1;
380c58f1c22SToby Isaac   if (label->bt) {ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);}
381c58f1c22SToby Isaac   PetscFunctionReturn(0);
382c58f1c22SToby Isaac }
383c58f1c22SToby Isaac 
384c58f1c22SToby Isaac #undef __FUNCT__
385c58f1c22SToby Isaac #define __FUNCT__ "DMLabelHasValue"
386c58f1c22SToby Isaac /*@
387c58f1c22SToby Isaac   DMLabelHasValue - Determine whether a label assigns the value to any point
388c58f1c22SToby Isaac 
389c58f1c22SToby Isaac   Input Parameters:
390c58f1c22SToby Isaac + label - the DMLabel
391c58f1c22SToby Isaac - value - the value
392c58f1c22SToby Isaac 
393c58f1c22SToby Isaac   Output Parameter:
394c58f1c22SToby Isaac . contains - Flag indicating whether the label maps this value to any point
395c58f1c22SToby Isaac 
396c58f1c22SToby Isaac   Level: developer
397c58f1c22SToby Isaac 
398c58f1c22SToby Isaac .seealso: DMLabelHasPoint(), DMLabelGetValue(), DMLabelSetValue()
399c58f1c22SToby Isaac @*/
400c58f1c22SToby Isaac PetscErrorCode DMLabelHasValue(DMLabel label, PetscInt value, PetscBool *contains)
401c58f1c22SToby Isaac {
402c58f1c22SToby Isaac   PetscInt v;
403c58f1c22SToby Isaac 
404c58f1c22SToby Isaac   PetscFunctionBegin;
405c58f1c22SToby Isaac   PetscValidPointer(contains, 3);
406c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
407c58f1c22SToby Isaac     if (value == label->stratumValues[v]) break;
408c58f1c22SToby Isaac   }
409c58f1c22SToby Isaac   *contains = (v < label->numStrata ? PETSC_TRUE : PETSC_FALSE);
410c58f1c22SToby Isaac   PetscFunctionReturn(0);
411c58f1c22SToby Isaac }
412c58f1c22SToby Isaac 
413c58f1c22SToby Isaac #undef __FUNCT__
414c58f1c22SToby Isaac #define __FUNCT__ "DMLabelHasPoint"
415c58f1c22SToby Isaac /*@
416c58f1c22SToby Isaac   DMLabelHasPoint - Determine whether a label assigns a value to a point
417c58f1c22SToby Isaac 
418c58f1c22SToby Isaac   Input Parameters:
419c58f1c22SToby Isaac + label - the DMLabel
420c58f1c22SToby Isaac - point - the point
421c58f1c22SToby Isaac 
422c58f1c22SToby Isaac   Output Parameter:
423c58f1c22SToby Isaac . contains - Flag indicating whether the label maps this point to a value
424c58f1c22SToby Isaac 
425c58f1c22SToby Isaac   Note: The user must call DMLabelCreateIndex() before this function.
426c58f1c22SToby Isaac 
427c58f1c22SToby Isaac   Level: developer
428c58f1c22SToby Isaac 
429c58f1c22SToby Isaac .seealso: DMLabelCreateIndex(), DMLabelGetValue(), DMLabelSetValue()
430c58f1c22SToby Isaac @*/
431c58f1c22SToby Isaac PetscErrorCode DMLabelHasPoint(DMLabel label, PetscInt point, PetscBool *contains)
432c58f1c22SToby Isaac {
433c58f1c22SToby Isaac   PetscErrorCode ierr;
434c58f1c22SToby Isaac 
435c58f1c22SToby Isaac   PetscFunctionBeginHot;
436c58f1c22SToby Isaac   PetscValidPointer(contains, 3);
437c58f1c22SToby Isaac   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
438c58f1c22SToby Isaac #if defined(PETSC_USE_DEBUG)
439c58f1c22SToby Isaac   if (!label->bt) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call DMLabelCreateIndex() before DMLabelHasPoint()");
440c58f1c22SToby Isaac   if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
441c58f1c22SToby Isaac #endif
442c58f1c22SToby Isaac   *contains = PetscBTLookup(label->bt, point - label->pStart) ? PETSC_TRUE : PETSC_FALSE;
443c58f1c22SToby Isaac   PetscFunctionReturn(0);
444c58f1c22SToby Isaac }
445c58f1c22SToby Isaac 
446c58f1c22SToby Isaac #undef __FUNCT__
447c58f1c22SToby Isaac #define __FUNCT__ "DMLabelStratumHasPoint"
448c58f1c22SToby Isaac /*@
449c58f1c22SToby Isaac   DMLabelStratumHasPoint - Return true if the stratum contains a point
450c58f1c22SToby Isaac 
451c58f1c22SToby Isaac   Input Parameters:
452c58f1c22SToby Isaac + label - the DMLabel
453c58f1c22SToby Isaac . value - the stratum value
454c58f1c22SToby Isaac - point - the point
455c58f1c22SToby Isaac 
456c58f1c22SToby Isaac   Output Parameter:
457c58f1c22SToby Isaac . contains - true if the stratum contains the point
458c58f1c22SToby Isaac 
459c58f1c22SToby Isaac   Level: intermediate
460c58f1c22SToby Isaac 
461c58f1c22SToby Isaac .seealso: DMLabelCreate(), DMLabelSetValue(), DMLabelClearValue()
462c58f1c22SToby Isaac @*/
463c58f1c22SToby Isaac PetscErrorCode DMLabelStratumHasPoint(DMLabel label, PetscInt value, PetscInt point, PetscBool *contains)
464c58f1c22SToby Isaac {
465c58f1c22SToby Isaac   PetscInt       v;
466c58f1c22SToby Isaac   PetscErrorCode ierr;
467c58f1c22SToby Isaac 
468c58f1c22SToby Isaac   PetscFunctionBegin;
469c58f1c22SToby Isaac   PetscValidPointer(contains, 4);
470c58f1c22SToby Isaac   *contains = PETSC_FALSE;
471c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
472c58f1c22SToby Isaac     if (label->stratumValues[v] == value) {
473c58f1c22SToby Isaac       if (label->arrayValid[v]) {
474c58f1c22SToby Isaac         PetscInt i;
475c58f1c22SToby Isaac 
476c58f1c22SToby Isaac         ierr = PetscFindInt(point, label->stratumSizes[v], &label->points[v][0], &i);CHKERRQ(ierr);
477c58f1c22SToby Isaac         if (i >= 0) {
478c58f1c22SToby Isaac           *contains = PETSC_TRUE;
479c58f1c22SToby Isaac           break;
480c58f1c22SToby Isaac         }
481c58f1c22SToby Isaac       } else {
482c58f1c22SToby Isaac         PetscBool has;
483c58f1c22SToby Isaac 
484c58f1c22SToby Isaac         PetscHashIHasKey(label->ht[v], point, has);
485c58f1c22SToby Isaac         if (has) {
486c58f1c22SToby Isaac           *contains = PETSC_TRUE;
487c58f1c22SToby Isaac           break;
488c58f1c22SToby Isaac         }
489c58f1c22SToby Isaac       }
490c58f1c22SToby Isaac     }
491c58f1c22SToby Isaac   }
492c58f1c22SToby Isaac   PetscFunctionReturn(0);
493c58f1c22SToby Isaac }
494c58f1c22SToby Isaac 
495c58f1c22SToby Isaac #undef __FUNCT__
4965aa44df4SToby Isaac #define __FUNCT__ "DMLabelGetDefaultValue"
4975aa44df4SToby Isaac /*
4985aa44df4SToby Isaac   DMLabelGetDefaultValue - Get the default value returned by DMLabelGetValue() if a point has not been explicitly given a value.
4995aa44df4SToby Isaac   When a label is created, it is initialized to -1.
5005aa44df4SToby Isaac 
5015aa44df4SToby Isaac   Input parameter:
5025aa44df4SToby Isaac . label - a DMLabel object
5035aa44df4SToby Isaac 
5045aa44df4SToby Isaac   Output parameter:
5055aa44df4SToby Isaac . defaultValue - the default value
5065aa44df4SToby Isaac 
5075aa44df4SToby Isaac   Level: beginner
5085aa44df4SToby Isaac 
5095aa44df4SToby Isaac .seealso: DMLabelSetDefaultValue(), DMLabelGetValue(), DMLabelSetValue()
5105aa44df4SToby Isaac */
5115aa44df4SToby Isaac PetscErrorCode DMLabelGetDefaultValue(DMLabel label, PetscInt *defaultValue)
5125aa44df4SToby Isaac {
5135aa44df4SToby Isaac   PetscFunctionBegin;
5145aa44df4SToby Isaac   *defaultValue = label->defaultValue;
5155aa44df4SToby Isaac   PetscFunctionReturn(0);
5165aa44df4SToby Isaac }
5175aa44df4SToby Isaac 
5185aa44df4SToby Isaac #undef __FUNCT__
5195aa44df4SToby Isaac #define __FUNCT__ "DMLabelSetDefaultValue"
5205aa44df4SToby Isaac /*
5215aa44df4SToby Isaac   DMLabelSetDefaultValue - Set the default value returned by DMLabelGetValue() if a point has not been explicitly given a value.
5225aa44df4SToby Isaac   When a label is created, it is initialized to -1.
5235aa44df4SToby Isaac 
5245aa44df4SToby Isaac   Input parameter:
5255aa44df4SToby Isaac . label - a DMLabel object
5265aa44df4SToby Isaac 
5275aa44df4SToby Isaac   Output parameter:
5285aa44df4SToby Isaac . defaultValue - the default value
5295aa44df4SToby Isaac 
5305aa44df4SToby Isaac   Level: beginner
5315aa44df4SToby Isaac 
5325aa44df4SToby Isaac .seealso: DMLabelGetDefaultValue(), DMLabelGetValue(), DMLabelSetValue()
5335aa44df4SToby Isaac */
5345aa44df4SToby Isaac PetscErrorCode DMLabelSetDefaultValue(DMLabel label, PetscInt defaultValue)
5355aa44df4SToby Isaac {
5365aa44df4SToby Isaac   PetscFunctionBegin;
5375aa44df4SToby Isaac   label->defaultValue = defaultValue;
5385aa44df4SToby Isaac   PetscFunctionReturn(0);
5395aa44df4SToby Isaac }
5405aa44df4SToby Isaac 
5415aa44df4SToby Isaac #undef __FUNCT__
542c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetValue"
543c58f1c22SToby Isaac /*@
5445aa44df4SToby Isaac   DMLabelGetValue - Return the value a label assigns to a point, or the label's default value (which is initially -1, and can be changed with DMLabelSetDefaultValue())
545c58f1c22SToby Isaac 
546c58f1c22SToby Isaac   Input Parameters:
547c58f1c22SToby Isaac + label - the DMLabel
548c58f1c22SToby Isaac - point - the point
549c58f1c22SToby Isaac 
550c58f1c22SToby Isaac   Output Parameter:
551c58f1c22SToby Isaac . value - The point value, or -1
552c58f1c22SToby Isaac 
553c58f1c22SToby Isaac   Level: intermediate
554c58f1c22SToby Isaac 
5555aa44df4SToby Isaac .seealso: DMLabelCreate(), DMLabelSetValue(), DMLabelClearValue(), DMLabelGetDefaultValue(), DMLabelSetDefaultValue()
556c58f1c22SToby Isaac @*/
557c58f1c22SToby Isaac PetscErrorCode DMLabelGetValue(DMLabel label, PetscInt point, PetscInt *value)
558c58f1c22SToby Isaac {
559c58f1c22SToby Isaac   PetscInt       v;
560c58f1c22SToby Isaac   PetscErrorCode ierr;
561c58f1c22SToby Isaac 
562c58f1c22SToby Isaac   PetscFunctionBegin;
563c58f1c22SToby Isaac   PetscValidPointer(value, 3);
5645aa44df4SToby Isaac   *value = label->defaultValue;
565c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
566c58f1c22SToby Isaac     if (label->arrayValid[v]) {
567c58f1c22SToby Isaac       PetscInt i;
568c58f1c22SToby Isaac 
569c58f1c22SToby Isaac       ierr = PetscFindInt(point, label->stratumSizes[v], &label->points[v][0], &i);CHKERRQ(ierr);
570c58f1c22SToby Isaac       if (i >= 0) {
571c58f1c22SToby Isaac         *value = label->stratumValues[v];
572c58f1c22SToby Isaac         break;
573c58f1c22SToby Isaac       }
574c58f1c22SToby Isaac     } else {
575c58f1c22SToby Isaac       PetscBool has;
576c58f1c22SToby Isaac 
577c58f1c22SToby Isaac       PetscHashIHasKey(label->ht[v], point, has);
578c58f1c22SToby Isaac       if (has) {
579c58f1c22SToby Isaac         *value = label->stratumValues[v];
580c58f1c22SToby Isaac         break;
581c58f1c22SToby Isaac       }
582c58f1c22SToby Isaac     }
583c58f1c22SToby Isaac   }
584c58f1c22SToby Isaac   PetscFunctionReturn(0);
585c58f1c22SToby Isaac }
586c58f1c22SToby Isaac 
587c58f1c22SToby Isaac #undef __FUNCT__
588c58f1c22SToby Isaac #define __FUNCT__ "DMLabelSetValue"
589c58f1c22SToby Isaac /*@
5905aa44df4SToby Isaac   DMLabelSetValue - Set the value a label assigns to a point.  If the value is the same as the label's default value (which is initially -1, and can be changed with DMLabelSetDefaultValue() to somethingg different), then this function will do nothing.
591c58f1c22SToby Isaac 
592c58f1c22SToby Isaac   Input Parameters:
593c58f1c22SToby Isaac + label - the DMLabel
594c58f1c22SToby Isaac . point - the point
595c58f1c22SToby Isaac - value - The point value
596c58f1c22SToby Isaac 
597c58f1c22SToby Isaac   Level: intermediate
598c58f1c22SToby Isaac 
5995aa44df4SToby Isaac .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelClearValue(), DMLabelGetDefaultValue(), DMLabelSetDefaultValue()
600c58f1c22SToby Isaac @*/
601c58f1c22SToby Isaac PetscErrorCode DMLabelSetValue(DMLabel label, PetscInt point, PetscInt value)
602c58f1c22SToby Isaac {
603c58f1c22SToby Isaac   PETSC_UNUSED PetscHashIIter iter, ret;
604c58f1c22SToby Isaac   PetscInt                    v;
605c58f1c22SToby Isaac   PetscErrorCode              ierr;
606c58f1c22SToby Isaac 
607c58f1c22SToby Isaac   PetscFunctionBegin;
608c58f1c22SToby Isaac   /* Find, or add, label value */
6095aa44df4SToby Isaac   if (value == label->defaultValue) PetscFunctionReturn(0);
610c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
611c58f1c22SToby Isaac     if (label->stratumValues[v] == value) break;
612c58f1c22SToby Isaac   }
613c58f1c22SToby Isaac   /* Create new table */
614c58f1c22SToby Isaac   if (v >= label->numStrata) {ierr = DMLabelAddStratum(label, value);CHKERRQ(ierr);}
615c58f1c22SToby Isaac   ierr = DMLabelMakeInvalid_Private(label, v);CHKERRQ(ierr);
616c58f1c22SToby Isaac   /* Set key */
617c58f1c22SToby Isaac   PetscHashIPut(label->ht[v], point, ret, iter);
618c58f1c22SToby Isaac   PetscFunctionReturn(0);
619c58f1c22SToby Isaac }
620c58f1c22SToby Isaac 
621c58f1c22SToby Isaac #undef __FUNCT__
622c58f1c22SToby Isaac #define __FUNCT__ "DMLabelClearValue"
623c58f1c22SToby Isaac /*@
624c58f1c22SToby Isaac   DMLabelClearValue - Clear the value a label assigns to a point
625c58f1c22SToby Isaac 
626c58f1c22SToby Isaac   Input Parameters:
627c58f1c22SToby Isaac + label - the DMLabel
628c58f1c22SToby Isaac . point - the point
629c58f1c22SToby Isaac - value - The point value
630c58f1c22SToby Isaac 
631c58f1c22SToby Isaac   Level: intermediate
632c58f1c22SToby Isaac 
633c58f1c22SToby Isaac .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue()
634c58f1c22SToby Isaac @*/
635c58f1c22SToby Isaac PetscErrorCode DMLabelClearValue(DMLabel label, PetscInt point, PetscInt value)
636c58f1c22SToby Isaac {
637c58f1c22SToby Isaac   PetscInt       v, p;
638c58f1c22SToby Isaac   PetscErrorCode ierr;
639c58f1c22SToby Isaac 
640c58f1c22SToby Isaac   PetscFunctionBegin;
641c58f1c22SToby Isaac   /* Find label value */
642c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
643c58f1c22SToby Isaac     if (label->stratumValues[v] == value) break;
644c58f1c22SToby Isaac   }
645c58f1c22SToby Isaac   if (v >= label->numStrata) PetscFunctionReturn(0);
646c58f1c22SToby Isaac   if (label->arrayValid[v]) {
647c58f1c22SToby Isaac     /* Check whether point exists */
648c58f1c22SToby Isaac     ierr = PetscFindInt(point, label->stratumSizes[v], &label->points[v][0], &p);CHKERRQ(ierr);
649c58f1c22SToby Isaac     if (p >= 0) {
650c58f1c22SToby Isaac       ierr = PetscMemmove(&label->points[v][p], &label->points[v][p+1], (label->stratumSizes[v]-p-1) * sizeof(PetscInt));CHKERRQ(ierr);
651c58f1c22SToby Isaac       --label->stratumSizes[v];
652c58f1c22SToby Isaac       if (label->bt) {
653c58f1c22SToby Isaac         if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
654c58f1c22SToby Isaac         ierr = PetscBTClear(label->bt, point - label->pStart);CHKERRQ(ierr);
655c58f1c22SToby Isaac       }
656c58f1c22SToby Isaac     }
657c58f1c22SToby Isaac   } else {
658c58f1c22SToby Isaac     ierr = PetscHashIDelKey(label->ht[v], point);CHKERRQ(ierr);
659c58f1c22SToby Isaac   }
660c58f1c22SToby Isaac   PetscFunctionReturn(0);
661c58f1c22SToby Isaac }
662c58f1c22SToby Isaac 
663c58f1c22SToby Isaac #undef __FUNCT__
664c58f1c22SToby Isaac #define __FUNCT__ "DMLabelInsertIS"
665c58f1c22SToby Isaac /*@
666c58f1c22SToby Isaac   DMLabelInsertIS - Set all points in the IS to a value
667c58f1c22SToby Isaac 
668c58f1c22SToby Isaac   Input Parameters:
669c58f1c22SToby Isaac + label - the DMLabel
670c58f1c22SToby Isaac . is    - the point IS
671c58f1c22SToby Isaac - value - The point value
672c58f1c22SToby Isaac 
673c58f1c22SToby Isaac   Level: intermediate
674c58f1c22SToby Isaac 
675c58f1c22SToby Isaac .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
676c58f1c22SToby Isaac @*/
677c58f1c22SToby Isaac PetscErrorCode DMLabelInsertIS(DMLabel label, IS is, PetscInt value)
678c58f1c22SToby Isaac {
679c58f1c22SToby Isaac   const PetscInt *points;
680c58f1c22SToby Isaac   PetscInt        n, p;
681c58f1c22SToby Isaac   PetscErrorCode  ierr;
682c58f1c22SToby Isaac 
683c58f1c22SToby Isaac   PetscFunctionBegin;
684c58f1c22SToby Isaac   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
685c58f1c22SToby Isaac   ierr = ISGetLocalSize(is, &n);CHKERRQ(ierr);
686c58f1c22SToby Isaac   ierr = ISGetIndices(is, &points);CHKERRQ(ierr);
687c58f1c22SToby Isaac   for (p = 0; p < n; ++p) {ierr = DMLabelSetValue(label, points[p], value);CHKERRQ(ierr);}
688c58f1c22SToby Isaac   ierr = ISRestoreIndices(is, &points);CHKERRQ(ierr);
689c58f1c22SToby Isaac   PetscFunctionReturn(0);
690c58f1c22SToby Isaac }
691c58f1c22SToby Isaac 
692c58f1c22SToby Isaac #undef __FUNCT__
693c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetNumValues"
694c58f1c22SToby Isaac PetscErrorCode DMLabelGetNumValues(DMLabel label, PetscInt *numValues)
695c58f1c22SToby Isaac {
696c58f1c22SToby Isaac   PetscFunctionBegin;
697c58f1c22SToby Isaac   PetscValidPointer(numValues, 2);
698c58f1c22SToby Isaac   *numValues = label->numStrata;
699c58f1c22SToby Isaac   PetscFunctionReturn(0);
700c58f1c22SToby Isaac }
701c58f1c22SToby Isaac 
702c58f1c22SToby Isaac #undef __FUNCT__
703c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetValueIS"
704c58f1c22SToby Isaac PetscErrorCode DMLabelGetValueIS(DMLabel label, IS *values)
705c58f1c22SToby Isaac {
706c58f1c22SToby Isaac   PetscErrorCode ierr;
707c58f1c22SToby Isaac 
708c58f1c22SToby Isaac   PetscFunctionBegin;
709c58f1c22SToby Isaac   PetscValidPointer(values, 2);
710c58f1c22SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values);CHKERRQ(ierr);
711c58f1c22SToby Isaac   PetscFunctionReturn(0);
712c58f1c22SToby Isaac }
713c58f1c22SToby Isaac 
714c58f1c22SToby Isaac #undef __FUNCT__
715fada774cSMatthew G. Knepley #define __FUNCT__ "DMLabelHasStratum"
716fada774cSMatthew G. Knepley PetscErrorCode DMLabelHasStratum(DMLabel label, PetscInt value, PetscBool *exists)
717fada774cSMatthew G. Knepley {
718fada774cSMatthew G. Knepley   PetscInt v;
719fada774cSMatthew G. Knepley 
720fada774cSMatthew G. Knepley   PetscFunctionBegin;
721fada774cSMatthew G. Knepley   PetscValidPointer(exists, 3);
722fada774cSMatthew G. Knepley   *exists = PETSC_FALSE;
723fada774cSMatthew G. Knepley   for (v = 0; v < label->numStrata; ++v) {
724fada774cSMatthew G. Knepley     if (label->stratumValues[v] == value) {
725fada774cSMatthew G. Knepley       *exists = PETSC_TRUE;
726fada774cSMatthew G. Knepley       break;
727fada774cSMatthew G. Knepley     }
728fada774cSMatthew G. Knepley   }
729fada774cSMatthew G. Knepley   PetscFunctionReturn(0);
730fada774cSMatthew G. Knepley }
731fada774cSMatthew G. Knepley 
732fada774cSMatthew G. Knepley #undef __FUNCT__
733c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetStratumSize"
734c58f1c22SToby Isaac PetscErrorCode DMLabelGetStratumSize(DMLabel label, PetscInt value, PetscInt *size)
735c58f1c22SToby Isaac {
736c58f1c22SToby Isaac   PetscInt       v;
737c58f1c22SToby Isaac   PetscErrorCode ierr;
738c58f1c22SToby Isaac 
739c58f1c22SToby Isaac   PetscFunctionBegin;
740c58f1c22SToby Isaac   PetscValidPointer(size, 3);
741c58f1c22SToby Isaac   *size = 0;
742c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
743c58f1c22SToby Isaac     if (label->stratumValues[v] == value) {
744c58f1c22SToby Isaac       ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
745c58f1c22SToby Isaac       *size = label->stratumSizes[v];
746c58f1c22SToby Isaac       break;
747c58f1c22SToby Isaac     }
748c58f1c22SToby Isaac   }
749c58f1c22SToby Isaac   PetscFunctionReturn(0);
750c58f1c22SToby Isaac }
751c58f1c22SToby Isaac 
752c58f1c22SToby Isaac #undef __FUNCT__
753c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetStratumBounds"
754c58f1c22SToby Isaac PetscErrorCode DMLabelGetStratumBounds(DMLabel label, PetscInt value, PetscInt *start, PetscInt *end)
755c58f1c22SToby Isaac {
756c58f1c22SToby Isaac   PetscInt       v;
757c58f1c22SToby Isaac   PetscErrorCode ierr;
758c58f1c22SToby Isaac 
759c58f1c22SToby Isaac   PetscFunctionBegin;
760c58f1c22SToby Isaac   if (start) {PetscValidPointer(start, 3); *start = 0;}
761c58f1c22SToby Isaac   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
762c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
763c58f1c22SToby Isaac     if (label->stratumValues[v] != value) continue;
764c58f1c22SToby Isaac     ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
765c58f1c22SToby Isaac     if (label->stratumSizes[v]  <= 0)     break;
766c58f1c22SToby Isaac     if (start) *start = label->points[v][0];
767c58f1c22SToby Isaac     if (end)   *end   = label->points[v][label->stratumSizes[v]-1]+1;
768c58f1c22SToby Isaac     break;
769c58f1c22SToby Isaac   }
770c58f1c22SToby Isaac   PetscFunctionReturn(0);
771c58f1c22SToby Isaac }
772c58f1c22SToby Isaac 
773c58f1c22SToby Isaac #undef __FUNCT__
774c58f1c22SToby Isaac #define __FUNCT__ "DMLabelGetStratumIS"
775c58f1c22SToby Isaac PetscErrorCode DMLabelGetStratumIS(DMLabel label, PetscInt value, IS *points)
776c58f1c22SToby Isaac {
777c58f1c22SToby Isaac   PetscInt       v;
778c58f1c22SToby Isaac   PetscErrorCode ierr;
779c58f1c22SToby Isaac 
780c58f1c22SToby Isaac   PetscFunctionBegin;
781c58f1c22SToby Isaac   PetscValidPointer(points, 3);
782c58f1c22SToby Isaac   *points = NULL;
783c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
784c58f1c22SToby Isaac     if (label->stratumValues[v] == value) {
785c58f1c22SToby Isaac       ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
786c58f1c22SToby Isaac       if (label->arrayValid[v]) {
787c58f1c22SToby Isaac         ierr = ISCreateGeneral(PETSC_COMM_SELF, label->stratumSizes[v], &label->points[v][0], PETSC_COPY_VALUES, points);CHKERRQ(ierr);
788c58f1c22SToby Isaac         ierr = PetscObjectSetName((PetscObject) *points, "indices");CHKERRQ(ierr);
789c58f1c22SToby Isaac       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Need to implement this to speedup Stratify");
790c58f1c22SToby Isaac       break;
791c58f1c22SToby Isaac     }
792c58f1c22SToby Isaac   }
793c58f1c22SToby Isaac   PetscFunctionReturn(0);
794c58f1c22SToby Isaac }
795c58f1c22SToby Isaac 
796c58f1c22SToby Isaac #undef __FUNCT__
797c58f1c22SToby Isaac #define __FUNCT__ "DMLabelClearStratum"
798c58f1c22SToby Isaac PetscErrorCode DMLabelClearStratum(DMLabel label, PetscInt value)
799c58f1c22SToby Isaac {
800c58f1c22SToby Isaac   PetscInt       v;
801c58f1c22SToby Isaac   PetscErrorCode ierr;
802c58f1c22SToby Isaac 
803c58f1c22SToby Isaac   PetscFunctionBegin;
804c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
805c58f1c22SToby Isaac     if (label->stratumValues[v] == value) break;
806c58f1c22SToby Isaac   }
807c58f1c22SToby Isaac   if (v >= label->numStrata) PetscFunctionReturn(0);
808c58f1c22SToby Isaac   if (label->bt) {
809c58f1c22SToby Isaac     PetscInt i;
810c58f1c22SToby Isaac 
811c58f1c22SToby Isaac     for (i = 0; i < label->stratumSizes[v]; ++i) {
812c58f1c22SToby Isaac       const PetscInt point = label->points[v][i];
813c58f1c22SToby Isaac 
814c58f1c22SToby Isaac       if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
815c58f1c22SToby Isaac       ierr = PetscBTClear(label->bt, point - label->pStart);CHKERRQ(ierr);
816c58f1c22SToby Isaac     }
817c58f1c22SToby Isaac   }
818c58f1c22SToby Isaac   if (label->arrayValid[v]) {
819c58f1c22SToby Isaac     label->stratumSizes[v] = 0;
820c58f1c22SToby Isaac   } else {
821c58f1c22SToby Isaac     PetscHashIClear(label->ht[v]);
822c58f1c22SToby Isaac   }
823c58f1c22SToby Isaac   PetscFunctionReturn(0);
824c58f1c22SToby Isaac }
825c58f1c22SToby Isaac 
826c58f1c22SToby Isaac #undef __FUNCT__
827c58f1c22SToby Isaac #define __FUNCT__ "DMLabelFilter"
828c58f1c22SToby Isaac PetscErrorCode DMLabelFilter(DMLabel label, PetscInt start, PetscInt end)
829c58f1c22SToby Isaac {
830c58f1c22SToby Isaac   PetscInt       v;
831c58f1c22SToby Isaac   PetscErrorCode ierr;
832c58f1c22SToby Isaac 
833c58f1c22SToby Isaac   PetscFunctionBegin;
834c58f1c22SToby Isaac   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
835c58f1c22SToby Isaac   label->pStart = start;
836c58f1c22SToby Isaac   label->pEnd   = end;
837c58f1c22SToby Isaac   if (label->bt) {ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);}
838c58f1c22SToby Isaac   /* Could squish offsets, but would only make sense if I reallocate the storage */
839c58f1c22SToby Isaac   for (v = 0; v < label->numStrata; ++v) {
840c58f1c22SToby Isaac     PetscInt off, q;
841c58f1c22SToby Isaac 
842c58f1c22SToby Isaac     for (off = 0, q = 0; q < label->stratumSizes[v]; ++q) {
843c58f1c22SToby Isaac       const PetscInt point = label->points[v][q];
844c58f1c22SToby Isaac 
845c58f1c22SToby Isaac       if ((point < start) || (point >= end)) continue;
846c58f1c22SToby Isaac       label->points[v][off++] = point;
847c58f1c22SToby Isaac     }
848c58f1c22SToby Isaac     label->stratumSizes[v] = off;
849c58f1c22SToby Isaac   }
850c58f1c22SToby Isaac   ierr = DMLabelCreateIndex(label, start, end);CHKERRQ(ierr);
851c58f1c22SToby Isaac   PetscFunctionReturn(0);
852c58f1c22SToby Isaac }
853c58f1c22SToby Isaac 
854c58f1c22SToby Isaac #undef __FUNCT__
855c58f1c22SToby Isaac #define __FUNCT__ "DMLabelPermute"
856c58f1c22SToby Isaac PetscErrorCode DMLabelPermute(DMLabel label, IS permutation, DMLabel *labelNew)
857c58f1c22SToby Isaac {
858c58f1c22SToby Isaac   const PetscInt *perm;
859c58f1c22SToby Isaac   PetscInt        numValues, numPoints, v, q;
860c58f1c22SToby Isaac   PetscErrorCode  ierr;
861c58f1c22SToby Isaac 
862c58f1c22SToby Isaac   PetscFunctionBegin;
863c58f1c22SToby Isaac   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
864c58f1c22SToby Isaac   ierr = DMLabelDuplicate(label, labelNew);CHKERRQ(ierr);
865c58f1c22SToby Isaac   ierr = DMLabelGetNumValues(*labelNew, &numValues);CHKERRQ(ierr);
866c58f1c22SToby Isaac   ierr = ISGetLocalSize(permutation, &numPoints);CHKERRQ(ierr);
867c58f1c22SToby Isaac   ierr = ISGetIndices(permutation, &perm);CHKERRQ(ierr);
868c58f1c22SToby Isaac   for (v = 0; v < numValues; ++v) {
869c58f1c22SToby Isaac     const PetscInt size   = (*labelNew)->stratumSizes[v];
870c58f1c22SToby Isaac 
871c58f1c22SToby Isaac     for (q = 0; q < size; ++q) {
872c58f1c22SToby Isaac       const PetscInt point = (*labelNew)->points[v][q];
873c58f1c22SToby Isaac 
874c58f1c22SToby Isaac       if ((point < 0) || (point >= numPoints)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [0, %D) for the remapping", point, numPoints);
875c58f1c22SToby Isaac       (*labelNew)->points[v][q] = perm[point];
876c58f1c22SToby Isaac     }
877c58f1c22SToby Isaac     ierr = PetscSortInt(size, &(*labelNew)->points[v][0]);CHKERRQ(ierr);
878c58f1c22SToby Isaac   }
879c58f1c22SToby Isaac   ierr = ISRestoreIndices(permutation, &perm);CHKERRQ(ierr);
880c58f1c22SToby Isaac   if (label->bt) {
881c58f1c22SToby Isaac     ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);
882c58f1c22SToby Isaac     ierr = DMLabelCreateIndex(label, label->pStart, label->pEnd);CHKERRQ(ierr);
883c58f1c22SToby Isaac   }
884c58f1c22SToby Isaac   PetscFunctionReturn(0);
885c58f1c22SToby Isaac }
886c58f1c22SToby Isaac 
887c58f1c22SToby Isaac #undef __FUNCT__
88826c55118SMichael Lange #define __FUNCT__ "DMLabelDistribute_Internal"
88926c55118SMichael Lange PetscErrorCode DMLabelDistribute_Internal(DMLabel label, PetscSF sf, PetscSection *leafSection, PetscInt **leafStrata)
89026c55118SMichael Lange {
89126c55118SMichael Lange   MPI_Comm       comm;
89226c55118SMichael Lange   PetscInt       s, l, nroots, nleaves, dof, offset, size;
89326c55118SMichael Lange   PetscInt      *remoteOffsets, *rootStrata, *rootIdx;
89426c55118SMichael Lange   PetscSection   rootSection;
89526c55118SMichael Lange   PetscSF        labelSF;
89626c55118SMichael Lange   PetscErrorCode ierr;
89726c55118SMichael Lange 
89826c55118SMichael Lange   PetscFunctionBegin;
89926c55118SMichael Lange   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
90026c55118SMichael Lange   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
90126c55118SMichael Lange   /* Build a section of stratum values per point, generate the according SF
90226c55118SMichael Lange      and distribute point-wise stratum values to leaves. */
90326c55118SMichael Lange   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL);CHKERRQ(ierr);
90426c55118SMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
90526c55118SMichael Lange   ierr = PetscSectionSetChart(rootSection, 0, nroots);CHKERRQ(ierr);
90626c55118SMichael Lange   if (label) {
90726c55118SMichael Lange     for (s = 0; s < label->numStrata; ++s) {
90826c55118SMichael Lange       for (l = 0; l < label->stratumSizes[s]; l++) {
90926c55118SMichael Lange         ierr = PetscSectionGetDof(rootSection, label->points[s][l], &dof);CHKERRQ(ierr);
91026c55118SMichael Lange         ierr = PetscSectionSetDof(rootSection, label->points[s][l], dof+1);CHKERRQ(ierr);
91126c55118SMichael Lange       }
91226c55118SMichael Lange     }
91326c55118SMichael Lange   }
91426c55118SMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
91526c55118SMichael Lange   /* Create a point-wise array of stratum values */
91626c55118SMichael Lange   ierr = PetscSectionGetStorageSize(rootSection, &size);CHKERRQ(ierr);
91726c55118SMichael Lange   ierr = PetscMalloc1(size, &rootStrata);CHKERRQ(ierr);
91826c55118SMichael Lange   ierr = PetscCalloc1(nroots, &rootIdx);CHKERRQ(ierr);
91926c55118SMichael Lange   if (label) {
92026c55118SMichael Lange     for (s = 0; s < label->numStrata; ++s) {
92126c55118SMichael Lange       for (l = 0; l < label->stratumSizes[s]; l++) {
92226c55118SMichael Lange         const PetscInt p = label->points[s][l];
92326c55118SMichael Lange         ierr = PetscSectionGetOffset(rootSection, p, &offset);CHKERRQ(ierr);
92426c55118SMichael Lange         rootStrata[offset+rootIdx[p]++] = label->stratumValues[s];
92526c55118SMichael Lange       }
92626c55118SMichael Lange     }
92726c55118SMichael Lange   }
92826c55118SMichael Lange   /* Build SF that maps label points to remote processes */
92926c55118SMichael Lange   ierr = PetscSectionCreate(comm, leafSection);CHKERRQ(ierr);
93026c55118SMichael Lange   ierr = PetscSFDistributeSection(sf, rootSection, &remoteOffsets, *leafSection);CHKERRQ(ierr);
93126c55118SMichael Lange   ierr = PetscSFCreateSectionSF(sf, rootSection, remoteOffsets, *leafSection, &labelSF);CHKERRQ(ierr);
93226c55118SMichael Lange   ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
93326c55118SMichael Lange   /* Send the strata for each point over the derived SF */
93426c55118SMichael Lange   ierr = PetscSectionGetStorageSize(*leafSection, &size);CHKERRQ(ierr);
93526c55118SMichael Lange   ierr = PetscMalloc1(size, leafStrata);CHKERRQ(ierr);
93626c55118SMichael Lange   ierr = PetscSFBcastBegin(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
93726c55118SMichael Lange   ierr = PetscSFBcastEnd(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
93826c55118SMichael Lange   /* Clean up */
93926c55118SMichael Lange   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
94026c55118SMichael Lange   ierr = PetscFree(rootIdx);CHKERRQ(ierr);
94126c55118SMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
94226c55118SMichael Lange   ierr = PetscSFDestroy(&labelSF);CHKERRQ(ierr);
94326c55118SMichael Lange   PetscFunctionReturn(0);
94426c55118SMichael Lange }
94526c55118SMichael Lange 
94626c55118SMichael Lange #undef __FUNCT__
947c58f1c22SToby Isaac #define __FUNCT__ "DMLabelDistribute"
948c58f1c22SToby Isaac PetscErrorCode DMLabelDistribute(DMLabel label, PetscSF sf, DMLabel *labelNew)
949c58f1c22SToby Isaac {
950c58f1c22SToby Isaac   MPI_Comm       comm;
95126c55118SMichael Lange   PetscSection   leafSection;
95226c55118SMichael Lange   PetscInt       p, pStart, pEnd, s, size, dof, offset, stratum;
95326c55118SMichael Lange   PetscInt      *leafStrata, *strataIdx;
954c58f1c22SToby Isaac   char          *name;
955c58f1c22SToby Isaac   PetscInt       nameSize;
9565cbdf6fcSMichael Lange   PetscHashI     stratumHash;
9575cbdf6fcSMichael Lange   PETSC_UNUSED   PetscHashIIter ret, iter;
958c58f1c22SToby Isaac   size_t         len = 0;
95926c55118SMichael Lange   PetscMPIInt    rank;
960c58f1c22SToby Isaac   PetscErrorCode ierr;
961c58f1c22SToby Isaac 
962c58f1c22SToby Isaac   PetscFunctionBegin;
963c58f1c22SToby Isaac   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
964c58f1c22SToby Isaac   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
965c58f1c22SToby Isaac   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
966c58f1c22SToby Isaac   /* Bcast name */
967c58f1c22SToby Isaac   if (!rank) {ierr = PetscStrlen(label->name, &len);CHKERRQ(ierr);}
968c58f1c22SToby Isaac   nameSize = len;
969c58f1c22SToby Isaac   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
970c58f1c22SToby Isaac   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
971c58f1c22SToby Isaac   if (!rank) {ierr = PetscMemcpy(name, label->name, nameSize+1);CHKERRQ(ierr);}
972c58f1c22SToby Isaac   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
973c58f1c22SToby Isaac   ierr = DMLabelCreate(name, labelNew);CHKERRQ(ierr);
974c58f1c22SToby Isaac   ierr = PetscFree(name);CHKERRQ(ierr);
97577d236dfSMichael Lange   /* Bcast defaultValue */
97677d236dfSMichael Lange   if (!rank) (*labelNew)->defaultValue = label->defaultValue;
97777d236dfSMichael Lange   ierr = MPI_Bcast(&(*labelNew)->defaultValue, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
97826c55118SMichael Lange   /* Distribute stratum values over the SF and get the point mapping on the receiver */
97926c55118SMichael Lange   ierr = DMLabelDistribute_Internal(label, sf, &leafSection, &leafStrata);CHKERRQ(ierr);
9805cbdf6fcSMichael Lange   /* Determine received stratum values and initialise new label*/
9815cbdf6fcSMichael Lange   PetscHashICreate(stratumHash);
98226c55118SMichael Lange   ierr = PetscSectionGetStorageSize(leafSection, &size);CHKERRQ(ierr);
9835cbdf6fcSMichael Lange   for (p = 0; p < size; ++p) PetscHashIPut(stratumHash, leafStrata[p], ret, iter);
9845cbdf6fcSMichael Lange   PetscHashISize(stratumHash, (*labelNew)->numStrata);
9855cbdf6fcSMichael Lange   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->arrayValid);CHKERRQ(ierr);
9865cbdf6fcSMichael Lange   for (s = 0; s < (*labelNew)->numStrata; ++s) (*labelNew)->arrayValid[s] = PETSC_TRUE;
9875cbdf6fcSMichael Lange   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->stratumValues);CHKERRQ(ierr);
9885cbdf6fcSMichael Lange   /* Turn leafStrata into indices rather than stratum values */
9895cbdf6fcSMichael Lange   offset = 0;
9905cbdf6fcSMichael Lange   ierr = PetscHashIGetKeys(stratumHash, &offset, (*labelNew)->stratumValues);CHKERRQ(ierr);
9915cbdf6fcSMichael Lange   for (p = 0; p < size; ++p) {
992231b9e6fSMatthew G. Knepley     for (s = 0; s < (*labelNew)->numStrata; ++s) {
993231b9e6fSMatthew G. Knepley       if (leafStrata[p] == (*labelNew)->stratumValues[s]) {leafStrata[p] = s; break;}
9945cbdf6fcSMichael Lange     }
9955cbdf6fcSMichael Lange   }
996c58f1c22SToby Isaac   /* Rebuild the point strata on the receiver */
997c58f1c22SToby Isaac   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->stratumSizes);CHKERRQ(ierr);
998c58f1c22SToby Isaac   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
999c58f1c22SToby Isaac   for (p=pStart; p<pEnd; p++) {
1000c58f1c22SToby Isaac     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1001c58f1c22SToby Isaac     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1002c58f1c22SToby Isaac     for (s=0; s<dof; s++) {
1003c58f1c22SToby Isaac       (*labelNew)->stratumSizes[leafStrata[offset+s]]++;
1004c58f1c22SToby Isaac     }
1005c58f1c22SToby Isaac   }
1006c58f1c22SToby Isaac   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->ht);CHKERRQ(ierr);
1007c58f1c22SToby Isaac   ierr = PetscMalloc1((*labelNew)->numStrata,&(*labelNew)->points);CHKERRQ(ierr);
1008c58f1c22SToby Isaac   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1009c58f1c22SToby Isaac     PetscHashICreate((*labelNew)->ht[s]);
1010c58f1c22SToby Isaac     ierr = PetscMalloc1((*labelNew)->stratumSizes[s], &(*labelNew)->points[s]);CHKERRQ(ierr);
1011c58f1c22SToby Isaac   }
1012c58f1c22SToby Isaac   /* Insert points into new strata */
1013c58f1c22SToby Isaac   ierr = PetscCalloc1((*labelNew)->numStrata, &strataIdx);CHKERRQ(ierr);
1014c58f1c22SToby Isaac   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
1015c58f1c22SToby Isaac   for (p=pStart; p<pEnd; p++) {
1016c58f1c22SToby Isaac     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1017c58f1c22SToby Isaac     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1018c58f1c22SToby Isaac     for (s=0; s<dof; s++) {
1019c58f1c22SToby Isaac       stratum = leafStrata[offset+s];
1020c58f1c22SToby Isaac       (*labelNew)->points[stratum][strataIdx[stratum]++] = p;
1021c58f1c22SToby Isaac     }
1022c58f1c22SToby Isaac   }
10235cbdf6fcSMichael Lange   PetscHashIDestroy(stratumHash);
1024c58f1c22SToby Isaac   ierr = PetscFree(leafStrata);CHKERRQ(ierr);
1025c58f1c22SToby Isaac   ierr = PetscFree(strataIdx);CHKERRQ(ierr);
1026c58f1c22SToby Isaac   ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
1027c58f1c22SToby Isaac   PetscFunctionReturn(0);
1028c58f1c22SToby Isaac }
1029c58f1c22SToby Isaac 
1030c58f1c22SToby Isaac #undef __FUNCT__
10317937d9ceSMichael Lange #define __FUNCT__ "DMLabelGather"
10327937d9ceSMichael Lange /*@
10337937d9ceSMichael Lange   DMLabelGather - Gather all label values from leafs into roots
10347937d9ceSMichael Lange 
10357937d9ceSMichael Lange   Input Parameters:
10367937d9ceSMichael Lange + label - the DMLabel
10377937d9ceSMichael Lange . point - the Star Forest point communication map
10387937d9ceSMichael Lange 
10397937d9ceSMichael Lange   Input Parameters:
10407937d9ceSMichael Lange + label - the new DMLabel with localised leaf values
10417937d9ceSMichael Lange 
10427937d9ceSMichael Lange   Level: developer
10437937d9ceSMichael Lange 
10447937d9ceSMichael Lange   Note: This is the inverse operation to DMLabelDistribute.
10457937d9ceSMichael Lange 
10467937d9ceSMichael Lange .seealso: DMLabelDistribute()
10477937d9ceSMichael Lange @*/
10487937d9ceSMichael Lange PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew)
10497937d9ceSMichael Lange {
10507937d9ceSMichael Lange   MPI_Comm       comm;
10517937d9ceSMichael Lange   PetscSection   rootSection;
10527937d9ceSMichael Lange   PetscSF        sfLabel;
10537937d9ceSMichael Lange   PetscSFNode   *rootPoints, *leafPoints;
10547937d9ceSMichael Lange   PetscInt       p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset;
10557937d9ceSMichael Lange   const PetscInt *rootDegree, *ilocal;
10567937d9ceSMichael Lange   PetscInt       *rootStrata;
10577937d9ceSMichael Lange   char          *name;
10587937d9ceSMichael Lange   PetscInt       nameSize;
10597937d9ceSMichael Lange   size_t         len = 0;
10607937d9ceSMichael Lange   PetscMPIInt    rank, numProcs;
10617937d9ceSMichael Lange   PetscErrorCode ierr;
10627937d9ceSMichael Lange 
10637937d9ceSMichael Lange   PetscFunctionBegin;
10647937d9ceSMichael Lange   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
10657937d9ceSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
10667937d9ceSMichael Lange   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
10677937d9ceSMichael Lange   /* Bcast name */
10687937d9ceSMichael Lange   if (!rank) {ierr = PetscStrlen(label->name, &len);CHKERRQ(ierr);}
10697937d9ceSMichael Lange   nameSize = len;
10707937d9ceSMichael Lange   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
10717937d9ceSMichael Lange   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
10727937d9ceSMichael Lange   if (!rank) {ierr = PetscMemcpy(name, label->name, nameSize+1);CHKERRQ(ierr);}
10737937d9ceSMichael Lange   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
10747937d9ceSMichael Lange   ierr = DMLabelCreate(name, labelNew);CHKERRQ(ierr);
10757937d9ceSMichael Lange   ierr = PetscFree(name);CHKERRQ(ierr);
10767937d9ceSMichael Lange   /* Gather rank/index pairs of leaves into local roots to build
10777937d9ceSMichael Lange      an inverse, multi-rooted SF. Note that this ignores local leaf
10787937d9ceSMichael Lange      indexing due to the use of the multiSF in PetscSFGather. */
10797937d9ceSMichael Lange   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL);CHKERRQ(ierr);
1080*dc53bc9bSMatthew G. Knepley   ierr = PetscMalloc1(nroots, &leafPoints);CHKERRQ(ierr);
1081*dc53bc9bSMatthew G. Knepley   for (p = 0; p < nroots; ++p) leafPoints[p].rank = leafPoints[p].index = -1;
10827937d9ceSMichael Lange   for (p = 0; p < nleaves; p++) {
1083*dc53bc9bSMatthew G. Knepley     leafPoints[ilocal[p]].index = ilocal[p];
1084*dc53bc9bSMatthew G. Knepley     leafPoints[ilocal[p]].rank  = rank;
10857937d9ceSMichael Lange   }
10867937d9ceSMichael Lange   ierr = PetscSFComputeDegreeBegin(sf, &rootDegree);CHKERRQ(ierr);
10877937d9ceSMichael Lange   ierr = PetscSFComputeDegreeEnd(sf, &rootDegree);CHKERRQ(ierr);
10887937d9ceSMichael Lange   for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p];
10897937d9ceSMichael Lange   ierr = PetscMalloc1(nmultiroots, &rootPoints);CHKERRQ(ierr);
10907937d9ceSMichael Lange   ierr = PetscSFGatherBegin(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
10917937d9ceSMichael Lange   ierr = PetscSFGatherEnd(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
10927937d9ceSMichael Lange   ierr = PetscSFCreate(comm,& sfLabel);CHKERRQ(ierr);
10937937d9ceSMichael Lange   ierr = PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
10947937d9ceSMichael Lange   /* Migrate label over inverted SF to pull stratum values at leaves into roots. */
10957937d9ceSMichael Lange   ierr = DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata);CHKERRQ(ierr);
10967937d9ceSMichael Lange   /* Rebuild the point strata on the receiver */
10977937d9ceSMichael Lange   for (p = 0, idx = 0; p < nroots; p++) {
10987937d9ceSMichael Lange     for (d = 0; d < rootDegree[p]; d++) {
10997937d9ceSMichael Lange       ierr = PetscSectionGetDof(rootSection, idx+d, &dof);CHKERRQ(ierr);
11007937d9ceSMichael Lange       ierr = PetscSectionGetOffset(rootSection, idx+d, &offset);CHKERRQ(ierr);
11017937d9ceSMichael Lange       for (s = 0; s < dof; s++) {ierr = DMLabelSetValue(*labelNew, p, rootStrata[offset+s]);CHKERRQ(ierr);}
11027937d9ceSMichael Lange     }
11037937d9ceSMichael Lange     idx += rootDegree[p];
11047937d9ceSMichael Lange   }
110577e0c0e7SMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
110677e0c0e7SMichael Lange   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
110777e0c0e7SMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
110877e0c0e7SMichael Lange   ierr = PetscSFDestroy(&sfLabel);CHKERRQ(ierr);
11097937d9ceSMichael Lange   PetscFunctionReturn(0);
11107937d9ceSMichael Lange }
11117937d9ceSMichael Lange 
11127937d9ceSMichael Lange #undef __FUNCT__
1113c58f1c22SToby Isaac #define __FUNCT__ "DMLabelConvertToSection"
1114c58f1c22SToby Isaac PetscErrorCode DMLabelConvertToSection(DMLabel label, PetscSection *section, IS *is)
1115c58f1c22SToby Isaac {
1116c58f1c22SToby Isaac   IS              vIS;
1117c58f1c22SToby Isaac   const PetscInt *values;
1118c58f1c22SToby Isaac   PetscInt       *points;
1119c58f1c22SToby Isaac   PetscInt        nV, vS = 0, vE = 0, v, N;
1120c58f1c22SToby Isaac   PetscErrorCode  ierr;
1121c58f1c22SToby Isaac 
1122c58f1c22SToby Isaac   PetscFunctionBegin;
1123c58f1c22SToby Isaac   ierr = DMLabelGetNumValues(label, &nV);CHKERRQ(ierr);
1124c58f1c22SToby Isaac   ierr = DMLabelGetValueIS(label, &vIS);CHKERRQ(ierr);
1125c58f1c22SToby Isaac   ierr = ISGetIndices(vIS, &values);CHKERRQ(ierr);
1126c58f1c22SToby Isaac   if (nV) {vS = values[0]; vE = values[0]+1;}
1127c58f1c22SToby Isaac   for (v = 1; v < nV; ++v) {
1128c58f1c22SToby Isaac     vS = PetscMin(vS, values[v]);
1129c58f1c22SToby Isaac     vE = PetscMax(vE, values[v]+1);
1130c58f1c22SToby Isaac   }
1131c58f1c22SToby Isaac   ierr = PetscSectionCreate(PETSC_COMM_SELF, section);CHKERRQ(ierr);
1132c58f1c22SToby Isaac   ierr = PetscSectionSetChart(*section, vS, vE);CHKERRQ(ierr);
1133c58f1c22SToby Isaac   for (v = 0; v < nV; ++v) {
1134c58f1c22SToby Isaac     PetscInt n;
1135c58f1c22SToby Isaac 
1136c58f1c22SToby Isaac     ierr = DMLabelGetStratumSize(label, values[v], &n);CHKERRQ(ierr);
1137c58f1c22SToby Isaac     ierr = PetscSectionSetDof(*section, values[v], n);CHKERRQ(ierr);
1138c58f1c22SToby Isaac   }
1139c58f1c22SToby Isaac   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
1140c58f1c22SToby Isaac   ierr = PetscSectionGetStorageSize(*section, &N);CHKERRQ(ierr);
1141c58f1c22SToby Isaac   ierr = PetscMalloc1(N, &points);CHKERRQ(ierr);
1142c58f1c22SToby Isaac   for (v = 0; v < nV; ++v) {
1143c58f1c22SToby Isaac     IS              is;
1144c58f1c22SToby Isaac     const PetscInt *spoints;
1145c58f1c22SToby Isaac     PetscInt        dof, off, p;
1146c58f1c22SToby Isaac 
1147c58f1c22SToby Isaac     ierr = PetscSectionGetDof(*section, values[v], &dof);CHKERRQ(ierr);
1148c58f1c22SToby Isaac     ierr = PetscSectionGetOffset(*section, values[v], &off);CHKERRQ(ierr);
1149c58f1c22SToby Isaac     ierr = DMLabelGetStratumIS(label, values[v], &is);CHKERRQ(ierr);
1150c58f1c22SToby Isaac     ierr = ISGetIndices(is, &spoints);CHKERRQ(ierr);
1151c58f1c22SToby Isaac     for (p = 0; p < dof; ++p) points[off+p] = spoints[p];
1152c58f1c22SToby Isaac     ierr = ISRestoreIndices(is, &spoints);CHKERRQ(ierr);
1153c58f1c22SToby Isaac     ierr = ISDestroy(&is);CHKERRQ(ierr);
1154c58f1c22SToby Isaac   }
1155c58f1c22SToby Isaac   ierr = ISRestoreIndices(vIS, &values);CHKERRQ(ierr);
1156c58f1c22SToby Isaac   ierr = ISDestroy(&vIS);CHKERRQ(ierr);
1157c58f1c22SToby Isaac   ierr = ISCreateGeneral(PETSC_COMM_SELF, N, points, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
1158c58f1c22SToby Isaac   PetscFunctionReturn(0);
1159c58f1c22SToby Isaac }
1160c58f1c22SToby Isaac 
1161c58f1c22SToby Isaac #undef __FUNCT__
1162c58f1c22SToby Isaac #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
1163c58f1c22SToby Isaac /*@C
1164c58f1c22SToby Isaac   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
1165c58f1c22SToby Isaac   the local section and an SF describing the section point overlap.
1166c58f1c22SToby Isaac 
1167c58f1c22SToby Isaac   Input Parameters:
1168c58f1c22SToby Isaac   + s - The PetscSection for the local field layout
1169c58f1c22SToby Isaac   . sf - The SF describing parallel layout of the section points
1170c58f1c22SToby Isaac   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
1171c58f1c22SToby Isaac   . label - The label specifying the points
1172c58f1c22SToby Isaac   - labelValue - The label stratum specifying the points
1173c58f1c22SToby Isaac 
1174c58f1c22SToby Isaac   Output Parameter:
1175c58f1c22SToby Isaac   . gsection - The PetscSection for the global field layout
1176c58f1c22SToby Isaac 
1177c58f1c22SToby Isaac   Note: This gives negative sizes and offsets to points not owned by this process
1178c58f1c22SToby Isaac 
1179c58f1c22SToby Isaac   Level: developer
1180c58f1c22SToby Isaac 
1181c58f1c22SToby Isaac .seealso: PetscSectionCreate()
1182c58f1c22SToby Isaac @*/
1183c58f1c22SToby Isaac PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
1184c58f1c22SToby Isaac {
1185c58f1c22SToby Isaac   PetscInt      *neg = NULL, *tmpOff = NULL;
1186c58f1c22SToby Isaac   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
1187c58f1c22SToby Isaac   PetscErrorCode ierr;
1188c58f1c22SToby Isaac 
1189c58f1c22SToby Isaac   PetscFunctionBegin;
1190c58f1c22SToby Isaac   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
1191c58f1c22SToby Isaac   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
1192c58f1c22SToby Isaac   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
1193c58f1c22SToby Isaac   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
1194c58f1c22SToby Isaac   if (nroots >= 0) {
1195c58f1c22SToby Isaac     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
1196c58f1c22SToby Isaac     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
1197c58f1c22SToby Isaac     if (nroots > pEnd-pStart) {
1198c58f1c22SToby Isaac       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
1199c58f1c22SToby Isaac     } else {
1200c58f1c22SToby Isaac       tmpOff = &(*gsection)->atlasDof[-pStart];
1201c58f1c22SToby Isaac     }
1202c58f1c22SToby Isaac   }
1203c58f1c22SToby Isaac   /* Mark ghost points with negative dof */
1204c58f1c22SToby Isaac   for (p = pStart; p < pEnd; ++p) {
1205c58f1c22SToby Isaac     PetscInt value;
1206c58f1c22SToby Isaac 
1207c58f1c22SToby Isaac     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
1208c58f1c22SToby Isaac     if (value != labelValue) continue;
1209c58f1c22SToby Isaac     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
1210c58f1c22SToby Isaac     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
1211c58f1c22SToby Isaac     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
1212c58f1c22SToby Isaac     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
1213c58f1c22SToby Isaac     if (neg) neg[p] = -(dof+1);
1214c58f1c22SToby Isaac   }
1215c58f1c22SToby Isaac   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
1216c58f1c22SToby Isaac   if (nroots >= 0) {
1217c58f1c22SToby Isaac     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1218c58f1c22SToby Isaac     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1219c58f1c22SToby Isaac     if (nroots > pEnd-pStart) {
1220c58f1c22SToby Isaac       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
1221c58f1c22SToby Isaac     }
1222c58f1c22SToby Isaac   }
1223c58f1c22SToby Isaac   /* Calculate new sizes, get proccess offset, and calculate point offsets */
1224c58f1c22SToby Isaac   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1225c58f1c22SToby Isaac     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
1226c58f1c22SToby Isaac     (*gsection)->atlasOff[p] = off;
1227c58f1c22SToby Isaac     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
1228c58f1c22SToby Isaac   }
1229c58f1c22SToby Isaac   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
1230c58f1c22SToby Isaac   globalOff -= off;
1231c58f1c22SToby Isaac   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1232c58f1c22SToby Isaac     (*gsection)->atlasOff[p] += globalOff;
1233c58f1c22SToby Isaac     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
1234c58f1c22SToby Isaac   }
1235c58f1c22SToby Isaac   /* Put in negative offsets for ghost points */
1236c58f1c22SToby Isaac   if (nroots >= 0) {
1237c58f1c22SToby Isaac     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1238c58f1c22SToby Isaac     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1239c58f1c22SToby Isaac     if (nroots > pEnd-pStart) {
1240c58f1c22SToby Isaac       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
1241c58f1c22SToby Isaac     }
1242c58f1c22SToby Isaac   }
1243c58f1c22SToby Isaac   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
1244c58f1c22SToby Isaac   ierr = PetscFree(neg);CHKERRQ(ierr);
1245c58f1c22SToby Isaac   PetscFunctionReturn(0);
1246c58f1c22SToby Isaac }
1247c58f1c22SToby Isaac 
1248