1 /*
2 Defines the abstract operations on index sets, i.e. the public interface.
3 */
4 #include <petsc/private/isimpl.h> /*I "petscis.h" I*/
5 #include <petscviewer.h>
6 #include <petscsf.h>
7
8 /* Logging support */
9 PetscClassId IS_CLASSID;
10 /* TODO: Much more events are missing! */
11 PetscLogEvent IS_View;
12 PetscLogEvent IS_Load;
13
14 /*@
15 ISRenumber - Renumbers the non-negative entries of an index set in a contiguous way, starting from 0.
16
17 Collective
18
19 Input Parameters:
20 + subset - the index set
21 - subset_mult - the multiplicity of each entry in subset (optional, can be `NULL`)
22
23 Output Parameters:
24 + N - one past the largest entry of the new `IS`
25 - subset_n - the new `IS`
26
27 Level: intermediate
28
29 Note:
30 All negative entries are mapped to -1. Indices with non positive multiplicities are skipped.
31
32 .seealso: `IS`
33 @*/
ISRenumber(IS subset,IS subset_mult,PetscInt * N,IS * subset_n)34 PetscErrorCode ISRenumber(IS subset, IS subset_mult, PetscInt *N, IS *subset_n)
35 {
36 PetscSF sf;
37 PetscLayout map;
38 const PetscInt *idxs, *idxs_mult = NULL;
39 PetscInt *leaf_data, *root_data, *gidxs, *ilocal, *ilocalneg;
40 PetscInt N_n, n, i, lbounds[2], gbounds[2], Nl, ibs;
41 PetscInt n_n, nlocals, start, first_index, npos, nneg;
42 PetscMPIInt commsize;
43 PetscBool first_found, isblock;
44
45 PetscFunctionBegin;
46 PetscValidHeaderSpecific(subset, IS_CLASSID, 1);
47 if (subset_mult) PetscValidHeaderSpecific(subset_mult, IS_CLASSID, 2);
48 if (N) PetscAssertPointer(N, 3);
49 else if (!subset_n) PetscFunctionReturn(PETSC_SUCCESS);
50 PetscCall(ISGetLocalSize(subset, &n));
51 if (subset_mult) {
52 PetscCall(ISGetLocalSize(subset_mult, &i));
53 PetscCheck(i == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local subset and multiplicity sizes don't match! %" PetscInt_FMT " != %" PetscInt_FMT, n, i);
54 }
55 /* create workspace layout for computing global indices of subset */
56 PetscCall(PetscMalloc1(n, &ilocal));
57 PetscCall(PetscMalloc1(n, &ilocalneg));
58 PetscCall(ISGetIndices(subset, &idxs));
59 PetscCall(ISGetBlockSize(subset, &ibs));
60 PetscCall(PetscObjectTypeCompare((PetscObject)subset, ISBLOCK, &isblock));
61 if (subset_mult) PetscCall(ISGetIndices(subset_mult, &idxs_mult));
62 lbounds[0] = PETSC_INT_MAX;
63 lbounds[1] = PETSC_INT_MIN;
64 for (i = 0, npos = 0, nneg = 0; i < n; i++) {
65 if (idxs[i] < 0) {
66 ilocalneg[nneg++] = i;
67 continue;
68 }
69 if (idxs[i] < lbounds[0]) lbounds[0] = idxs[i];
70 if (idxs[i] > lbounds[1]) lbounds[1] = idxs[i];
71 ilocal[npos++] = i;
72 }
73 if (npos == n) {
74 PetscCall(PetscFree(ilocal));
75 PetscCall(PetscFree(ilocalneg));
76 }
77
78 /* create sf : leaf_data == multiplicity of indexes, root data == global index in layout */
79 PetscCall(PetscMalloc1(n, &leaf_data));
80 for (i = 0; i < n; i++) leaf_data[i] = idxs_mult ? PetscMax(idxs_mult[i], 0) : 1;
81
82 /* local size of new subset */
83 n_n = 0;
84 for (i = 0; i < n; i++) n_n += leaf_data[i];
85 if (ilocalneg)
86 for (i = 0; i < nneg; i++) leaf_data[ilocalneg[i]] = 0;
87 PetscCall(PetscFree(ilocalneg));
88 PetscCall(PetscMalloc1(PetscMax(n_n, n), &gidxs)); /* allocating extra space to reuse gidxs */
89 /* check for early termination (all negative) */
90 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)subset), lbounds, gbounds));
91 if (gbounds[1] < gbounds[0]) {
92 if (N) *N = 0;
93 if (subset_n) { /* all negative */
94 for (i = 0; i < n_n; i++) gidxs[i] = -1;
95 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)subset), n_n, gidxs, PETSC_COPY_VALUES, subset_n));
96 }
97 PetscCall(PetscFree(leaf_data));
98 PetscCall(PetscFree(gidxs));
99 PetscCall(ISRestoreIndices(subset, &idxs));
100 if (subset_mult) PetscCall(ISRestoreIndices(subset_mult, &idxs_mult));
101 PetscCall(PetscFree(ilocal));
102 PetscCall(PetscFree(ilocalneg));
103 PetscFunctionReturn(PETSC_SUCCESS);
104 }
105
106 /* split work */
107 N_n = gbounds[1] - gbounds[0] + 1;
108 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)subset), &map));
109 PetscCall(PetscLayoutSetBlockSize(map, 1));
110 PetscCall(PetscLayoutSetSize(map, N_n));
111 PetscCall(PetscLayoutSetUp(map));
112 PetscCall(PetscLayoutGetLocalSize(map, &Nl));
113
114 /* global indexes in layout */
115 for (i = 0; i < npos; i++) gidxs[i] = (ilocal ? idxs[ilocal[i]] : idxs[i]) - gbounds[0];
116 PetscCall(ISRestoreIndices(subset, &idxs));
117 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)subset), &sf));
118 PetscCall(PetscSFSetGraphLayout(sf, map, npos, ilocal, PETSC_USE_POINTER, gidxs));
119 PetscCall(PetscLayoutDestroy(&map));
120
121 /* reduce from leaves to roots */
122 PetscCall(PetscCalloc1(Nl, &root_data));
123 PetscCall(PetscSFReduceBegin(sf, MPIU_INT, leaf_data, root_data, MPI_MAX));
124 PetscCall(PetscSFReduceEnd(sf, MPIU_INT, leaf_data, root_data, MPI_MAX));
125
126 /* count indexes in local part of layout */
127 nlocals = 0;
128 first_index = -1;
129 first_found = PETSC_FALSE;
130 for (i = 0; i < Nl; i++) {
131 if (!first_found && root_data[i]) {
132 first_found = PETSC_TRUE;
133 first_index = i;
134 }
135 nlocals += root_data[i];
136 }
137
138 /* cumulative of number of indexes and size of subset without holes */
139 #if defined(PETSC_HAVE_MPI_EXSCAN)
140 start = 0;
141 PetscCallMPI(MPI_Exscan(&nlocals, &start, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)subset)));
142 #else
143 PetscCallMPI(MPI_Scan(&nlocals, &start, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)subset)));
144 start = start - nlocals;
145 #endif
146
147 if (N) { /* compute total size of new subset if requested */
148 *N = start + nlocals;
149 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)subset), &commsize));
150 PetscCallMPI(MPI_Bcast(N, 1, MPIU_INT, commsize - 1, PetscObjectComm((PetscObject)subset)));
151 }
152
153 if (!subset_n) {
154 PetscCall(PetscFree(gidxs));
155 PetscCall(PetscSFDestroy(&sf));
156 PetscCall(PetscFree(leaf_data));
157 PetscCall(PetscFree(root_data));
158 PetscCall(PetscFree(ilocal));
159 if (subset_mult) PetscCall(ISRestoreIndices(subset_mult, &idxs_mult));
160 PetscFunctionReturn(PETSC_SUCCESS);
161 }
162
163 /* adapt root data with cumulative */
164 if (first_found) {
165 PetscInt old_index;
166
167 root_data[first_index] += start;
168 old_index = first_index;
169 for (i = first_index + 1; i < Nl; i++) {
170 if (root_data[i]) {
171 root_data[i] += root_data[old_index];
172 old_index = i;
173 }
174 }
175 }
176
177 /* from roots to leaves */
178 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, root_data, leaf_data, MPI_REPLACE));
179 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, root_data, leaf_data, MPI_REPLACE));
180 PetscCall(PetscSFDestroy(&sf));
181
182 /* create new IS with global indexes without holes */
183 for (i = 0; i < n_n; i++) gidxs[i] = -1;
184 if (subset_mult) {
185 PetscInt cum;
186
187 isblock = PETSC_FALSE;
188 for (i = 0, cum = 0; i < n; i++)
189 for (PetscInt j = 0; j < idxs_mult[i]; j++) gidxs[cum++] = leaf_data[i] - idxs_mult[i] + j;
190 } else
191 for (i = 0; i < n; i++) gidxs[i] = leaf_data[i] - 1;
192
193 if (isblock) {
194 if (ibs > 1)
195 for (i = 0; i < n_n / ibs; i++) gidxs[i] = gidxs[i * ibs] / ibs;
196 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)subset), ibs, n_n / ibs, gidxs, PETSC_COPY_VALUES, subset_n));
197 } else {
198 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)subset), n_n, gidxs, PETSC_COPY_VALUES, subset_n));
199 }
200 if (subset_mult) PetscCall(ISRestoreIndices(subset_mult, &idxs_mult));
201 PetscCall(PetscFree(gidxs));
202 PetscCall(PetscFree(leaf_data));
203 PetscCall(PetscFree(root_data));
204 PetscCall(PetscFree(ilocal));
205 PetscFunctionReturn(PETSC_SUCCESS);
206 }
207
208 /*@
209 ISCreateSubIS - Create a sub index set from a global index set selecting some components.
210
211 Collective
212
213 Input Parameters:
214 + is - the index set
215 - comps - which components we will extract from `is`
216
217 Output Parameters:
218 . subis - the new sub index set
219
220 Example usage:
221 We have an index set `is` living on 3 processes with the following values\:
222 | 4 9 0 | 2 6 7 | 10 11 1|
223 and another index set `comps` used to indicate which components of is we want to take,
224 | 7 5 | 1 2 | 0 4|
225 The output index set `subis` should look like\:
226 | 11 7 | 9 0 | 4 6|
227
228 Level: intermediate
229
230 .seealso: `IS`, `VecGetSubVector()`, `MatCreateSubMatrix()`
231 @*/
ISCreateSubIS(IS is,IS comps,IS * subis)232 PetscErrorCode ISCreateSubIS(IS is, IS comps, IS *subis)
233 {
234 PetscSF sf;
235 const PetscInt *is_indices, *comps_indices;
236 PetscInt *subis_indices, nroots, nleaves, *mine, i, lidx;
237 PetscMPIInt owner;
238 PetscSFNode *remote;
239 MPI_Comm comm;
240
241 PetscFunctionBegin;
242 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
243 PetscValidHeaderSpecific(comps, IS_CLASSID, 2);
244 PetscAssertPointer(subis, 3);
245
246 PetscCall(PetscObjectGetComm((PetscObject)is, &comm));
247 PetscCall(ISGetLocalSize(comps, &nleaves));
248 PetscCall(ISGetLocalSize(is, &nroots));
249 PetscCall(PetscMalloc1(nleaves, &remote));
250 PetscCall(PetscMalloc1(nleaves, &mine));
251 PetscCall(ISGetIndices(comps, &comps_indices));
252 /*
253 * Construct a PetscSF in which "is" data serves as roots and "subis" is leaves.
254 * Root data are sent to leaves using PetscSFBcast().
255 * */
256 for (i = 0; i < nleaves; i++) {
257 mine[i] = i;
258 /* Connect a remote root with the current leaf. The value on the remote root
259 * will be received by the current local leaf.
260 * */
261 owner = -1;
262 lidx = -1;
263 PetscCall(PetscLayoutFindOwnerIndex(is->map, comps_indices[i], &owner, &lidx));
264 remote[i].rank = owner;
265 remote[i].index = lidx;
266 }
267 PetscCall(ISRestoreIndices(comps, &comps_indices));
268 PetscCall(PetscSFCreate(comm, &sf));
269 PetscCall(PetscSFSetFromOptions(sf));
270 PetscCall(PetscSFSetGraph(sf, nroots, nleaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
271
272 PetscCall(PetscMalloc1(nleaves, &subis_indices));
273 PetscCall(ISGetIndices(is, &is_indices));
274 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, is_indices, subis_indices, MPI_REPLACE));
275 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, is_indices, subis_indices, MPI_REPLACE));
276 PetscCall(ISRestoreIndices(is, &is_indices));
277 PetscCall(PetscSFDestroy(&sf));
278 PetscCall(ISCreateGeneral(comm, nleaves, subis_indices, PETSC_OWN_POINTER, subis));
279 PetscFunctionReturn(PETSC_SUCCESS);
280 }
281
282 /*@
283 ISClearInfoCache - clear the cache of computed index set properties
284
285 Not Collective
286
287 Input Parameters:
288 + is - the index set
289 - clear_permanent_local - whether to remove the permanent status of local properties
290
291 Level: developer
292
293 Note:
294 Because all processes must agree on the global permanent status of a property,
295 the permanent status can only be changed with `ISSetInfo()`, because this routine is not collective
296
297 .seealso: `IS`, `ISInfo`, `ISInfoType`, `ISSetInfo()`
298 @*/
ISClearInfoCache(IS is,PetscBool clear_permanent_local)299 PetscErrorCode ISClearInfoCache(IS is, PetscBool clear_permanent_local)
300 {
301 PetscInt i, j;
302
303 PetscFunctionBegin;
304 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
305 PetscValidType(is, 1);
306 for (i = 0; i < IS_INFO_MAX; i++) {
307 if (clear_permanent_local) is->info_permanent[IS_LOCAL][i] = PETSC_FALSE;
308 for (j = 0; j < 2; j++) {
309 if (!is->info_permanent[j][i]) is->info[j][i] = IS_INFO_UNKNOWN;
310 }
311 }
312 PetscFunctionReturn(PETSC_SUCCESS);
313 }
314
ISSetInfo_Internal(IS is,ISInfo info,ISInfoType type,ISInfoBool ipermanent,PetscBool flg)315 static PetscErrorCode ISSetInfo_Internal(IS is, ISInfo info, ISInfoType type, ISInfoBool ipermanent, PetscBool flg)
316 {
317 ISInfoBool iflg = flg ? IS_INFO_TRUE : IS_INFO_FALSE;
318 PetscInt itype = (type == IS_LOCAL) ? 0 : 1;
319 PetscBool permanent_set = (ipermanent == IS_INFO_UNKNOWN) ? PETSC_FALSE : PETSC_TRUE;
320 PetscBool permanent = (ipermanent == IS_INFO_TRUE) ? PETSC_TRUE : PETSC_FALSE;
321
322 PetscFunctionBegin;
323 /* set this property */
324 is->info[itype][(int)info] = iflg;
325 if (permanent_set) is->info_permanent[itype][(int)info] = permanent;
326 /* set implications */
327 switch (info) {
328 case IS_SORTED:
329 if (PetscDefined(USE_DEBUG) && flg) {
330 PetscInt n;
331 const PetscInt *indices;
332
333 PetscCall(ISGetLocalSize(is, &n));
334 PetscCall(ISGetIndices(is, &indices));
335 PetscCall(PetscSortedInt(n, indices, &flg));
336 if (type == IS_GLOBAL) PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)is)));
337 PetscCheck(flg, type == IS_GLOBAL ? PetscObjectComm((PetscObject)is) : PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "IS is not sorted");
338 PetscCall(ISRestoreIndices(is, &indices));
339 }
340 if (flg && type == IS_GLOBAL) { /* an array that is globally sorted is also locally sorted */
341 is->info[IS_LOCAL][(int)info] = IS_INFO_TRUE;
342 /* global permanence implies local permanence */
343 if (permanent_set && permanent) is->info_permanent[IS_LOCAL][(int)info] = PETSC_TRUE;
344 }
345 if (!flg) { /* if an array is not sorted, it cannot be an interval or the identity */
346 is->info[itype][IS_INTERVAL] = IS_INFO_FALSE;
347 is->info[itype][IS_IDENTITY] = IS_INFO_FALSE;
348 if (permanent_set) {
349 is->info_permanent[itype][IS_INTERVAL] = permanent;
350 is->info_permanent[itype][IS_IDENTITY] = permanent;
351 }
352 }
353 break;
354 case IS_UNIQUE:
355 if (flg && type == IS_GLOBAL) { /* an array that is globally unique is also locally unique */
356 is->info[IS_LOCAL][(int)info] = IS_INFO_TRUE;
357 /* global permanence implies local permanence */
358 if (permanent_set && permanent) is->info_permanent[IS_LOCAL][(int)info] = PETSC_TRUE;
359 }
360 if (!flg) { /* if an array is not unique, it cannot be a permutation, and interval, or the identity */
361 is->info[itype][IS_PERMUTATION] = IS_INFO_FALSE;
362 is->info[itype][IS_INTERVAL] = IS_INFO_FALSE;
363 is->info[itype][IS_IDENTITY] = IS_INFO_FALSE;
364 if (permanent_set) {
365 is->info_permanent[itype][IS_PERMUTATION] = permanent;
366 is->info_permanent[itype][IS_INTERVAL] = permanent;
367 is->info_permanent[itype][IS_IDENTITY] = permanent;
368 }
369 }
370 break;
371 case IS_PERMUTATION:
372 if (flg) { /* an array that is a permutation is unique and is unique locally */
373 is->info[itype][IS_UNIQUE] = IS_INFO_TRUE;
374 is->info[IS_LOCAL][IS_UNIQUE] = IS_INFO_TRUE;
375 if (permanent_set && permanent) {
376 is->info_permanent[itype][IS_UNIQUE] = PETSC_TRUE;
377 is->info_permanent[IS_LOCAL][IS_UNIQUE] = PETSC_TRUE;
378 }
379 } else { /* an array that is not a permutation cannot be the identity */
380 is->info[itype][IS_IDENTITY] = IS_INFO_FALSE;
381 if (permanent_set) is->info_permanent[itype][IS_IDENTITY] = permanent;
382 }
383 break;
384 case IS_INTERVAL:
385 if (flg) { /* an array that is an interval is sorted and unique */
386 is->info[itype][IS_SORTED] = IS_INFO_TRUE;
387 is->info[IS_LOCAL][IS_SORTED] = IS_INFO_TRUE;
388 is->info[itype][IS_UNIQUE] = IS_INFO_TRUE;
389 is->info[IS_LOCAL][IS_UNIQUE] = IS_INFO_TRUE;
390 if (permanent_set && permanent) {
391 is->info_permanent[itype][IS_SORTED] = PETSC_TRUE;
392 is->info_permanent[IS_LOCAL][IS_SORTED] = PETSC_TRUE;
393 is->info_permanent[itype][IS_UNIQUE] = PETSC_TRUE;
394 is->info_permanent[IS_LOCAL][IS_UNIQUE] = PETSC_TRUE;
395 }
396 } else { /* an array that is not an interval cannot be the identity */
397 is->info[itype][IS_IDENTITY] = IS_INFO_FALSE;
398 if (permanent_set) is->info_permanent[itype][IS_IDENTITY] = permanent;
399 }
400 break;
401 case IS_IDENTITY:
402 if (flg) { /* an array that is the identity is sorted, unique, an interval, and a permutation */
403 is->info[itype][IS_SORTED] = IS_INFO_TRUE;
404 is->info[IS_LOCAL][IS_SORTED] = IS_INFO_TRUE;
405 is->info[itype][IS_UNIQUE] = IS_INFO_TRUE;
406 is->info[IS_LOCAL][IS_UNIQUE] = IS_INFO_TRUE;
407 is->info[itype][IS_PERMUTATION] = IS_INFO_TRUE;
408 is->info[itype][IS_INTERVAL] = IS_INFO_TRUE;
409 is->info[IS_LOCAL][IS_INTERVAL] = IS_INFO_TRUE;
410 if (permanent_set && permanent) {
411 is->info_permanent[itype][IS_SORTED] = PETSC_TRUE;
412 is->info_permanent[IS_LOCAL][IS_SORTED] = PETSC_TRUE;
413 is->info_permanent[itype][IS_UNIQUE] = PETSC_TRUE;
414 is->info_permanent[IS_LOCAL][IS_UNIQUE] = PETSC_TRUE;
415 is->info_permanent[itype][IS_PERMUTATION] = PETSC_TRUE;
416 is->info_permanent[itype][IS_INTERVAL] = PETSC_TRUE;
417 is->info_permanent[IS_LOCAL][IS_INTERVAL] = PETSC_TRUE;
418 }
419 }
420 break;
421 default:
422 PetscCheck(type != IS_LOCAL, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown IS property");
423 SETERRQ(PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_OUTOFRANGE, "Unknown IS property");
424 }
425 PetscFunctionReturn(PETSC_SUCCESS);
426 }
427
428 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
429 /*@
430 ISSetInfo - Set known information about an index set.
431
432 Logically Collective if `ISInfoType` is `IS_GLOBAL`
433
434 Input Parameters:
435 + is - the index set
436 . info - describing a property of the index set, one of those listed below,
437 . type - `IS_LOCAL` if the information describes the local portion of the index set,
438 `IS_GLOBAL` if it describes the whole index set
439 . permanent - `PETSC_TRUE` if it is known that the property will persist through changes to the index set, `PETSC_FALSE` otherwise
440 If the user sets a property as permanently known, it will bypass computation of that property
441 - flg - set the described property as true (`PETSC_TRUE`) or false (`PETSC_FALSE`)
442
443 Values of `info` Describing `IS` Structure:
444 + `IS_SORTED` - the [local part of the] index set is sorted in ascending order
445 . `IS_UNIQUE` - each entry in the [local part of the] index set is unique
446 . `IS_PERMUTATION` - the [local part of the] index set is a permutation of the integers {0, 1, ..., N-1}, where N is the size of the [local part of the] index set
447 . `IS_INTERVAL` - the [local part of the] index set is equal to a contiguous range of integers {f, f + 1, ..., f + N-1}
448 - `IS_IDENTITY` - the [local part of the] index set is equal to the integers {0, 1, ..., N-1}
449
450 Level: advanced
451
452 Notes:
453 If type is `IS_GLOBAL`, all processes that share the index set must pass the same value in flg
454
455 It is possible to set a property with `ISSetInfo()` that contradicts what would be previously computed with `ISGetInfo()`
456
457 .seealso: `ISInfo`, `ISInfoType`, `IS`
458 @*/
ISSetInfo(IS is,ISInfo info,ISInfoType type,PetscBool permanent,PetscBool flg)459 PetscErrorCode ISSetInfo(IS is, ISInfo info, ISInfoType type, PetscBool permanent, PetscBool flg)
460 {
461 MPI_Comm comm, errcomm;
462 PetscMPIInt size;
463
464 PetscFunctionBegin;
465 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
466 PetscValidType(is, 1);
467 comm = PetscObjectComm((PetscObject)is);
468 if (type == IS_GLOBAL) {
469 PetscValidLogicalCollectiveEnum(is, info, 2);
470 PetscValidLogicalCollectiveBool(is, permanent, 4);
471 PetscValidLogicalCollectiveBool(is, flg, 5);
472 errcomm = comm;
473 } else {
474 errcomm = PETSC_COMM_SELF;
475 }
476
477 PetscCheck((int)info > IS_INFO_MIN && (int)info < IS_INFO_MAX, errcomm, PETSC_ERR_ARG_OUTOFRANGE, "Option %d is out of range", (int)info);
478
479 PetscCallMPI(MPI_Comm_size(comm, &size));
480 /* do not use global values if size == 1: it makes it easier to keep the implications straight */
481 if (size == 1) type = IS_LOCAL;
482 PetscCall(ISSetInfo_Internal(is, info, type, permanent ? IS_INFO_TRUE : IS_INFO_FALSE, flg));
483 PetscFunctionReturn(PETSC_SUCCESS);
484 }
485
ISGetInfo_Sorted_Private(IS is,ISInfoType type,PetscBool * flg)486 static PetscErrorCode ISGetInfo_Sorted_Private(IS is, ISInfoType type, PetscBool *flg)
487 {
488 MPI_Comm comm;
489 PetscMPIInt size, rank;
490
491 PetscFunctionBegin;
492 comm = PetscObjectComm((PetscObject)is);
493 PetscCallMPI(MPI_Comm_size(comm, &size));
494 PetscCallMPI(MPI_Comm_rank(comm, &rank));
495 if (type == IS_GLOBAL && is->ops->sortedglobal) {
496 PetscUseTypeMethod(is, sortedglobal, flg);
497 } else {
498 PetscBool sortedLocal = PETSC_FALSE;
499
500 /* determine if the array is locally sorted */
501 if (type == IS_GLOBAL && size > 1) {
502 /* call ISGetInfo so that a cached value will be used if possible */
503 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sortedLocal));
504 } else if (is->ops->sortedlocal) {
505 PetscUseTypeMethod(is, sortedlocal, &sortedLocal);
506 } else {
507 /* default: get the local indices and directly check */
508 const PetscInt *idx;
509 PetscInt n;
510
511 PetscCall(ISGetIndices(is, &idx));
512 PetscCall(ISGetLocalSize(is, &n));
513 PetscCall(PetscSortedInt(n, idx, &sortedLocal));
514 PetscCall(ISRestoreIndices(is, &idx));
515 }
516
517 if (type == IS_LOCAL || size == 1) {
518 *flg = sortedLocal;
519 } else {
520 PetscCallMPI(MPIU_Allreduce(&sortedLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
521 if (*flg) {
522 PetscInt n, min = PETSC_INT_MAX, max = PETSC_INT_MIN;
523 PetscInt maxprev;
524
525 PetscCall(ISGetLocalSize(is, &n));
526 if (n) PetscCall(ISGetMinMax(is, &min, &max));
527 maxprev = PETSC_INT_MIN;
528 PetscCallMPI(MPI_Exscan(&max, &maxprev, 1, MPIU_INT, MPI_MAX, comm));
529 if (rank && (maxprev > min)) sortedLocal = PETSC_FALSE;
530 PetscCallMPI(MPIU_Allreduce(&sortedLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
531 }
532 }
533 }
534 PetscFunctionReturn(PETSC_SUCCESS);
535 }
536
537 static PetscErrorCode ISGetIndicesCopy_Private(IS is, PetscInt idx[]);
538
ISGetInfo_Unique_Private(IS is,ISInfoType type,PetscBool * flg)539 static PetscErrorCode ISGetInfo_Unique_Private(IS is, ISInfoType type, PetscBool *flg)
540 {
541 MPI_Comm comm;
542 PetscMPIInt size, rank;
543 PetscInt i;
544
545 PetscFunctionBegin;
546 comm = PetscObjectComm((PetscObject)is);
547 PetscCallMPI(MPI_Comm_size(comm, &size));
548 PetscCallMPI(MPI_Comm_rank(comm, &rank));
549 if (type == IS_GLOBAL && is->ops->uniqueglobal) {
550 PetscUseTypeMethod(is, uniqueglobal, flg);
551 } else {
552 PetscBool uniqueLocal;
553 PetscInt n = -1;
554 PetscInt *idx = NULL;
555
556 /* determine if the array is locally unique */
557 if (type == IS_GLOBAL && size > 1) {
558 /* call ISGetInfo so that a cached value will be used if possible */
559 PetscCall(ISGetInfo(is, IS_UNIQUE, IS_LOCAL, PETSC_TRUE, &uniqueLocal));
560 } else if (is->ops->uniquelocal) {
561 PetscUseTypeMethod(is, uniquelocal, &uniqueLocal);
562 } else {
563 /* default: get the local indices and directly check */
564 uniqueLocal = PETSC_TRUE;
565 PetscCall(ISGetLocalSize(is, &n));
566 PetscCall(PetscMalloc1(n, &idx));
567 PetscCall(ISGetIndicesCopy_Private(is, idx));
568 PetscCall(PetscIntSortSemiOrdered(n, idx));
569 for (i = 1; i < n; i++)
570 if (idx[i] == idx[i - 1]) break;
571 if (i < n) uniqueLocal = PETSC_FALSE;
572 }
573
574 PetscCall(PetscFree(idx));
575 if (type == IS_LOCAL || size == 1) {
576 *flg = uniqueLocal;
577 } else {
578 PetscCallMPI(MPIU_Allreduce(&uniqueLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
579 if (*flg) {
580 PetscInt min = PETSC_INT_MAX, max = PETSC_INT_MIN, maxprev;
581
582 if (!idx) {
583 PetscCall(ISGetLocalSize(is, &n));
584 PetscCall(PetscMalloc1(n, &idx));
585 PetscCall(ISGetIndicesCopy_Private(is, idx));
586 }
587 PetscCall(PetscParallelSortInt(is->map, is->map, idx, idx));
588 if (n) {
589 min = idx[0];
590 max = idx[n - 1];
591 }
592 for (i = 1; i < n; i++)
593 if (idx[i] == idx[i - 1]) break;
594 if (i < n) uniqueLocal = PETSC_FALSE;
595 maxprev = PETSC_INT_MIN;
596 PetscCallMPI(MPI_Exscan(&max, &maxprev, 1, MPIU_INT, MPI_MAX, comm));
597 if (rank && (maxprev == min)) uniqueLocal = PETSC_FALSE;
598 PetscCallMPI(MPIU_Allreduce(&uniqueLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
599 }
600 }
601 PetscCall(PetscFree(idx));
602 }
603 PetscFunctionReturn(PETSC_SUCCESS);
604 }
605
ISGetInfo_Permutation(IS is,ISInfoType type,PetscBool * flg)606 static PetscErrorCode ISGetInfo_Permutation(IS is, ISInfoType type, PetscBool *flg)
607 {
608 MPI_Comm comm;
609 PetscMPIInt size;
610
611 PetscFunctionBegin;
612 comm = PetscObjectComm((PetscObject)is);
613 PetscCallMPI(MPI_Comm_size(comm, &size));
614 if (type == IS_GLOBAL && is->ops->permglobal) {
615 PetscUseTypeMethod(is, permglobal, flg);
616 } else if (type == IS_LOCAL && is->ops->permlocal) {
617 PetscUseTypeMethod(is, permlocal, flg);
618 } else {
619 PetscBool permLocal;
620 PetscInt n, i, rStart;
621 PetscInt *idx;
622
623 PetscCall(ISGetLocalSize(is, &n));
624 PetscCall(PetscMalloc1(n, &idx));
625 PetscCall(ISGetIndicesCopy_Private(is, idx));
626 if (type == IS_GLOBAL) {
627 PetscCall(PetscParallelSortInt(is->map, is->map, idx, idx));
628 PetscCall(PetscLayoutGetRange(is->map, &rStart, NULL));
629 } else {
630 PetscCall(PetscIntSortSemiOrdered(n, idx));
631 rStart = 0;
632 }
633 permLocal = PETSC_TRUE;
634 for (i = 0; i < n; i++) {
635 if (idx[i] != rStart + i) break;
636 }
637 if (i < n) permLocal = PETSC_FALSE;
638 if (type == IS_LOCAL || size == 1) {
639 *flg = permLocal;
640 } else {
641 PetscCallMPI(MPIU_Allreduce(&permLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
642 }
643 PetscCall(PetscFree(idx));
644 }
645 PetscFunctionReturn(PETSC_SUCCESS);
646 }
647
ISGetInfo_Interval(IS is,ISInfoType type,PetscBool * flg)648 static PetscErrorCode ISGetInfo_Interval(IS is, ISInfoType type, PetscBool *flg)
649 {
650 MPI_Comm comm;
651 PetscMPIInt size, rank;
652 PetscInt i;
653
654 PetscFunctionBegin;
655 comm = PetscObjectComm((PetscObject)is);
656 PetscCallMPI(MPI_Comm_size(comm, &size));
657 PetscCallMPI(MPI_Comm_rank(comm, &rank));
658 if (type == IS_GLOBAL && is->ops->intervalglobal) {
659 PetscUseTypeMethod(is, intervalglobal, flg);
660 } else {
661 PetscBool intervalLocal;
662
663 /* determine if the array is locally an interval */
664 if (type == IS_GLOBAL && size > 1) {
665 /* call ISGetInfo so that a cached value will be used if possible */
666 PetscCall(ISGetInfo(is, IS_INTERVAL, IS_LOCAL, PETSC_TRUE, &intervalLocal));
667 } else if (is->ops->intervallocal) {
668 PetscUseTypeMethod(is, intervallocal, &intervalLocal);
669 } else {
670 PetscInt n;
671 const PetscInt *idx;
672 /* default: get the local indices and directly check */
673 intervalLocal = PETSC_TRUE;
674 PetscCall(ISGetLocalSize(is, &n));
675 PetscCall(ISGetIndices(is, &idx));
676 for (i = 1; i < n; i++)
677 if (idx[i] != idx[i - 1] + 1) break;
678 if (i < n) intervalLocal = PETSC_FALSE;
679 PetscCall(ISRestoreIndices(is, &idx));
680 }
681
682 if (type == IS_LOCAL || size == 1) {
683 *flg = intervalLocal;
684 } else {
685 PetscCallMPI(MPIU_Allreduce(&intervalLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
686 if (*flg) {
687 PetscInt n, min = PETSC_INT_MAX, max = PETSC_INT_MIN;
688 PetscInt maxprev;
689
690 PetscCall(ISGetLocalSize(is, &n));
691 if (n) PetscCall(ISGetMinMax(is, &min, &max));
692 maxprev = PETSC_INT_MIN;
693 PetscCallMPI(MPI_Exscan(&max, &maxprev, 1, MPIU_INT, MPI_MAX, comm));
694 if (rank && n && (maxprev != min - 1)) intervalLocal = PETSC_FALSE;
695 PetscCallMPI(MPIU_Allreduce(&intervalLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
696 }
697 }
698 }
699 PetscFunctionReturn(PETSC_SUCCESS);
700 }
701
ISGetInfo_Identity(IS is,ISInfoType type,PetscBool * flg)702 static PetscErrorCode ISGetInfo_Identity(IS is, ISInfoType type, PetscBool *flg)
703 {
704 MPI_Comm comm;
705 PetscMPIInt size;
706
707 PetscFunctionBegin;
708 comm = PetscObjectComm((PetscObject)is);
709 PetscCallMPI(MPI_Comm_size(comm, &size));
710 if (type == IS_GLOBAL && is->ops->intervalglobal) {
711 PetscBool isinterval;
712
713 PetscUseTypeMethod(is, intervalglobal, &isinterval);
714 *flg = PETSC_FALSE;
715 if (isinterval) {
716 PetscInt min;
717
718 PetscCall(ISGetMinMax(is, &min, NULL));
719 PetscCallMPI(MPI_Bcast(&min, 1, MPIU_INT, 0, comm));
720 if (min == 0) *flg = PETSC_TRUE;
721 }
722 } else if (type == IS_LOCAL && is->ops->intervallocal) {
723 PetscBool isinterval;
724
725 PetscUseTypeMethod(is, intervallocal, &isinterval);
726 *flg = PETSC_FALSE;
727 if (isinterval) {
728 PetscInt min;
729
730 PetscCall(ISGetMinMax(is, &min, NULL));
731 if (min == 0) *flg = PETSC_TRUE;
732 }
733 } else {
734 PetscBool identLocal;
735 PetscInt n, i, rStart;
736 const PetscInt *idx;
737
738 PetscCall(ISGetLocalSize(is, &n));
739 PetscCall(ISGetIndices(is, &idx));
740 PetscCall(PetscLayoutGetRange(is->map, &rStart, NULL));
741 identLocal = PETSC_TRUE;
742 for (i = 0; i < n; i++) {
743 if (idx[i] != rStart + i) break;
744 }
745 if (i < n) identLocal = PETSC_FALSE;
746 if (type == IS_LOCAL || size == 1) {
747 *flg = identLocal;
748 } else {
749 PetscCallMPI(MPIU_Allreduce(&identLocal, flg, 1, MPI_C_BOOL, MPI_LAND, comm));
750 }
751 PetscCall(ISRestoreIndices(is, &idx));
752 }
753 PetscFunctionReturn(PETSC_SUCCESS);
754 }
755
756 /*@
757 ISGetInfo - Determine whether an index set satisfies a given property
758
759 Collective or Logically Collective if the type is `IS_GLOBAL` (logically collective if the value of the property has been permanently set with `ISSetInfo()`)
760
761 Input Parameters:
762 + is - the index set
763 . info - describing a property of the index set, one of those listed in the documentation of `ISSetInfo()`
764 . compute - if `PETSC_FALSE`, the property will not be computed if it is not already known and the property will be assumed to be false
765 - type - whether the property is local (`IS_LOCAL`) or global (`IS_GLOBAL`)
766
767 Output Parameter:
768 . flg - whether the property is true (`PETSC_TRUE`) or false (`PETSC_FALSE`)
769
770 Level: advanced
771
772 Notes:
773 `ISGetInfo()` uses cached values when possible, which will be incorrect if `ISSetInfo()` has been called with incorrect information.
774
775 To clear cached values, use `ISClearInfoCache()`.
776
777 .seealso: `IS`, `ISInfo`, `ISInfoType`, `ISSetInfo()`, `ISClearInfoCache()`
778 @*/
ISGetInfo(IS is,ISInfo info,ISInfoType type,PetscBool compute,PetscBool * flg)779 PetscErrorCode ISGetInfo(IS is, ISInfo info, ISInfoType type, PetscBool compute, PetscBool *flg)
780 {
781 MPI_Comm comm, errcomm;
782 PetscMPIInt rank, size;
783 PetscInt itype;
784 PetscBool hasprop;
785 PetscBool infer;
786
787 PetscFunctionBegin;
788 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
789 PetscValidType(is, 1);
790 comm = PetscObjectComm((PetscObject)is);
791 if (type == IS_GLOBAL) {
792 PetscValidLogicalCollectiveEnum(is, info, 2);
793 errcomm = comm;
794 } else {
795 errcomm = PETSC_COMM_SELF;
796 }
797
798 PetscCallMPI(MPI_Comm_size(comm, &size));
799 PetscCallMPI(MPI_Comm_rank(comm, &rank));
800
801 PetscCheck((int)info > IS_INFO_MIN && (int)info < IS_INFO_MAX, errcomm, PETSC_ERR_ARG_OUTOFRANGE, "Option %d is out of range", (int)info);
802 if (size == 1) type = IS_LOCAL;
803 itype = (type == IS_LOCAL) ? 0 : 1;
804 hasprop = PETSC_FALSE;
805 infer = PETSC_FALSE;
806 if (is->info_permanent[itype][(int)info]) {
807 hasprop = (is->info[itype][(int)info] == IS_INFO_TRUE) ? PETSC_TRUE : PETSC_FALSE;
808 infer = PETSC_TRUE;
809 } else if ((itype == IS_LOCAL) && (is->info[IS_LOCAL][info] != IS_INFO_UNKNOWN)) {
810 /* we can cache local properties as long as we clear them when the IS changes */
811 /* NOTE: we only cache local values because there is no ISAssemblyBegin()/ISAssemblyEnd(),
812 so we have no way of knowing when a cached value has been invalidated by changes on a different process */
813 hasprop = (is->info[itype][(int)info] == IS_INFO_TRUE) ? PETSC_TRUE : PETSC_FALSE;
814 infer = PETSC_TRUE;
815 } else if (compute) {
816 switch (info) {
817 case IS_SORTED:
818 PetscCall(ISGetInfo_Sorted_Private(is, type, &hasprop));
819 break;
820 case IS_UNIQUE:
821 PetscCall(ISGetInfo_Unique_Private(is, type, &hasprop));
822 break;
823 case IS_PERMUTATION:
824 PetscCall(ISGetInfo_Permutation(is, type, &hasprop));
825 break;
826 case IS_INTERVAL:
827 PetscCall(ISGetInfo_Interval(is, type, &hasprop));
828 break;
829 case IS_IDENTITY:
830 PetscCall(ISGetInfo_Identity(is, type, &hasprop));
831 break;
832 default:
833 SETERRQ(errcomm, PETSC_ERR_ARG_OUTOFRANGE, "Unknown IS property");
834 }
835 infer = PETSC_TRUE;
836 }
837 /* call ISSetInfo_Internal to keep all of the implications straight */
838 if (infer) PetscCall(ISSetInfo_Internal(is, info, type, IS_INFO_UNKNOWN, hasprop));
839 *flg = hasprop;
840 PetscFunctionReturn(PETSC_SUCCESS);
841 }
842
ISCopyInfo_Private(IS source,IS dest)843 static PetscErrorCode ISCopyInfo_Private(IS source, IS dest)
844 {
845 PetscFunctionBegin;
846 PetscCall(PetscArraycpy(&dest->info[0], &source->info[0], 2));
847 PetscCall(PetscArraycpy(&dest->info_permanent[0], &source->info_permanent[0], 2));
848 PetscFunctionReturn(PETSC_SUCCESS);
849 }
850
851 /*@
852 ISIdentity - Determines whether index set is the identity mapping.
853
854 Collective
855
856 Input Parameter:
857 . is - the index set
858
859 Output Parameter:
860 . ident - `PETSC_TRUE` if an identity, else `PETSC_FALSE`
861
862 Level: intermediate
863
864 Note:
865 If `ISSetIdentity()` (or `ISSetInfo()` for a permanent property) has been called,
866 `ISIdentity()` will return its answer without communication between processes, but
867 otherwise the output ident will be computed from `ISGetInfo()`,
868 which may require synchronization on the communicator of `is`. To avoid this computation,
869 call `ISGetInfo()` directly with the compute flag set to `PETSC_FALSE`, and ident will be assumed false.
870
871 .seealso: `IS`, `ISSetIdentity()`, `ISGetInfo()`
872 @*/
ISIdentity(IS is,PetscBool * ident)873 PetscErrorCode ISIdentity(IS is, PetscBool *ident)
874 {
875 PetscFunctionBegin;
876 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
877 PetscAssertPointer(ident, 2);
878 PetscCall(ISGetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, ident));
879 PetscFunctionReturn(PETSC_SUCCESS);
880 }
881
882 /*@
883 ISSetIdentity - Informs the index set that it is an identity.
884
885 Logically Collective
886
887 Input Parameter:
888 . is - the index set
889
890 Level: intermediate
891
892 Notes:
893 `is` will be considered the identity permanently, even if indices have been changes (for example, with
894 `ISGeneralSetIndices()`). It's a good idea to only set this property if `is` will not change in the future.
895
896 To clear this property, use `ISClearInfoCache()`.
897
898 Developer Notes:
899 Some of these info routines have statements about values changing in the `IS`, this seems to contradict the fact that `IS` cannot be changed?
900
901 .seealso: `IS`, `ISIdentity()`, `ISSetInfo()`, `ISClearInfoCache()`
902 @*/
ISSetIdentity(IS is)903 PetscErrorCode ISSetIdentity(IS is)
904 {
905 PetscFunctionBegin;
906 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
907 PetscCall(ISSetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, PETSC_TRUE));
908 PetscFunctionReturn(PETSC_SUCCESS);
909 }
910
911 /*@
912 ISContiguousLocal - Locates an index set with contiguous range within a global range, if possible
913
914 Not Collective
915
916 Input Parameters:
917 + is - the index set
918 . gstart - global start
919 - gend - global end
920
921 Output Parameters:
922 + start - start of contiguous block, as an offset from `gstart`
923 - contig - `PETSC_TRUE` if the index set refers to contiguous entries on this process, else `PETSC_FALSE`
924
925 Level: developer
926
927 .seealso: `IS`, `ISGetLocalSize()`, `VecGetOwnershipRange()`
928 @*/
ISContiguousLocal(IS is,PetscInt gstart,PetscInt gend,PetscInt * start,PetscBool * contig)929 PetscErrorCode ISContiguousLocal(IS is, PetscInt gstart, PetscInt gend, PetscInt *start, PetscBool *contig)
930 {
931 PetscFunctionBegin;
932 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
933 PetscAssertPointer(start, 4);
934 PetscAssertPointer(contig, 5);
935 PetscCheck(gstart <= gend, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "gstart %" PetscInt_FMT " must be less than or equal to gend %" PetscInt_FMT, gstart, gend);
936 *start = -1;
937 *contig = PETSC_FALSE;
938 PetscTryTypeMethod(is, contiguous, gstart, gend, start, contig);
939 PetscFunctionReturn(PETSC_SUCCESS);
940 }
941
942 /*@
943 ISPermutation - `PETSC_TRUE` or `PETSC_FALSE` depending on whether the
944 index set has been declared to be a permutation.
945
946 Logically Collective
947
948 Input Parameter:
949 . is - the index set
950
951 Output Parameter:
952 . perm - `PETSC_TRUE` if a permutation, else `PETSC_FALSE`
953
954 Level: intermediate
955
956 Note:
957 If it is not already known that `is` is a permutation (if `ISSetPermutation()`
958 or `ISSetInfo()` has not been called), this routine will not attempt to compute
959 whether the index set is a permutation and will assume `perm` is `PETSC_FALSE`.
960 To compute the value when it is not already known, use `ISGetInfo()` with
961 the compute flag set to `PETSC_TRUE`.
962
963 Developer Notes:
964 Perhaps some of these routines should use the `PetscBool3` enum to return appropriate values
965
966 .seealso: `IS`, `ISSetPermutation()`, `ISGetInfo()`
967 @*/
ISPermutation(IS is,PetscBool * perm)968 PetscErrorCode ISPermutation(IS is, PetscBool *perm)
969 {
970 PetscFunctionBegin;
971 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
972 PetscAssertPointer(perm, 2);
973 PetscCall(ISGetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_FALSE, perm));
974 PetscFunctionReturn(PETSC_SUCCESS);
975 }
976
977 /*@
978 ISSetPermutation - Informs the index set that it is a permutation.
979
980 Logically Collective
981
982 Input Parameter:
983 . is - the index set
984
985 Level: intermediate
986
987 Notes:
988 `is` will be considered a permutation permanently, even if indices have been changes (for example, with
989 `ISGeneralSetIndices()`). It's a good idea to only set this property if `is` will not change in the future.
990
991 To clear this property, use `ISClearInfoCache()`.
992
993 The debug version of the libraries (./configure --with-debugging=1) checks if the
994 index set is actually a permutation. The optimized version just believes you.
995
996 .seealso: `IS`, `ISPermutation()`, `ISSetInfo()`, `ISClearInfoCache().`
997 @*/
ISSetPermutation(IS is)998 PetscErrorCode ISSetPermutation(IS is)
999 {
1000 PetscFunctionBegin;
1001 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1002 if (PetscDefined(USE_DEBUG)) {
1003 PetscMPIInt size;
1004
1005 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1006 if (size == 1) {
1007 PetscInt i, n, *idx;
1008 const PetscInt *iidx;
1009
1010 PetscCall(ISGetSize(is, &n));
1011 PetscCall(PetscMalloc1(n, &idx));
1012 PetscCall(ISGetIndices(is, &iidx));
1013 PetscCall(PetscArraycpy(idx, iidx, n));
1014 PetscCall(PetscIntSortSemiOrdered(n, idx));
1015 for (i = 0; i < n; i++) PetscCheck(idx[i] == i, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Index set is not a permutation");
1016 PetscCall(PetscFree(idx));
1017 PetscCall(ISRestoreIndices(is, &iidx));
1018 }
1019 }
1020 PetscCall(ISSetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_TRUE, PETSC_TRUE));
1021 PetscFunctionReturn(PETSC_SUCCESS);
1022 }
1023
1024 /*@
1025 ISDestroy - Destroys an index set.
1026
1027 Collective
1028
1029 Input Parameter:
1030 . is - the index set
1031
1032 Level: beginner
1033
1034 .seealso: `IS`, `ISCreateGeneral()`, `ISCreateStride()`, `ISCreateBlock()`
1035 @*/
ISDestroy(IS * is)1036 PetscErrorCode ISDestroy(IS *is)
1037 {
1038 PetscFunctionBegin;
1039 if (!*is) PetscFunctionReturn(PETSC_SUCCESS);
1040 PetscValidHeaderSpecific(*is, IS_CLASSID, 1);
1041 if (--((PetscObject)*is)->refct > 0) {
1042 *is = NULL;
1043 PetscFunctionReturn(PETSC_SUCCESS);
1044 }
1045 if ((*is)->complement) {
1046 PetscInt refcnt;
1047 PetscCall(PetscObjectGetReference((PetscObject)((*is)->complement), &refcnt));
1048 PetscCheck(refcnt <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Nonlocal IS has not been restored");
1049 PetscCall(ISDestroy(&(*is)->complement));
1050 }
1051 PetscTryTypeMethod(*is, destroy);
1052 PetscCall(PetscLayoutDestroy(&(*is)->map));
1053 /* Destroy local representations of offproc data. */
1054 PetscCall(PetscFree((*is)->total));
1055 PetscCall(PetscFree((*is)->nonlocal));
1056 PetscCall(PetscHeaderDestroy(is));
1057 PetscFunctionReturn(PETSC_SUCCESS);
1058 }
1059
1060 /*@
1061 ISInvertPermutation - Creates a new permutation that is the inverse of
1062 a given permutation.
1063
1064 Collective
1065
1066 Input Parameters:
1067 + is - the index set
1068 - nlocal - number of indices on this processor in result (ignored for 1 processor) or
1069 use `PETSC_DECIDE`
1070
1071 Output Parameter:
1072 . isout - the inverse permutation
1073
1074 Level: intermediate
1075
1076 Note:
1077 For parallel index sets this does the complete parallel permutation, but the
1078 code is not efficient for huge index sets (10,000,000 indices).
1079
1080 .seealso: `IS`, `ISGetInfo()`, `ISSetPermutation()`, `ISGetPermutation()`
1081 @*/
ISInvertPermutation(IS is,PetscInt nlocal,IS * isout)1082 PetscErrorCode ISInvertPermutation(IS is, PetscInt nlocal, IS *isout)
1083 {
1084 PetscBool isperm, isidentity, issame;
1085
1086 PetscFunctionBegin;
1087 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1088 PetscAssertPointer(isout, 3);
1089 PetscCall(ISGetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_TRUE, &isperm));
1090 PetscCheck(isperm, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_WRONG, "Not a permutation");
1091 PetscCall(ISGetInfo(is, IS_IDENTITY, IS_GLOBAL, PETSC_TRUE, &isidentity));
1092 issame = PETSC_FALSE;
1093 if (isidentity) {
1094 PetscInt n;
1095 PetscBool isallsame;
1096
1097 PetscCall(ISGetLocalSize(is, &n));
1098 issame = (PetscBool)(n == nlocal);
1099 PetscCallMPI(MPIU_Allreduce(&issame, &isallsame, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)is)));
1100 issame = isallsame;
1101 }
1102 if (issame) {
1103 PetscCall(ISDuplicate(is, isout));
1104 } else {
1105 PetscUseTypeMethod(is, invertpermutation, nlocal, isout);
1106 PetscCall(ISSetPermutation(*isout));
1107 }
1108 PetscFunctionReturn(PETSC_SUCCESS);
1109 }
1110
1111 /*@
1112 ISGetSize - Returns the global length of an index set.
1113
1114 Not Collective
1115
1116 Input Parameter:
1117 . is - the index set
1118
1119 Output Parameter:
1120 . size - the global size
1121
1122 Level: beginner
1123
1124 .seealso: `IS`
1125 @*/
ISGetSize(IS is,PetscInt * size)1126 PetscErrorCode ISGetSize(IS is, PetscInt *size)
1127 {
1128 PetscFunctionBegin;
1129 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1130 PetscAssertPointer(size, 2);
1131 *size = is->map->N;
1132 PetscFunctionReturn(PETSC_SUCCESS);
1133 }
1134
1135 /*@
1136 ISGetLocalSize - Returns the local (processor) length of an index set.
1137
1138 Not Collective
1139
1140 Input Parameter:
1141 . is - the index set
1142
1143 Output Parameter:
1144 . size - the local size
1145
1146 Level: beginner
1147
1148 .seealso: `IS`, `ISGetSize()`
1149 @*/
ISGetLocalSize(IS is,PetscInt * size)1150 PetscErrorCode ISGetLocalSize(IS is, PetscInt *size)
1151 {
1152 PetscFunctionBegin;
1153 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1154 PetscAssertPointer(size, 2);
1155 *size = is->map->n;
1156 PetscFunctionReturn(PETSC_SUCCESS);
1157 }
1158
1159 /*@
1160 ISGetLayout - get `PetscLayout` describing index set layout
1161
1162 Not Collective
1163
1164 Input Parameter:
1165 . is - the index set
1166
1167 Output Parameter:
1168 . map - the layout
1169
1170 Level: developer
1171
1172 .seealso: `IS`, `PetscLayout`, `ISSetLayout()`, `ISGetSize()`, `ISGetLocalSize()`
1173 @*/
ISGetLayout(IS is,PetscLayout * map)1174 PetscErrorCode ISGetLayout(IS is, PetscLayout *map)
1175 {
1176 PetscFunctionBegin;
1177 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1178 PetscAssertPointer(map, 2);
1179 *map = is->map;
1180 PetscFunctionReturn(PETSC_SUCCESS);
1181 }
1182
1183 /*@
1184 ISSetLayout - set `PetscLayout` describing index set layout
1185
1186 Collective
1187
1188 Input Parameters:
1189 + is - the index set
1190 - map - the layout
1191
1192 Level: developer
1193
1194 Notes:
1195 Users should typically use higher level functions such as `ISCreateGeneral()`.
1196
1197 This function can be useful in some special cases of constructing a new `IS`, e.g. after `ISCreate()` and before `ISLoad()`.
1198 Otherwise, it is only valid to replace the layout with a layout known to be equivalent.
1199
1200 .seealso: `IS`, `PetscLayout`, `ISCreate()`, `ISGetLayout()`, `ISGetSize()`, `ISGetLocalSize()`
1201 @*/
ISSetLayout(IS is,PetscLayout map)1202 PetscErrorCode ISSetLayout(IS is, PetscLayout map)
1203 {
1204 PetscFunctionBegin;
1205 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1206 PetscAssertPointer(map, 2);
1207 PetscCall(PetscLayoutReference(map, &is->map));
1208 PetscFunctionReturn(PETSC_SUCCESS);
1209 }
1210
1211 /*@C
1212 ISGetIndices - Returns a pointer to the indices. The user should call
1213 `ISRestoreIndices()` after having looked at the indices. The user should
1214 NOT change the indices.
1215
1216 Not Collective
1217
1218 Input Parameter:
1219 . is - the index set
1220
1221 Output Parameter:
1222 . ptr - the location to put the pointer to the indices
1223
1224 Level: intermediate
1225
1226 Fortran Note:
1227 .vb
1228 PetscInt, pointer :: ptr(:)
1229 .ve
1230
1231 .seealso: `IS`, `ISRestoreIndices()`
1232 @*/
ISGetIndices(IS is,const PetscInt * ptr[])1233 PetscErrorCode ISGetIndices(IS is, const PetscInt *ptr[])
1234 {
1235 PetscFunctionBegin;
1236 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1237 PetscAssertPointer(ptr, 2);
1238 PetscUseTypeMethod(is, getindices, ptr);
1239 PetscFunctionReturn(PETSC_SUCCESS);
1240 }
1241
1242 /*@
1243 ISGetMinMax - Gets the minimum and maximum values in an `IS`
1244
1245 Not Collective
1246
1247 Input Parameter:
1248 . is - the index set
1249
1250 Output Parameters:
1251 + min - the minimum value, you may pass `NULL`
1252 - max - the maximum value, you may pass `NULL`
1253
1254 Level: intermediate
1255
1256 Notes:
1257 Empty index sets return min=`PETSC_INT_MAX` and max=`PETSC_INT_MIN`.
1258
1259 In parallel, it returns the `min` and `max` of the local portion of `is`
1260
1261 .seealso: `IS`, `ISGetIndices()`, `ISRestoreIndices()`
1262 @*/
ISGetMinMax(IS is,PetscInt * min,PetscInt * max)1263 PetscErrorCode ISGetMinMax(IS is, PetscInt *min, PetscInt *max)
1264 {
1265 PetscFunctionBegin;
1266 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1267 if (min) *min = is->min;
1268 if (max) *max = is->max;
1269 PetscFunctionReturn(PETSC_SUCCESS);
1270 }
1271
1272 /*@
1273 ISLocate - determine the location of an index within the local component of an index set
1274
1275 Not Collective
1276
1277 Input Parameters:
1278 + is - the index set
1279 - key - the search key
1280
1281 Output Parameter:
1282 . location - if >= 0, a location within the index set that is equal to the key, otherwise the key is not in the index set
1283
1284 Level: intermediate
1285
1286 .seealso: `IS`
1287 @*/
ISLocate(IS is,PetscInt key,PetscInt * location)1288 PetscErrorCode ISLocate(IS is, PetscInt key, PetscInt *location)
1289 {
1290 PetscFunctionBegin;
1291 if (is->ops->locate) {
1292 PetscUseTypeMethod(is, locate, key, location);
1293 } else {
1294 PetscInt numIdx;
1295 PetscBool sorted;
1296 const PetscInt *idx;
1297
1298 PetscCall(ISGetLocalSize(is, &numIdx));
1299 PetscCall(ISGetIndices(is, &idx));
1300 PetscCall(ISSorted(is, &sorted));
1301 if (sorted) {
1302 PetscCall(PetscFindInt(key, numIdx, idx, location));
1303 } else {
1304 PetscInt i;
1305
1306 *location = -1;
1307 for (i = 0; i < numIdx; i++) {
1308 if (idx[i] == key) {
1309 *location = i;
1310 break;
1311 }
1312 }
1313 }
1314 PetscCall(ISRestoreIndices(is, &idx));
1315 }
1316 PetscFunctionReturn(PETSC_SUCCESS);
1317 }
1318
1319 /*@C
1320 ISRestoreIndices - Restores an index set to a usable state after a call to `ISGetIndices()`.
1321
1322 Not Collective
1323
1324 Input Parameters:
1325 + is - the index set
1326 - ptr - the pointer obtained by `ISGetIndices()`
1327
1328 Level: intermediate
1329
1330 Fortran Note:
1331 .vb
1332 PetscInt, pointer :: ptr(:)
1333 .ve
1334
1335 .seealso: `IS`, `ISGetIndices()`
1336 @*/
ISRestoreIndices(IS is,const PetscInt * ptr[])1337 PetscErrorCode ISRestoreIndices(IS is, const PetscInt *ptr[])
1338 {
1339 PetscFunctionBegin;
1340 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1341 PetscAssertPointer(ptr, 2);
1342 PetscTryTypeMethod(is, restoreindices, ptr);
1343 PetscFunctionReturn(PETSC_SUCCESS);
1344 }
1345
ISGatherTotal_Private(IS is)1346 static PetscErrorCode ISGatherTotal_Private(IS is)
1347 {
1348 PetscInt i, n, N;
1349 const PetscInt *lindices;
1350 MPI_Comm comm;
1351 PetscMPIInt rank, size, *sizes = NULL, *offsets = NULL, nn;
1352
1353 PetscFunctionBegin;
1354 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1355
1356 PetscCall(PetscObjectGetComm((PetscObject)is, &comm));
1357 PetscCallMPI(MPI_Comm_size(comm, &size));
1358 PetscCallMPI(MPI_Comm_rank(comm, &rank));
1359 PetscCall(ISGetLocalSize(is, &n));
1360 PetscCall(PetscMalloc2(size, &sizes, size, &offsets));
1361
1362 PetscCall(PetscMPIIntCast(n, &nn));
1363 PetscCallMPI(MPI_Allgather(&nn, 1, MPI_INT, sizes, 1, MPI_INT, comm));
1364 offsets[0] = 0;
1365 for (i = 1; i < size; ++i) offsets[i] = offsets[i - 1] + sizes[i - 1];
1366 N = offsets[size - 1] + sizes[size - 1];
1367
1368 PetscCall(PetscMalloc1(N, &is->total));
1369 PetscCall(ISGetIndices(is, &lindices));
1370 PetscCallMPI(MPI_Allgatherv((void *)lindices, nn, MPIU_INT, is->total, sizes, offsets, MPIU_INT, comm));
1371 PetscCall(ISRestoreIndices(is, &lindices));
1372 is->local_offset = offsets[rank];
1373 PetscCall(PetscFree2(sizes, offsets));
1374 PetscFunctionReturn(PETSC_SUCCESS);
1375 }
1376
1377 /*@C
1378 ISGetTotalIndices - Retrieve an array containing all indices across the communicator.
1379
1380 Collective
1381
1382 Input Parameter:
1383 . is - the index set
1384
1385 Output Parameter:
1386 . indices - total indices with rank 0 indices first, and so on; total array size is
1387 the same as returned with `ISGetSize()`.
1388
1389 Level: intermediate
1390
1391 Notes:
1392 this is potentially nonscalable, but depends on the size of the total index set
1393 and the size of the communicator. This may be feasible for index sets defined on
1394 subcommunicators, such that the set size does not grow with `PETSC_WORLD_COMM`.
1395 Note also that there is no way to tell where the local part of the indices starts
1396 (use `ISGetIndices()` and `ISGetNonlocalIndices()` to retrieve just the local and just
1397 the nonlocal part (complement), respectively).
1398
1399 .seealso: `IS`, `ISRestoreTotalIndices()`, `ISGetNonlocalIndices()`, `ISGetSize()`
1400 @*/
ISGetTotalIndices(IS is,const PetscInt * indices[])1401 PetscErrorCode ISGetTotalIndices(IS is, const PetscInt *indices[])
1402 {
1403 PetscMPIInt size;
1404
1405 PetscFunctionBegin;
1406 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1407 PetscAssertPointer(indices, 2);
1408 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1409 if (size == 1) {
1410 PetscUseTypeMethod(is, getindices, indices);
1411 } else {
1412 if (!is->total) PetscCall(ISGatherTotal_Private(is));
1413 *indices = is->total;
1414 }
1415 PetscFunctionReturn(PETSC_SUCCESS);
1416 }
1417
1418 /*@C
1419 ISRestoreTotalIndices - Restore the index array obtained with `ISGetTotalIndices()`.
1420
1421 Not Collective.
1422
1423 Input Parameters:
1424 + is - the index set
1425 - indices - index array; must be the array obtained with `ISGetTotalIndices()`
1426
1427 Level: intermediate
1428
1429 .seealso: `IS`, `ISGetNonlocalIndices()`
1430 @*/
ISRestoreTotalIndices(IS is,const PetscInt * indices[])1431 PetscErrorCode ISRestoreTotalIndices(IS is, const PetscInt *indices[])
1432 {
1433 PetscMPIInt size;
1434
1435 PetscFunctionBegin;
1436 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1437 PetscAssertPointer(indices, 2);
1438 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1439 if (size == 1) {
1440 PetscUseTypeMethod(is, restoreindices, indices);
1441 } else {
1442 PetscCheck(is->total == *indices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Index array pointer being restored does not point to the array obtained from the IS.");
1443 }
1444 PetscFunctionReturn(PETSC_SUCCESS);
1445 }
1446
1447 /*@C
1448 ISGetNonlocalIndices - Retrieve an array of indices from remote processors
1449 in this communicator.
1450
1451 Collective
1452
1453 Input Parameter:
1454 . is - the index set
1455
1456 Output Parameter:
1457 . indices - indices with rank 0 indices first, and so on, omitting
1458 the current rank. Total number of indices is the difference
1459 total and local, obtained with `ISGetSize()` and `ISGetLocalSize()`,
1460 respectively.
1461
1462 Level: intermediate
1463
1464 Notes:
1465 Restore the indices using `ISRestoreNonlocalIndices()`.
1466
1467 The same scalability considerations as those for `ISGetTotalIndices()` apply here.
1468
1469 .seealso: `IS`, `ISGetTotalIndices()`, `ISRestoreNonlocalIndices()`, `ISGetSize()`, `ISGetLocalSize().`
1470 @*/
ISGetNonlocalIndices(IS is,const PetscInt * indices[])1471 PetscErrorCode ISGetNonlocalIndices(IS is, const PetscInt *indices[])
1472 {
1473 PetscMPIInt size;
1474 PetscInt n, N;
1475
1476 PetscFunctionBegin;
1477 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1478 PetscAssertPointer(indices, 2);
1479 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size));
1480 if (size == 1) *indices = NULL;
1481 else {
1482 if (!is->total) PetscCall(ISGatherTotal_Private(is));
1483 PetscCall(ISGetLocalSize(is, &n));
1484 PetscCall(ISGetSize(is, &N));
1485 PetscCall(PetscMalloc1(N - n, &is->nonlocal));
1486 PetscCall(PetscArraycpy(is->nonlocal, is->total, is->local_offset));
1487 PetscCall(PetscArraycpy(is->nonlocal + is->local_offset, is->total + is->local_offset + n, N - is->local_offset - n));
1488 *indices = is->nonlocal;
1489 }
1490 PetscFunctionReturn(PETSC_SUCCESS);
1491 }
1492
1493 /*@C
1494 ISRestoreNonlocalIndices - Restore the index array obtained with `ISGetNonlocalIndices()`.
1495
1496 Not Collective.
1497
1498 Input Parameters:
1499 + is - the index set
1500 - indices - index array; must be the array obtained with `ISGetNonlocalIndices()`
1501
1502 Level: intermediate
1503
1504 .seealso: `IS`, `ISGetTotalIndices()`, `ISGetNonlocalIndices()`, `ISRestoreTotalIndices()`
1505 @*/
ISRestoreNonlocalIndices(IS is,const PetscInt * indices[])1506 PetscErrorCode ISRestoreNonlocalIndices(IS is, const PetscInt *indices[])
1507 {
1508 PetscFunctionBegin;
1509 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1510 PetscAssertPointer(indices, 2);
1511 PetscCheck(is->nonlocal == *indices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Index array pointer being restored does not point to the array obtained from the IS.");
1512 PetscFunctionReturn(PETSC_SUCCESS);
1513 }
1514
1515 /*@
1516 ISGetNonlocalIS - Gather all nonlocal indices for this `IS` and present
1517 them as another sequential index set.
1518
1519 Collective
1520
1521 Input Parameter:
1522 . is - the index set
1523
1524 Output Parameter:
1525 . complement - sequential `IS` with indices identical to the result of
1526 `ISGetNonlocalIndices()`
1527
1528 Level: intermediate
1529
1530 Notes:
1531 Complement represents the result of `ISGetNonlocalIndices()` as an `IS`.
1532 Therefore scalability issues similar to `ISGetNonlocalIndices()` apply.
1533
1534 The resulting `IS` must be restored using `ISRestoreNonlocalIS()`.
1535
1536 .seealso: `IS`, `ISGetNonlocalIndices()`, `ISRestoreNonlocalIndices()`, `ISAllGather()`, `ISGetSize()`
1537 @*/
ISGetNonlocalIS(IS is,IS * complement)1538 PetscErrorCode ISGetNonlocalIS(IS is, IS *complement)
1539 {
1540 PetscFunctionBegin;
1541 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1542 PetscAssertPointer(complement, 2);
1543 /* Check if the complement exists already. */
1544 if (is->complement) {
1545 *complement = is->complement;
1546 PetscCall(PetscObjectReference((PetscObject)is->complement));
1547 } else {
1548 PetscInt N, n;
1549 const PetscInt *idx;
1550 PetscCall(ISGetSize(is, &N));
1551 PetscCall(ISGetLocalSize(is, &n));
1552 PetscCall(ISGetNonlocalIndices(is, &idx));
1553 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, N - n, idx, PETSC_USE_POINTER, &is->complement));
1554 PetscCall(PetscObjectReference((PetscObject)is->complement));
1555 *complement = is->complement;
1556 }
1557 PetscFunctionReturn(PETSC_SUCCESS);
1558 }
1559
1560 /*@
1561 ISRestoreNonlocalIS - Restore the `IS` obtained with `ISGetNonlocalIS()`.
1562
1563 Not collective.
1564
1565 Input Parameters:
1566 + is - the index set
1567 - complement - index set of `is`'s nonlocal indices
1568
1569 Level: intermediate
1570
1571 .seealso: `IS`, `ISGetNonlocalIS()`, `ISGetNonlocalIndices()`, `ISRestoreNonlocalIndices()`
1572 @*/
ISRestoreNonlocalIS(IS is,IS * complement)1573 PetscErrorCode ISRestoreNonlocalIS(IS is, IS *complement)
1574 {
1575 PetscInt refcnt;
1576
1577 PetscFunctionBegin;
1578 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1579 PetscAssertPointer(complement, 2);
1580 PetscCheck(*complement == is->complement, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Complement IS being restored was not obtained with ISGetNonlocalIS()");
1581 PetscCall(PetscObjectGetReference((PetscObject)is->complement, &refcnt));
1582 PetscCheck(refcnt > 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Duplicate call to ISRestoreNonlocalIS() detected");
1583 PetscCall(PetscObjectDereference((PetscObject)is->complement));
1584 PetscFunctionReturn(PETSC_SUCCESS);
1585 }
1586
1587 /*@
1588 ISViewFromOptions - View an `IS` based on options in the options database
1589
1590 Collective
1591
1592 Input Parameters:
1593 + A - the index set
1594 . obj - Optional object that provides the prefix for the options database
1595 - name - command line option
1596
1597 Level: intermediate
1598
1599 Note:
1600 See `PetscObjectViewFromOptions()` for possible `PetscViewer` and `PetscViewerFormat` values
1601
1602 .seealso: `IS`, `ISView()`, `PetscObjectViewFromOptions()`, `ISCreate()`
1603 @*/
ISViewFromOptions(IS A,PetscObject obj,const char name[])1604 PetscErrorCode ISViewFromOptions(IS A, PetscObject obj, const char name[])
1605 {
1606 PetscFunctionBegin;
1607 PetscValidHeaderSpecific(A, IS_CLASSID, 1);
1608 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1609 PetscFunctionReturn(PETSC_SUCCESS);
1610 }
1611
1612 /*@
1613 ISView - Displays an index set.
1614
1615 Collective
1616
1617 Input Parameters:
1618 + is - the index set
1619 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`.
1620
1621 Level: intermediate
1622
1623 .seealso: `IS`, `PetscViewer`, `PetscViewerASCIIOpen()`, `ISViewFromOptions()`
1624 @*/
ISView(IS is,PetscViewer viewer)1625 PetscErrorCode ISView(IS is, PetscViewer viewer)
1626 {
1627 PetscFunctionBegin;
1628 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1629 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)is), &viewer));
1630 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1631 PetscCheckSameComm(is, 1, viewer, 2);
1632
1633 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)is, viewer));
1634 PetscCall(PetscLogEventBegin(IS_View, is, viewer, 0, 0));
1635 PetscUseTypeMethod(is, view, viewer);
1636 PetscCall(PetscLogEventEnd(IS_View, is, viewer, 0, 0));
1637 PetscFunctionReturn(PETSC_SUCCESS);
1638 }
1639
1640 /*@
1641 ISLoad - Loads an index set that has been stored in binary or HDF5 format with `ISView()`.
1642
1643 Collective
1644
1645 Input Parameters:
1646 + is - the newly loaded index set, this needs to have been created with `ISCreate()` or some related function before a call to `ISLoad()`.
1647 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or HDF5 file viewer, obtained from `PetscViewerHDF5Open()`
1648
1649 Level: intermediate
1650
1651 Notes:
1652 IF using HDF5, you must assign the IS the same name as was used in `is`
1653 that was stored in the file using `PetscObjectSetName()`. Otherwise you will
1654 get the error message: "Cannot H5DOpen2() with Vec name NAMEOFOBJECT"
1655
1656 .seealso: `IS`, `PetscViewerBinaryOpen()`, `ISView()`, `MatLoad()`, `VecLoad()`
1657 @*/
ISLoad(IS is,PetscViewer viewer)1658 PetscErrorCode ISLoad(IS is, PetscViewer viewer)
1659 {
1660 PetscBool isbinary, ishdf5;
1661
1662 PetscFunctionBegin;
1663 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1664 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1665 PetscCheckSameComm(is, 1, viewer, 2);
1666 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
1667 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1668 PetscCheck(isbinary || ishdf5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen()");
1669 if (!((PetscObject)is)->type_name) PetscCall(ISSetType(is, ISGENERAL));
1670 PetscCall(PetscLogEventBegin(IS_Load, is, viewer, 0, 0));
1671 PetscUseTypeMethod(is, load, viewer);
1672 PetscCall(PetscLogEventEnd(IS_Load, is, viewer, 0, 0));
1673 PetscFunctionReturn(PETSC_SUCCESS);
1674 }
1675
1676 /*@
1677 ISSort - Sorts the indices of an index set.
1678
1679 Collective
1680
1681 Input Parameter:
1682 . is - the index set
1683
1684 Level: intermediate
1685
1686 .seealso: `IS`, `ISSortRemoveDups()`, `ISSorted()`
1687 @*/
ISSort(IS is)1688 PetscErrorCode ISSort(IS is)
1689 {
1690 PetscBool flg;
1691
1692 PetscFunctionBegin;
1693 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1694 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_FALSE, &flg));
1695 if (!flg) {
1696 PetscUseTypeMethod(is, sort);
1697 PetscCall(ISSetInfo(is, IS_SORTED, IS_LOCAL, is->info_permanent[IS_LOCAL][IS_SORTED], PETSC_TRUE));
1698 }
1699 PetscFunctionReturn(PETSC_SUCCESS);
1700 }
1701
1702 /*@
1703 ISSortRemoveDups - Sorts the indices of an index set, removing duplicates.
1704
1705 Collective
1706
1707 Input Parameter:
1708 . is - the index set
1709
1710 Level: intermediate
1711
1712 .seealso: `IS`, `ISSort()`, `ISSorted()`
1713 @*/
ISSortRemoveDups(IS is)1714 PetscErrorCode ISSortRemoveDups(IS is)
1715 {
1716 PetscFunctionBegin;
1717 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1718 PetscCall(ISClearInfoCache(is, PETSC_FALSE));
1719 PetscUseTypeMethod(is, sortremovedups);
1720 PetscCall(ISSetInfo(is, IS_SORTED, IS_LOCAL, is->info_permanent[IS_LOCAL][IS_SORTED], PETSC_TRUE));
1721 PetscCall(ISSetInfo(is, IS_UNIQUE, IS_LOCAL, is->info_permanent[IS_LOCAL][IS_UNIQUE], PETSC_TRUE));
1722 PetscFunctionReturn(PETSC_SUCCESS);
1723 }
1724
1725 /*@
1726 ISToGeneral - Converts an IS object of any type to `ISGENERAL` type
1727
1728 Collective
1729
1730 Input Parameter:
1731 . is - the index set
1732
1733 Level: intermediate
1734
1735 .seealso: `IS`, `ISSorted()`
1736 @*/
ISToGeneral(IS is)1737 PetscErrorCode ISToGeneral(IS is)
1738 {
1739 PetscFunctionBegin;
1740 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1741 PetscUseTypeMethod(is, togeneral);
1742 PetscFunctionReturn(PETSC_SUCCESS);
1743 }
1744
1745 /*@
1746 ISSorted - Checks the indices to determine whether they have been sorted.
1747
1748 Not Collective
1749
1750 Input Parameter:
1751 . is - the index set
1752
1753 Output Parameter:
1754 . flg - output flag, either `PETSC_TRUE` if the index set is sorted,
1755 or `PETSC_FALSE` otherwise.
1756
1757 Level: intermediate
1758
1759 Note:
1760 For parallel IS objects this only indicates if the local part of `is`
1761 is sorted. So some processors may return `PETSC_TRUE` while others may
1762 return `PETSC_FALSE`.
1763
1764 .seealso: `ISSort()`, `ISSortRemoveDups()`
1765 @*/
ISSorted(IS is,PetscBool * flg)1766 PetscErrorCode ISSorted(IS is, PetscBool *flg)
1767 {
1768 PetscFunctionBegin;
1769 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1770 PetscAssertPointer(flg, 2);
1771 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, flg));
1772 PetscFunctionReturn(PETSC_SUCCESS);
1773 }
1774
1775 /*@
1776 ISDuplicate - Creates a duplicate copy of an index set.
1777
1778 Collective
1779
1780 Input Parameter:
1781 . is - the index set
1782
1783 Output Parameter:
1784 . newIS - the copy of the index set
1785
1786 Level: beginner
1787
1788 .seealso: `IS`, `ISCreateGeneral()`, `ISCopy()`
1789 @*/
ISDuplicate(IS is,IS * newIS)1790 PetscErrorCode ISDuplicate(IS is, IS *newIS)
1791 {
1792 PetscFunctionBegin;
1793 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1794 PetscAssertPointer(newIS, 2);
1795 PetscUseTypeMethod(is, duplicate, newIS);
1796 PetscCall(ISCopyInfo_Private(is, *newIS));
1797 PetscFunctionReturn(PETSC_SUCCESS);
1798 }
1799
1800 /*@
1801 ISCopy - Copies an index set.
1802
1803 Collective
1804
1805 Input Parameter:
1806 . is - the index set
1807
1808 Output Parameter:
1809 . isy - the copy of the index set
1810
1811 Level: beginner
1812
1813 .seealso: `IS`, `ISDuplicate()`, `ISShift()`
1814 @*/
ISCopy(IS is,IS isy)1815 PetscErrorCode ISCopy(IS is, IS isy)
1816 {
1817 PetscInt bs, bsy;
1818
1819 PetscFunctionBegin;
1820 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1821 PetscValidHeaderSpecific(isy, IS_CLASSID, 2);
1822 PetscCheckSameComm(is, 1, isy, 2);
1823 if (is == isy) PetscFunctionReturn(PETSC_SUCCESS);
1824 PetscCall(PetscLayoutGetBlockSize(is->map, &bs));
1825 PetscCall(PetscLayoutGetBlockSize(isy->map, &bsy));
1826 PetscCheck(is->map->N == isy->map->N, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_INCOMP, "Index sets have different global size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->N, isy->map->N);
1827 PetscCheck(is->map->n == isy->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different local size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->n, isy->map->n);
1828 PetscCheck(bs == bsy, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different block size %" PetscInt_FMT " != %" PetscInt_FMT, bs, bsy);
1829 PetscCall(ISCopyInfo_Private(is, isy));
1830 isy->max = is->max;
1831 isy->min = is->min;
1832 PetscUseTypeMethod(is, copy, isy);
1833 PetscFunctionReturn(PETSC_SUCCESS);
1834 }
1835
1836 /*@
1837 ISShift - Shift all indices by given offset
1838
1839 Collective
1840
1841 Input Parameters:
1842 + is - the index set
1843 - offset - the offset
1844
1845 Output Parameter:
1846 . isy - the shifted copy of the input index set
1847
1848 Level: beginner
1849
1850 Notes:
1851 The `offset` can be different across processes.
1852
1853 `is` and `isy` can be the same.
1854
1855 .seealso: `ISDuplicate()`, `ISCopy()`
1856 @*/
ISShift(IS is,PetscInt offset,IS isy)1857 PetscErrorCode ISShift(IS is, PetscInt offset, IS isy)
1858 {
1859 PetscFunctionBegin;
1860 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1861 PetscValidHeaderSpecific(isy, IS_CLASSID, 3);
1862 PetscCheckSameComm(is, 1, isy, 3);
1863 if (!offset) {
1864 PetscCall(ISCopy(is, isy));
1865 PetscFunctionReturn(PETSC_SUCCESS);
1866 }
1867 PetscCheck(is->map->N == isy->map->N, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_INCOMP, "Index sets have different global size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->N, isy->map->N);
1868 PetscCheck(is->map->n == isy->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different local size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->n, isy->map->n);
1869 PetscCheck(is->map->bs == isy->map->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Index sets have different block size %" PetscInt_FMT " != %" PetscInt_FMT, is->map->bs, isy->map->bs);
1870 PetscCall(ISCopyInfo_Private(is, isy));
1871 isy->max = is->max + offset;
1872 isy->min = is->min + offset;
1873 PetscUseMethod(is, "ISShift_C", (IS, PetscInt, IS), (is, offset, isy));
1874 PetscFunctionReturn(PETSC_SUCCESS);
1875 }
1876
1877 /*@
1878 ISOnComm - Split a parallel `IS` on subcomms (usually self) or concatenate index sets on subcomms into a parallel index set
1879
1880 Collective
1881
1882 Input Parameters:
1883 + is - index set
1884 . comm - communicator for new index set
1885 - mode - copy semantics, `PETSC_USE_POINTER` for no-copy if possible, otherwise `PETSC_COPY_VALUES`
1886
1887 Output Parameter:
1888 . newis - new `IS` on `comm`
1889
1890 Level: advanced
1891
1892 Notes:
1893 It is usually desirable to create a parallel `IS` and look at the local part when necessary.
1894
1895 This function is useful if serial `IS`s must be created independently, or to view many
1896 logically independent serial `IS`s.
1897
1898 The input `IS` must have the same type on every MPI process.
1899
1900 .seealso: `IS`
1901 @*/
ISOnComm(IS is,MPI_Comm comm,PetscCopyMode mode,IS * newis)1902 PetscErrorCode ISOnComm(IS is, MPI_Comm comm, PetscCopyMode mode, IS *newis)
1903 {
1904 PetscMPIInt match;
1905
1906 PetscFunctionBegin;
1907 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1908 PetscAssertPointer(newis, 4);
1909 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)is), comm, &match));
1910 if (mode != PETSC_COPY_VALUES && (match == MPI_IDENT || match == MPI_CONGRUENT)) {
1911 PetscCall(PetscObjectReference((PetscObject)is));
1912 *newis = is;
1913 } else PetscUseTypeMethod(is, oncomm, comm, mode, newis);
1914 PetscFunctionReturn(PETSC_SUCCESS);
1915 }
1916
1917 /*@
1918 ISSetBlockSize - informs an index set that it has a given block size
1919
1920 Logicall Collective
1921
1922 Input Parameters:
1923 + is - index set
1924 - bs - block size
1925
1926 Level: intermediate
1927
1928 Notes:
1929 This is much like the block size for `Vec`s. It indicates that one can think of the indices as
1930 being in a collection of equal size blocks. For `ISBLOCK` these collections of blocks are all contiguous
1931 within a block but this is not the case for other `IS`. For example, an `IS` with entries {0, 2, 3, 4, 6, 7} could
1932 have a block size of three set.
1933
1934 `ISBlockGetIndices()` only works for `ISBLOCK`, not others.
1935
1936 .seealso: `IS`, `ISGetBlockSize()`, `ISCreateBlock()`, `ISBlockGetIndices()`,
1937 @*/
ISSetBlockSize(IS is,PetscInt bs)1938 PetscErrorCode ISSetBlockSize(IS is, PetscInt bs)
1939 {
1940 PetscFunctionBegin;
1941 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
1942 PetscValidLogicalCollectiveInt(is, bs, 2);
1943 PetscCheck(bs >= 1, PetscObjectComm((PetscObject)is), PETSC_ERR_ARG_OUTOFRANGE, "Block size %" PetscInt_FMT ", must be positive", bs);
1944 if (PetscDefined(USE_DEBUG)) {
1945 const PetscInt *indices;
1946 PetscInt length, i, j;
1947 PetscCall(ISGetIndices(is, &indices));
1948 if (indices) {
1949 PetscCall(ISGetLocalSize(is, &length));
1950 PetscCheck(length % bs == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local size %" PetscInt_FMT " not compatible with proposed block size %" PetscInt_FMT, length, bs);
1951 for (i = 1; i < length / bs; i += bs) {
1952 for (j = 1; j < bs - 1; j++) {
1953 PetscCheck(indices[i * bs + j] == indices[(i - 1) * bs + j] + indices[i * bs] - indices[(i - 1) * bs], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Proposed block size %" PetscInt_FMT " is incompatible with the indices", bs);
1954 }
1955 }
1956 }
1957 PetscCall(ISRestoreIndices(is, &indices));
1958 }
1959 PetscUseTypeMethod(is, setblocksize, bs);
1960 PetscFunctionReturn(PETSC_SUCCESS);
1961 }
1962
1963 /*@
1964 ISGetBlockSize - Returns the number of elements in a block.
1965
1966 Not Collective
1967
1968 Input Parameter:
1969 . is - the index set
1970
1971 Output Parameter:
1972 . size - the number of elements in a block
1973
1974 Level: intermediate
1975
1976 Note:
1977 See `ISSetBlockSize()`
1978
1979 .seealso: `IS`, `ISBlockGetSize()`, `ISGetSize()`, `ISCreateBlock()`, `ISSetBlockSize()`
1980 @*/
ISGetBlockSize(IS is,PetscInt * size)1981 PetscErrorCode ISGetBlockSize(IS is, PetscInt *size)
1982 {
1983 PetscFunctionBegin;
1984 PetscCall(PetscLayoutGetBlockSize(is->map, size));
1985 PetscFunctionReturn(PETSC_SUCCESS);
1986 }
1987
1988 /*@
1989 ISSetCompressOutput - set the flag for output compression
1990
1991 Logicall Collective
1992
1993 Input Parameters:
1994 + is - index set
1995 - compress - flag for output compression
1996
1997 Level: intermediate
1998
1999 .seealso: `IS`, `ISGetCompressOutput()`, `ISView()`
2000 @*/
ISSetCompressOutput(IS is,PetscBool compress)2001 PetscErrorCode ISSetCompressOutput(IS is, PetscBool compress)
2002 {
2003 PetscFunctionBegin;
2004 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
2005 PetscValidLogicalCollectiveBool(is, compress, 2);
2006 is->compressOutput = compress;
2007 PetscFunctionReturn(PETSC_SUCCESS);
2008 }
2009
2010 /*@
2011 ISGetCompressOutput - Returns the flag for output compression
2012
2013 Not Collective
2014
2015 Input Parameter:
2016 . is - the index set
2017
2018 Output Parameter:
2019 . compress - the flag to compress output
2020
2021 Level: intermediate
2022
2023 .seealso: `IS`, `ISSetCompressOutput()`, `ISView()`
2024 @*/
ISGetCompressOutput(IS is,PetscBool * compress)2025 PetscErrorCode ISGetCompressOutput(IS is, PetscBool *compress)
2026 {
2027 PetscFunctionBegin;
2028 PetscValidHeaderSpecific(is, IS_CLASSID, 1);
2029 PetscAssertPointer(compress, 2);
2030 *compress = is->compressOutput;
2031 PetscFunctionReturn(PETSC_SUCCESS);
2032 }
2033
ISGetIndicesCopy_Private(IS is,PetscInt idx[])2034 static PetscErrorCode ISGetIndicesCopy_Private(IS is, PetscInt idx[])
2035 {
2036 PetscInt len, i;
2037 const PetscInt *ptr;
2038
2039 PetscFunctionBegin;
2040 PetscCall(ISGetLocalSize(is, &len));
2041 PetscCall(ISGetIndices(is, &ptr));
2042 for (i = 0; i < len; i++) idx[i] = ptr[i];
2043 PetscCall(ISRestoreIndices(is, &ptr));
2044 PetscFunctionReturn(PETSC_SUCCESS);
2045 }
2046