xref: /petsc/src/vec/vec/utils/vinv.c (revision 83c9f7f220f3448cfcd2a76a64462ac242b37309)
1 
2 /*
3      Some useful vector utility functions.
4 */
5 #include <../src/vec/vec/impls/mpi/pvecimpl.h> /*I "petscvec.h" I*/
6 
7 /*@
8    VecStrideSet - Sets a subvector of a vector defined
9    by a starting point and a stride with a given value
10 
11    Logically Collective on Vec
12 
13    Input Parameters:
14 +  v - the vector
15 .  start - starting point of the subvector (defined by a stride)
16 -  s - value to set for each entry in that subvector
17 
18    Notes:
19    One must call VecSetBlockSize() before this routine to set the stride
20    information, or use a vector created from a multicomponent DMDA.
21 
22    This will only work if the desire subvector is a stride subvector
23 
24    Level: advanced
25 
26 .seealso: `VecNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideScale()`
27 @*/
28 PetscErrorCode VecStrideSet(Vec v, PetscInt start, PetscScalar s) {
29   PetscInt     i, n, bs;
30   PetscScalar *x;
31 
32   PetscFunctionBegin;
33   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
34   PetscCall(VecGetLocalSize(v, &n));
35   PetscCall(VecGetBlockSize(v, &bs));
36   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
37   PetscCheck(start < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\n  Have you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start, bs);
38   PetscCall(VecGetArray(v, &x));
39   for (i = start; i < n; i += bs) x[i] = s;
40   PetscCall(VecRestoreArray(v, &x));
41   PetscFunctionReturn(0);
42 }
43 
44 /*@
45    VecStrideScale - Scales a subvector of a vector defined
46    by a starting point and a stride.
47 
48    Logically Collective on Vec
49 
50    Input Parameters:
51 +  v - the vector
52 .  start - starting point of the subvector (defined by a stride)
53 -  scale - value to multiply each subvector entry by
54 
55    Notes:
56    One must call VecSetBlockSize() before this routine to set the stride
57    information, or use a vector created from a multicomponent DMDA.
58 
59    This will only work if the desire subvector is a stride subvector
60 
61    Level: advanced
62 
63 .seealso: `VecNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideScale()`
64 @*/
65 PetscErrorCode VecStrideScale(Vec v, PetscInt start, PetscScalar scale) {
66   PetscInt     i, n, bs;
67   PetscScalar *x;
68 
69   PetscFunctionBegin;
70   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
71   PetscCall(VecGetLocalSize(v, &n));
72   PetscCall(VecGetBlockSize(v, &bs));
73   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
74   PetscCheck(start < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\n  Have you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start, bs);
75   PetscCall(VecGetArray(v, &x));
76   for (i = start; i < n; i += bs) x[i] *= scale;
77   PetscCall(VecRestoreArray(v, &x));
78   PetscFunctionReturn(0);
79 }
80 
81 /*@
82    VecStrideNorm - Computes the norm of subvector of a vector defined
83    by a starting point and a stride.
84 
85    Collective on Vec
86 
87    Input Parameters:
88 +  v - the vector
89 .  start - starting point of the subvector (defined by a stride)
90 -  ntype - type of norm, one of NORM_1, NORM_2, NORM_INFINITY
91 
92    Output Parameter:
93 .  norm - the norm
94 
95    Notes:
96    One must call VecSetBlockSize() before this routine to set the stride
97    information, or use a vector created from a multicomponent DMDA.
98 
99    If x is the array representing the vector x then this computes the norm
100    of the array (x[start],x[start+stride],x[start+2*stride], ....)
101 
102    This is useful for computing, say the norm of the pressure variable when
103    the pressure is stored (interlaced) with other variables, say density etc.
104 
105    This will only work if the desire subvector is a stride subvector
106 
107    Level: advanced
108 
109 .seealso: `VecNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`
110 @*/
111 PetscErrorCode VecStrideNorm(Vec v, PetscInt start, NormType ntype, PetscReal *nrm) {
112   PetscInt           i, n, bs;
113   const PetscScalar *x;
114   PetscReal          tnorm;
115 
116   PetscFunctionBegin;
117   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
118   PetscValidLogicalCollectiveEnum(v, ntype, 3);
119   PetscValidRealPointer(nrm, 4);
120   PetscCall(VecGetLocalSize(v, &n));
121   PetscCall(VecGetBlockSize(v, &bs));
122   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
123   PetscCheck(start < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\n Have you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start, bs);
124   PetscCall(VecGetArrayRead(v, &x));
125   if (ntype == NORM_2) {
126     PetscScalar sum = 0.0;
127     for (i = start; i < n; i += bs) sum += x[i] * (PetscConj(x[i]));
128     tnorm = PetscRealPart(sum);
129     PetscCall(MPIU_Allreduce(&tnorm, nrm, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)v)));
130     *nrm = PetscSqrtReal(*nrm);
131   } else if (ntype == NORM_1) {
132     tnorm = 0.0;
133     for (i = start; i < n; i += bs) tnorm += PetscAbsScalar(x[i]);
134     PetscCall(MPIU_Allreduce(&tnorm, nrm, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)v)));
135   } else if (ntype == NORM_INFINITY) {
136     tnorm = 0.0;
137     for (i = start; i < n; i += bs) {
138       if (PetscAbsScalar(x[i]) > tnorm) tnorm = PetscAbsScalar(x[i]);
139     }
140     PetscCall(MPIU_Allreduce(&tnorm, nrm, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)v)));
141   } else SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown norm type");
142   PetscCall(VecRestoreArrayRead(v, &x));
143   PetscFunctionReturn(0);
144 }
145 
146 /*@
147    VecStrideMax - Computes the maximum of subvector of a vector defined
148    by a starting point and a stride and optionally its location.
149 
150    Collective on Vec
151 
152    Input Parameters:
153 +  v - the vector
154 -  start - starting point of the subvector (defined by a stride)
155 
156    Output Parameters:
157 +  idex - the location where the maximum occurred  (pass NULL if not required)
158 -  nrm - the maximum value in the subvector
159 
160    Notes:
161    One must call VecSetBlockSize() before this routine to set the stride
162    information, or use a vector created from a multicomponent DMDA.
163 
164    If xa is the array representing the vector x, then this computes the max
165    of the array (xa[start],xa[start+stride],xa[start+2*stride], ....)
166 
167    This is useful for computing, say the maximum of the pressure variable when
168    the pressure is stored (interlaced) with other variables, e.g., density, etc.
169    This will only work if the desire subvector is a stride subvector.
170 
171    Level: advanced
172 
173 .seealso: `VecMax()`, `VecStrideNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`
174 @*/
175 PetscErrorCode VecStrideMax(Vec v, PetscInt start, PetscInt *idex, PetscReal *nrm) {
176   PetscInt           i, n, bs, id = -1;
177   const PetscScalar *x;
178   PetscReal          max = PETSC_MIN_REAL;
179 
180   PetscFunctionBegin;
181   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
182   PetscValidRealPointer(nrm, 4);
183   PetscCall(VecGetLocalSize(v, &n));
184   PetscCall(VecGetBlockSize(v, &bs));
185   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
186   PetscCheck(start < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\n Have you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start, bs);
187   PetscCall(VecGetArrayRead(v, &x));
188   for (i = start; i < n; i += bs) {
189     if (PetscRealPart(x[i]) > max) {
190       max = PetscRealPart(x[i]);
191       id  = i;
192     }
193   }
194   PetscCall(VecRestoreArrayRead(v, &x));
195 #if defined(PETSC_HAVE_MPIUNI)
196   *nrm = max;
197   if (idex) *idex = id;
198 #else
199   if (!idex) {
200     PetscCall(MPIU_Allreduce(&max, nrm, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)v)));
201   } else {
202     struct {
203       PetscReal v;
204       PetscInt  i;
205     } in, out;
206     PetscInt rstart;
207 
208     PetscCall(VecGetOwnershipRange(v, &rstart, NULL));
209     in.v = max;
210     in.i = rstart + id;
211     PetscCall(MPIU_Allreduce(&in, &out, 1, MPIU_REAL_INT, MPIU_MAXLOC, PetscObjectComm((PetscObject)v)));
212     *nrm  = out.v;
213     *idex = out.i;
214   }
215 #endif
216   PetscFunctionReturn(0);
217 }
218 
219 /*@
220    VecStrideMin - Computes the minimum of subvector of a vector defined
221    by a starting point and a stride and optionally its location.
222 
223    Collective on Vec
224 
225    Input Parameters:
226 +  v - the vector
227 -  start - starting point of the subvector (defined by a stride)
228 
229    Output Parameters:
230 +  idex - the location where the minimum occurred. (pass NULL if not required)
231 -  nrm - the minimum value in the subvector
232 
233    Level: advanced
234 
235    Notes:
236    One must call VecSetBlockSize() before this routine to set the stride
237    information, or use a vector created from a multicomponent DMDA.
238 
239    If xa is the array representing the vector x, then this computes the min
240    of the array (xa[start],xa[start+stride],xa[start+2*stride], ....)
241 
242    This is useful for computing, say the minimum of the pressure variable when
243    the pressure is stored (interlaced) with other variables, e.g., density, etc.
244    This will only work if the desire subvector is a stride subvector.
245 
246 .seealso: `VecMin()`, `VecStrideNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMax()`
247 @*/
248 PetscErrorCode VecStrideMin(Vec v, PetscInt start, PetscInt *idex, PetscReal *nrm) {
249   PetscInt           i, n, bs, id = -1;
250   const PetscScalar *x;
251   PetscReal          min = PETSC_MAX_REAL;
252 
253   PetscFunctionBegin;
254   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
255   PetscValidRealPointer(nrm, 4);
256   PetscCall(VecGetLocalSize(v, &n));
257   PetscCall(VecGetBlockSize(v, &bs));
258   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
259   PetscCheck(start < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\nHave you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start, bs);
260   PetscCall(VecGetArrayRead(v, &x));
261   for (i = start; i < n; i += bs) {
262     if (PetscRealPart(x[i]) < min) {
263       min = PetscRealPart(x[i]);
264       id  = i;
265     }
266   }
267   PetscCall(VecRestoreArrayRead(v, &x));
268 #if defined(PETSC_HAVE_MPIUNI)
269   *nrm = min;
270   if (idex) *idex = id;
271 #else
272   if (!idex) {
273     PetscCall(MPIU_Allreduce(&min, nrm, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)v)));
274   } else {
275     struct {
276       PetscReal v;
277       PetscInt  i;
278     } in, out;
279     PetscInt rstart;
280 
281     PetscCall(VecGetOwnershipRange(v, &rstart, NULL));
282     in.v = min;
283     in.i = rstart + id;
284     PetscCall(MPIU_Allreduce(&in, &out, 1, MPIU_REAL_INT, MPIU_MINLOC, PetscObjectComm((PetscObject)v)));
285     *nrm  = out.v;
286     *idex = out.i;
287   }
288 #endif
289   PetscFunctionReturn(0);
290 }
291 
292 /*@
293    VecStrideSum - Computes the sum of subvector of a vector defined
294    by a starting point and a stride.
295 
296    Collective on v
297 
298    Input Parameters:
299 +  v - the vector
300 -  start - starting point of the subvector (defined by a stride)
301 
302    Output Parameter:
303 .  sum - the sum
304 
305    Notes:
306    One must call `VecSetBlockSize()` before this routine to set the stride
307    information, or use a vector created from a multicomponent `DMDA`.
308 
309    If x is the array representing the vector x then this computes the sum
310    of the array (x[start],x[start+stride],x[start+2*stride], ....)
311 
312    Level: advanced
313 
314 .seealso: `VecSum()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`
315 @*/
316 PetscErrorCode VecStrideSum(Vec v, PetscInt start, PetscScalar *sum) {
317   PetscInt           i, n, bs;
318   const PetscScalar *x;
319   PetscScalar        local_sum = 0.0;
320 
321   PetscFunctionBegin;
322   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
323   PetscValidScalarPointer(sum, 3);
324   PetscCall(VecGetLocalSize(v, &n));
325   PetscCall(VecGetBlockSize(v, &bs));
326   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
327   PetscCheck(start < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\n Have you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start, bs);
328   PetscCall(VecGetArrayRead(v, &x));
329   for (i = start; i < n; i += bs) local_sum += x[i];
330   PetscCall(MPIU_Allreduce(&local_sum, sum, 1, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)v)));
331   PetscCall(VecRestoreArrayRead(v, &x));
332   PetscFunctionReturn(0);
333 }
334 
335 /*@
336    VecStrideScaleAll - Scales the subvectors of a vector defined
337    by a starting point and a stride.
338 
339    Logically Collective on Vec
340 
341    Input Parameters:
342 +  v - the vector
343 -  scales - values to multiply each subvector entry by
344 
345    Notes:
346    One must call VecSetBlockSize() before this routine to set the stride
347    information, or use a vector created from a multicomponent DMDA.
348 
349    The dimension of scales must be the same as the vector block size
350 
351    Level: advanced
352 
353 .seealso: `VecNorm()`, `VecStrideScale()`, `VecScale()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`
354 @*/
355 PetscErrorCode VecStrideScaleAll(Vec v, const PetscScalar *scales) {
356   PetscInt     i, j, n, bs;
357   PetscScalar *x;
358 
359   PetscFunctionBegin;
360   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
361   PetscValidScalarPointer(scales, 2);
362   PetscCall(VecGetLocalSize(v, &n));
363   PetscCall(VecGetBlockSize(v, &bs));
364   PetscCall(VecGetArray(v, &x));
365   /* need to provide optimized code for each bs */
366   for (i = 0; i < n; i += bs) {
367     for (j = 0; j < bs; j++) x[i + j] *= scales[j];
368   }
369   PetscCall(VecRestoreArray(v, &x));
370   PetscFunctionReturn(0);
371 }
372 
373 /*@
374    VecStrideNormAll - Computes the norms of subvectors of a vector defined
375    by a starting point and a stride.
376 
377    Collective on Vec
378 
379    Input Parameters:
380 +  v - the vector
381 -  ntype - type of norm, one of NORM_1, NORM_2, NORM_INFINITY
382 
383    Output Parameter:
384 .  nrm - the norms
385 
386    Notes:
387    One must call VecSetBlockSize() before this routine to set the stride
388    information, or use a vector created from a multicomponent DMDA.
389 
390    If x is the array representing the vector x then this computes the norm
391    of the array (x[start],x[start+stride],x[start+2*stride], ....) for each start < stride
392 
393    The dimension of nrm must be the same as the vector block size
394 
395    This will only work if the desire subvector is a stride subvector
396 
397    Level: advanced
398 
399 .seealso: `VecNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`
400 @*/
401 PetscErrorCode VecStrideNormAll(Vec v, NormType ntype, PetscReal nrm[]) {
402   PetscInt           i, j, n, bs;
403   const PetscScalar *x;
404   PetscReal          tnorm[128];
405   MPI_Comm           comm;
406 
407   PetscFunctionBegin;
408   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
409   PetscValidLogicalCollectiveEnum(v, ntype, 2);
410   PetscValidRealPointer(nrm, 3);
411   PetscCall(VecGetLocalSize(v, &n));
412   PetscCall(VecGetArrayRead(v, &x));
413   PetscCall(PetscObjectGetComm((PetscObject)v, &comm));
414 
415   PetscCall(VecGetBlockSize(v, &bs));
416   PetscCheck(bs <= 128, comm, PETSC_ERR_SUP, "Currently supports only blocksize up to 128");
417 
418   if (ntype == NORM_2) {
419     PetscScalar sum[128];
420     for (j = 0; j < bs; j++) sum[j] = 0.0;
421     for (i = 0; i < n; i += bs) {
422       for (j = 0; j < bs; j++) sum[j] += x[i + j] * (PetscConj(x[i + j]));
423     }
424     for (j = 0; j < bs; j++) tnorm[j] = PetscRealPart(sum[j]);
425 
426     PetscCall(MPIU_Allreduce(tnorm, nrm, bs, MPIU_REAL, MPIU_SUM, comm));
427     for (j = 0; j < bs; j++) nrm[j] = PetscSqrtReal(nrm[j]);
428   } else if (ntype == NORM_1) {
429     for (j = 0; j < bs; j++) tnorm[j] = 0.0;
430 
431     for (i = 0; i < n; i += bs) {
432       for (j = 0; j < bs; j++) tnorm[j] += PetscAbsScalar(x[i + j]);
433     }
434 
435     PetscCall(MPIU_Allreduce(tnorm, nrm, bs, MPIU_REAL, MPIU_SUM, comm));
436   } else if (ntype == NORM_INFINITY) {
437     PetscReal tmp;
438     for (j = 0; j < bs; j++) tnorm[j] = 0.0;
439 
440     for (i = 0; i < n; i += bs) {
441       for (j = 0; j < bs; j++) {
442         if ((tmp = PetscAbsScalar(x[i + j])) > tnorm[j]) tnorm[j] = tmp;
443         /* check special case of tmp == NaN */
444         if (tmp != tmp) {
445           tnorm[j] = tmp;
446           break;
447         }
448       }
449     }
450     PetscCall(MPIU_Allreduce(tnorm, nrm, bs, MPIU_REAL, MPIU_MAX, comm));
451   } else SETERRQ(comm, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown norm type");
452   PetscCall(VecRestoreArrayRead(v, &x));
453   PetscFunctionReturn(0);
454 }
455 
456 /*@
457    VecStrideMaxAll - Computes the maximums of subvectors of a vector defined
458    by a starting point and a stride and optionally its location.
459 
460    Collective on Vec
461 
462    Input Parameter:
463 .  v - the vector
464 
465    Output Parameters:
466 +  index - the location where the maximum occurred (not supported, pass NULL,
467            if you need this, send mail to petsc-maint@mcs.anl.gov to request it)
468 -  nrm - the maximum values of each subvector
469 
470    Notes:
471    One must call VecSetBlockSize() before this routine to set the stride
472    information, or use a vector created from a multicomponent DMDA.
473 
474    The dimension of nrm must be the same as the vector block size
475 
476    Level: advanced
477 
478 .seealso: `VecMax()`, `VecStrideNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`
479 @*/
480 PetscErrorCode VecStrideMaxAll(Vec v, PetscInt idex[], PetscReal nrm[]) {
481   PetscInt           i, j, n, bs;
482   const PetscScalar *x;
483   PetscReal          max[128], tmp;
484   MPI_Comm           comm;
485 
486   PetscFunctionBegin;
487   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
488   PetscValidRealPointer(nrm, 3);
489   PetscCheck(!idex, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for returning index; send mail to petsc-maint@mcs.anl.gov asking for it");
490   PetscCall(VecGetLocalSize(v, &n));
491   PetscCall(VecGetArrayRead(v, &x));
492   PetscCall(PetscObjectGetComm((PetscObject)v, &comm));
493 
494   PetscCall(VecGetBlockSize(v, &bs));
495   PetscCheck(bs <= 128, comm, PETSC_ERR_SUP, "Currently supports only blocksize up to 128");
496 
497   if (!n) {
498     for (j = 0; j < bs; j++) max[j] = PETSC_MIN_REAL;
499   } else {
500     for (j = 0; j < bs; j++) max[j] = PetscRealPart(x[j]);
501 
502     for (i = bs; i < n; i += bs) {
503       for (j = 0; j < bs; j++) {
504         if ((tmp = PetscRealPart(x[i + j])) > max[j]) max[j] = tmp;
505       }
506     }
507   }
508   PetscCall(MPIU_Allreduce(max, nrm, bs, MPIU_REAL, MPIU_MAX, comm));
509 
510   PetscCall(VecRestoreArrayRead(v, &x));
511   PetscFunctionReturn(0);
512 }
513 
514 /*@
515    VecStrideMinAll - Computes the minimum of subvector of a vector defined
516    by a starting point and a stride and optionally its location.
517 
518    Collective on Vec
519 
520    Input Parameter:
521 .  v - the vector
522 
523    Output Parameters:
524 +  idex - the location where the minimum occurred (not supported, pass NULL,
525            if you need this, send mail to petsc-maint@mcs.anl.gov to request it)
526 -  nrm - the minimums of each subvector
527 
528    Level: advanced
529 
530    Notes:
531    One must call VecSetBlockSize() before this routine to set the stride
532    information, or use a vector created from a multicomponent DMDA.
533 
534    The dimension of nrm must be the same as the vector block size
535 
536 .seealso: `VecMin()`, `VecStrideNorm()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMax()`
537 @*/
538 PetscErrorCode VecStrideMinAll(Vec v, PetscInt idex[], PetscReal nrm[]) {
539   PetscInt           i, n, bs, j;
540   const PetscScalar *x;
541   PetscReal          min[128], tmp;
542   MPI_Comm           comm;
543 
544   PetscFunctionBegin;
545   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
546   PetscValidRealPointer(nrm, 3);
547   PetscCheck(!idex, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support yet for returning index; send mail to petsc-maint@mcs.anl.gov asking for it");
548   PetscCall(VecGetLocalSize(v, &n));
549   PetscCall(VecGetArrayRead(v, &x));
550   PetscCall(PetscObjectGetComm((PetscObject)v, &comm));
551 
552   PetscCall(VecGetBlockSize(v, &bs));
553   PetscCheck(bs <= 128, comm, PETSC_ERR_SUP, "Currently supports only blocksize up to 128");
554 
555   if (!n) {
556     for (j = 0; j < bs; j++) min[j] = PETSC_MAX_REAL;
557   } else {
558     for (j = 0; j < bs; j++) min[j] = PetscRealPart(x[j]);
559 
560     for (i = bs; i < n; i += bs) {
561       for (j = 0; j < bs; j++) {
562         if ((tmp = PetscRealPart(x[i + j])) < min[j]) min[j] = tmp;
563       }
564     }
565   }
566   PetscCall(MPIU_Allreduce(min, nrm, bs, MPIU_REAL, MPIU_MIN, comm));
567 
568   PetscCall(VecRestoreArrayRead(v, &x));
569   PetscFunctionReturn(0);
570 }
571 
572 /*@
573    VecStrideSumAll - Computes the sums of subvectors of a vector defined by a stride.
574 
575    Collective on Vec
576 
577    Input Parameter:
578 .  v - the vector
579 
580    Output Parameter:
581 .  sums - the sums
582 
583    Notes:
584    One must call `VecSetBlockSize()` before this routine to set the stride
585    information, or use a vector created from a multicomponent `DMDA`.
586 
587    If x is the array representing the vector x then this computes the sum
588    of the array (x[start],x[start+stride],x[start+2*stride], ....) for each start < stride
589 
590    Level: advanced
591 
592 .seealso: `VecSum()`, `VecStrideGather()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`
593 @*/
594 PetscErrorCode VecStrideSumAll(Vec v, PetscScalar sums[]) {
595   PetscInt           i, j, n, bs;
596   const PetscScalar *x;
597   PetscScalar        local_sums[128];
598   MPI_Comm           comm;
599 
600   PetscFunctionBegin;
601   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
602   PetscValidScalarPointer(sums, 2);
603   PetscCall(VecGetLocalSize(v, &n));
604   PetscCall(VecGetArrayRead(v, &x));
605   PetscCall(PetscObjectGetComm((PetscObject)v, &comm));
606 
607   PetscCall(VecGetBlockSize(v, &bs));
608   PetscCheck(bs <= 128, comm, PETSC_ERR_SUP, "Currently supports only blocksize up to 128");
609 
610   for (j = 0; j < bs; j++) local_sums[j] = 0.0;
611   for (i = 0; i < n; i += bs) {
612     for (j = 0; j < bs; j++) local_sums[j] += x[i + j];
613   }
614   PetscCall(MPIU_Allreduce(local_sums, sums, bs, MPIU_SCALAR, MPIU_SUM, comm));
615 
616   PetscCall(VecRestoreArrayRead(v, &x));
617   PetscFunctionReturn(0);
618 }
619 
620 /*----------------------------------------------------------------------------------------------*/
621 /*@
622    VecStrideGatherAll - Gathers all the single components from a multi-component vector into
623    separate vectors.
624 
625    Collective on Vec
626 
627    Input Parameters:
628 +  v - the vector
629 -  addv - one of ADD_VALUES,INSERT_VALUES,MAX_VALUES
630 
631    Output Parameter:
632 .  s - the location where the subvectors are stored
633 
634    Notes:
635    One must call VecSetBlockSize() before this routine to set the stride
636    information, or use a vector created from a multicomponent DMDA.
637 
638    If x is the array representing the vector x then this gathers
639    the arrays (x[start],x[start+stride],x[start+2*stride], ....)
640    for start=0,1,2,...bs-1
641 
642    The parallel layout of the vector and the subvector must be the same;
643    i.e., nlocal of v = stride*(nlocal of s)
644 
645    Not optimized; could be easily
646 
647    Level: advanced
648 
649 .seealso: `VecStrideNorm()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideGather()`,
650           `VecStrideScatterAll()`
651 @*/
652 PetscErrorCode VecStrideGatherAll(Vec v, Vec s[], InsertMode addv) {
653   PetscInt           i, n, n2, bs, j, k, *bss = NULL, nv, jj, nvc;
654   PetscScalar      **y;
655   const PetscScalar *x;
656 
657   PetscFunctionBegin;
658   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
659   PetscValidPointer(s, 2);
660   PetscValidHeaderSpecific(*s, VEC_CLASSID, 2);
661   PetscCall(VecGetLocalSize(v, &n));
662   PetscCall(VecGetLocalSize(s[0], &n2));
663   PetscCall(VecGetArrayRead(v, &x));
664   PetscCall(VecGetBlockSize(v, &bs));
665   PetscCheck(bs > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Input vector does not have a valid blocksize set");
666 
667   PetscCall(PetscMalloc2(bs, &y, bs, &bss));
668   nv  = 0;
669   nvc = 0;
670   for (i = 0; i < bs; i++) {
671     PetscCall(VecGetBlockSize(s[i], &bss[i]));
672     if (bss[i] < 1) bss[i] = 1; /* if user never set it then assume 1  Re: [PETSC #8241] VecStrideGatherAll */
673     PetscCall(VecGetArray(s[i], &y[i]));
674     nvc += bss[i];
675     nv++;
676     PetscCheck(nvc <= bs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of subvectors in subvectors > number of vectors in main vector");
677     if (nvc == bs) break;
678   }
679 
680   n = n / bs;
681 
682   jj = 0;
683   if (addv == INSERT_VALUES) {
684     for (j = 0; j < nv; j++) {
685       for (k = 0; k < bss[j]; k++) {
686         for (i = 0; i < n; i++) y[j][i * bss[j] + k] = x[bs * i + jj + k];
687       }
688       jj += bss[j];
689     }
690   } else if (addv == ADD_VALUES) {
691     for (j = 0; j < nv; j++) {
692       for (k = 0; k < bss[j]; k++) {
693         for (i = 0; i < n; i++) y[j][i * bss[j] + k] += x[bs * i + jj + k];
694       }
695       jj += bss[j];
696     }
697 #if !defined(PETSC_USE_COMPLEX)
698   } else if (addv == MAX_VALUES) {
699     for (j = 0; j < nv; j++) {
700       for (k = 0; k < bss[j]; k++) {
701         for (i = 0; i < n; i++) y[j][i * bss[j] + k] = PetscMax(y[j][i * bss[j] + k], x[bs * i + jj + k]);
702       }
703       jj += bss[j];
704     }
705 #endif
706   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown insert type");
707 
708   PetscCall(VecRestoreArrayRead(v, &x));
709   for (i = 0; i < nv; i++) PetscCall(VecRestoreArray(s[i], &y[i]));
710 
711   PetscCall(PetscFree2(y, bss));
712   PetscFunctionReturn(0);
713 }
714 
715 /*@
716    VecStrideScatterAll - Scatters all the single components from separate vectors into
717      a multi-component vector.
718 
719    Collective on Vec
720 
721    Input Parameters:
722 +  s - the location where the subvectors are stored
723 -  addv - one of ADD_VALUES,INSERT_VALUES,MAX_VALUES
724 
725    Output Parameter:
726 .  v - the multicomponent vector
727 
728    Notes:
729    One must call VecSetBlockSize() before this routine to set the stride
730    information, or use a vector created from a multicomponent DMDA.
731 
732    The parallel layout of the vector and the subvector must be the same;
733    i.e., nlocal of v = stride*(nlocal of s)
734 
735    Not optimized; could be easily
736 
737    Level: advanced
738 
739 .seealso: `VecStrideNorm()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideGather()`,
740           `VecStrideScatterAll()`
741 @*/
742 PetscErrorCode VecStrideScatterAll(Vec s[], Vec v, InsertMode addv) {
743   PetscInt            i, n, n2, bs, j, jj, k, *bss = NULL, nv, nvc;
744   PetscScalar        *x;
745   PetscScalar const **y;
746 
747   PetscFunctionBegin;
748   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
749   PetscValidPointer(s, 1);
750   PetscValidHeaderSpecific(*s, VEC_CLASSID, 1);
751   PetscCall(VecGetLocalSize(v, &n));
752   PetscCall(VecGetLocalSize(s[0], &n2));
753   PetscCall(VecGetArray(v, &x));
754   PetscCall(VecGetBlockSize(v, &bs));
755   PetscCheck(bs > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Input vector does not have a valid blocksize set");
756 
757   PetscCall(PetscMalloc2(bs, (PetscScalar ***)&y, bs, &bss));
758   nv  = 0;
759   nvc = 0;
760   for (i = 0; i < bs; i++) {
761     PetscCall(VecGetBlockSize(s[i], &bss[i]));
762     if (bss[i] < 1) bss[i] = 1; /* if user never set it then assume 1  Re: [PETSC #8241] VecStrideGatherAll */
763     PetscCall(VecGetArrayRead(s[i], &y[i]));
764     nvc += bss[i];
765     nv++;
766     PetscCheck(nvc <= bs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of subvectors in subvectors > number of vectors in main vector");
767     if (nvc == bs) break;
768   }
769 
770   n = n / bs;
771 
772   jj = 0;
773   if (addv == INSERT_VALUES) {
774     for (j = 0; j < nv; j++) {
775       for (k = 0; k < bss[j]; k++) {
776         for (i = 0; i < n; i++) x[bs * i + jj + k] = y[j][i * bss[j] + k];
777       }
778       jj += bss[j];
779     }
780   } else if (addv == ADD_VALUES) {
781     for (j = 0; j < nv; j++) {
782       for (k = 0; k < bss[j]; k++) {
783         for (i = 0; i < n; i++) x[bs * i + jj + k] += y[j][i * bss[j] + k];
784       }
785       jj += bss[j];
786     }
787 #if !defined(PETSC_USE_COMPLEX)
788   } else if (addv == MAX_VALUES) {
789     for (j = 0; j < nv; j++) {
790       for (k = 0; k < bss[j]; k++) {
791         for (i = 0; i < n; i++) x[bs * i + jj + k] = PetscMax(x[bs * i + jj + k], y[j][i * bss[j] + k]);
792       }
793       jj += bss[j];
794     }
795 #endif
796   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown insert type");
797 
798   PetscCall(VecRestoreArray(v, &x));
799   for (i = 0; i < nv; i++) PetscCall(VecRestoreArrayRead(s[i], &y[i]));
800   PetscCall(PetscFree2(*(PetscScalar ***)&y, bss));
801   PetscFunctionReturn(0);
802 }
803 
804 /*@
805    VecStrideGather - Gathers a single component from a multi-component vector into
806    another vector.
807 
808    Collective on Vec
809 
810    Input Parameters:
811 +  v - the vector
812 .  start - starting point of the subvector (defined by a stride)
813 -  addv - one of ADD_VALUES,INSERT_VALUES,MAX_VALUES
814 
815    Output Parameter:
816 .  s - the location where the subvector is stored
817 
818    Notes:
819    One must call VecSetBlockSize() before this routine to set the stride
820    information, or use a vector created from a multicomponent DMDA.
821 
822    If x is the array representing the vector x then this gathers
823    the array (x[start],x[start+stride],x[start+2*stride], ....)
824 
825    The parallel layout of the vector and the subvector must be the same;
826    i.e., nlocal of v = stride*(nlocal of s)
827 
828    Not optimized; could be easily
829 
830    Level: advanced
831 
832 .seealso: `VecStrideNorm()`, `VecStrideScatter()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideGatherAll()`,
833           `VecStrideScatterAll()`
834 @*/
835 PetscErrorCode VecStrideGather(Vec v, PetscInt start, Vec s, InsertMode addv) {
836   PetscFunctionBegin;
837   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
838   PetscValidHeaderSpecific(s, VEC_CLASSID, 3);
839   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
840   PetscCheck(start < v->map->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\n Have you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start,
841              v->map->bs);
842   PetscUseTypeMethod(v, stridegather, start, s, addv);
843   PetscFunctionReturn(0);
844 }
845 
846 /*@
847    VecStrideScatter - Scatters a single component from a vector into a multi-component vector.
848 
849    Collective on Vec
850 
851    Input Parameters:
852 +  s - the single-component vector
853 .  start - starting point of the subvector (defined by a stride)
854 -  addv - one of ADD_VALUES,INSERT_VALUES,MAX_VALUES
855 
856    Output Parameter:
857 .  v - the location where the subvector is scattered (the multi-component vector)
858 
859    Notes:
860    One must call VecSetBlockSize() on the multi-component vector before this
861    routine to set the stride  information, or use a vector created from a multicomponent DMDA.
862 
863    The parallel layout of the vector and the subvector must be the same;
864    i.e., nlocal of v = stride*(nlocal of s)
865 
866    Not optimized; could be easily
867 
868    Level: advanced
869 
870 .seealso: `VecStrideNorm()`, `VecStrideGather()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideGatherAll()`,
871           `VecStrideScatterAll()`, `VecStrideSubSetScatter()`, `VecStrideSubSetGather()`
872 @*/
873 PetscErrorCode VecStrideScatter(Vec s, PetscInt start, Vec v, InsertMode addv) {
874   PetscFunctionBegin;
875   PetscValidHeaderSpecific(s, VEC_CLASSID, 1);
876   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
877   PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative start %" PetscInt_FMT, start);
878   PetscCheck(start < v->map->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Start of stride subvector (%" PetscInt_FMT ") is too large for stride\n Have you set the vector blocksize (%" PetscInt_FMT ") correctly with VecSetBlockSize()?", start,
879              v->map->bs);
880   PetscCall((*v->ops->stridescatter)(s, start, v, addv));
881   PetscFunctionReturn(0);
882 }
883 
884 /*@
885    VecStrideSubSetGather - Gathers a subset of components from a multi-component vector into
886    another vector.
887 
888    Collective on Vec
889 
890    Input Parameters:
891 +  v - the vector
892 .  nidx - the number of indices
893 .  idxv - the indices of the components 0 <= idxv[0] ...idxv[nidx-1] < bs(v), they need not be sorted
894 .  idxs - the indices of the components 0 <= idxs[0] ...idxs[nidx-1] < bs(s), they need not be sorted, may be null if nidx == bs(s) or is PETSC_DETERMINE
895 -  addv - one of ADD_VALUES,INSERT_VALUES,MAX_VALUES
896 
897    Output Parameter:
898 .  s - the location where the subvector is stored
899 
900    Notes:
901    One must call VecSetBlockSize() on both vectors before this routine to set the stride
902    information, or use a vector created from a multicomponent DMDA.
903 
904    The parallel layout of the vector and the subvector must be the same;
905 
906    Not optimized; could be easily
907 
908    Level: advanced
909 
910 .seealso: `VecStrideNorm()`, `VecStrideScatter()`, `VecStrideGather()`, `VecStrideSubSetScatter()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideGatherAll()`,
911           `VecStrideScatterAll()`
912 @*/
913 PetscErrorCode VecStrideSubSetGather(Vec v, PetscInt nidx, const PetscInt idxv[], const PetscInt idxs[], Vec s, InsertMode addv) {
914   PetscFunctionBegin;
915   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
916   PetscValidHeaderSpecific(s, VEC_CLASSID, 5);
917   if (nidx == PETSC_DETERMINE) nidx = s->map->bs;
918   PetscUseTypeMethod(v, stridesubsetgather, nidx, idxv, idxs, s, addv);
919   PetscFunctionReturn(0);
920 }
921 
922 /*@
923    VecStrideSubSetScatter - Scatters components from a vector into a subset of components of a multi-component vector.
924 
925    Collective on Vec
926 
927    Input Parameters:
928 +  s - the smaller-component vector
929 .  nidx - the number of indices in idx
930 .  idxs - the indices of the components in the smaller-component vector, 0 <= idxs[0] ...idxs[nidx-1] < bs(s) they need not be sorted, may be null if nidx == bs(s) or is PETSC_DETERMINE
931 .  idxv - the indices of the components in the larger-component vector, 0 <= idx[0] ...idx[nidx-1] < bs(v) they need not be sorted
932 -  addv - one of ADD_VALUES,INSERT_VALUES,MAX_VALUES
933 
934    Output Parameter:
935 .  v - the location where the subvector is into scattered (the multi-component vector)
936 
937    Notes:
938    One must call VecSetBlockSize() on the vectors before this
939    routine to set the stride  information, or use a vector created from a multicomponent DMDA.
940 
941    The parallel layout of the vector and the subvector must be the same;
942 
943    Not optimized; could be easily
944 
945    Level: advanced
946 
947 .seealso: `VecStrideNorm()`, `VecStrideGather()`, `VecStrideGather()`, `VecStrideSubSetGather()`, `VecStrideMin()`, `VecStrideMax()`, `VecStrideGatherAll()`,
948           `VecStrideScatterAll()`
949 @*/
950 PetscErrorCode VecStrideSubSetScatter(Vec s, PetscInt nidx, const PetscInt idxs[], const PetscInt idxv[], Vec v, InsertMode addv) {
951   PetscFunctionBegin;
952   PetscValidHeaderSpecific(s, VEC_CLASSID, 1);
953   PetscValidHeaderSpecific(v, VEC_CLASSID, 5);
954   if (nidx == PETSC_DETERMINE) nidx = s->map->bs;
955   PetscCall((*v->ops->stridesubsetscatter)(s, nidx, idxs, idxv, v, addv));
956   PetscFunctionReturn(0);
957 }
958 
959 PetscErrorCode VecStrideGather_Default(Vec v, PetscInt start, Vec s, InsertMode addv) {
960   PetscInt           i, n, bs, ns;
961   const PetscScalar *x;
962   PetscScalar       *y;
963 
964   PetscFunctionBegin;
965   PetscCall(VecGetLocalSize(v, &n));
966   PetscCall(VecGetLocalSize(s, &ns));
967   PetscCall(VecGetArrayRead(v, &x));
968   PetscCall(VecGetArray(s, &y));
969 
970   bs = v->map->bs;
971   PetscCheck(n == ns * bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Subvector length * blocksize %" PetscInt_FMT " not correct for gather from original vector %" PetscInt_FMT, ns * bs, n);
972   x += start;
973   n = n / bs;
974 
975   if (addv == INSERT_VALUES) {
976     for (i = 0; i < n; i++) y[i] = x[bs * i];
977   } else if (addv == ADD_VALUES) {
978     for (i = 0; i < n; i++) y[i] += x[bs * i];
979 #if !defined(PETSC_USE_COMPLEX)
980   } else if (addv == MAX_VALUES) {
981     for (i = 0; i < n; i++) y[i] = PetscMax(y[i], x[bs * i]);
982 #endif
983   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown insert type");
984 
985   PetscCall(VecRestoreArrayRead(v, &x));
986   PetscCall(VecRestoreArray(s, &y));
987   PetscFunctionReturn(0);
988 }
989 
990 PetscErrorCode VecStrideScatter_Default(Vec s, PetscInt start, Vec v, InsertMode addv) {
991   PetscInt           i, n, bs, ns;
992   PetscScalar       *x;
993   const PetscScalar *y;
994 
995   PetscFunctionBegin;
996   PetscCall(VecGetLocalSize(v, &n));
997   PetscCall(VecGetLocalSize(s, &ns));
998   PetscCall(VecGetArray(v, &x));
999   PetscCall(VecGetArrayRead(s, &y));
1000 
1001   bs = v->map->bs;
1002   PetscCheck(n == ns * bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Subvector length * blocksize %" PetscInt_FMT " not correct for scatter to multicomponent vector %" PetscInt_FMT, ns * bs, n);
1003   x += start;
1004   n = n / bs;
1005 
1006   if (addv == INSERT_VALUES) {
1007     for (i = 0; i < n; i++) x[bs * i] = y[i];
1008   } else if (addv == ADD_VALUES) {
1009     for (i = 0; i < n; i++) x[bs * i] += y[i];
1010 #if !defined(PETSC_USE_COMPLEX)
1011   } else if (addv == MAX_VALUES) {
1012     for (i = 0; i < n; i++) x[bs * i] = PetscMax(y[i], x[bs * i]);
1013 #endif
1014   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown insert type");
1015 
1016   PetscCall(VecRestoreArray(v, &x));
1017   PetscCall(VecRestoreArrayRead(s, &y));
1018   PetscFunctionReturn(0);
1019 }
1020 
1021 PetscErrorCode VecStrideSubSetGather_Default(Vec v, PetscInt nidx, const PetscInt idxv[], const PetscInt idxs[], Vec s, InsertMode addv) {
1022   PetscInt           i, j, n, bs, bss, ns;
1023   const PetscScalar *x;
1024   PetscScalar       *y;
1025 
1026   PetscFunctionBegin;
1027   PetscCall(VecGetLocalSize(v, &n));
1028   PetscCall(VecGetLocalSize(s, &ns));
1029   PetscCall(VecGetArrayRead(v, &x));
1030   PetscCall(VecGetArray(s, &y));
1031 
1032   bs  = v->map->bs;
1033   bss = s->map->bs;
1034   n   = n / bs;
1035 
1036   if (PetscDefined(USE_DEBUG)) {
1037     PetscCheck(n == ns / bss, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Incompatible layout of vectors");
1038     for (j = 0; j < nidx; j++) {
1039       PetscCheck(idxv[j] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "idx[%" PetscInt_FMT "] %" PetscInt_FMT " is negative", j, idxv[j]);
1040       PetscCheck(idxv[j] < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "idx[%" PetscInt_FMT "] %" PetscInt_FMT " is greater than or equal to vector blocksize %" PetscInt_FMT, j, idxv[j], bs);
1041     }
1042     PetscCheck(idxs || bss == nidx, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must provide idxs when not gathering into all locations");
1043   }
1044 
1045   if (addv == INSERT_VALUES) {
1046     if (!idxs) {
1047       for (i = 0; i < n; i++) {
1048         for (j = 0; j < bss; j++) y[bss * i + j] = x[bs * i + idxv[j]];
1049       }
1050     } else {
1051       for (i = 0; i < n; i++) {
1052         for (j = 0; j < bss; j++) y[bss * i + idxs[j]] = x[bs * i + idxv[j]];
1053       }
1054     }
1055   } else if (addv == ADD_VALUES) {
1056     if (!idxs) {
1057       for (i = 0; i < n; i++) {
1058         for (j = 0; j < bss; j++) y[bss * i + j] += x[bs * i + idxv[j]];
1059       }
1060     } else {
1061       for (i = 0; i < n; i++) {
1062         for (j = 0; j < bss; j++) y[bss * i + idxs[j]] += x[bs * i + idxv[j]];
1063       }
1064     }
1065 #if !defined(PETSC_USE_COMPLEX)
1066   } else if (addv == MAX_VALUES) {
1067     if (!idxs) {
1068       for (i = 0; i < n; i++) {
1069         for (j = 0; j < bss; j++) y[bss * i + j] = PetscMax(y[bss * i + j], x[bs * i + idxv[j]]);
1070       }
1071     } else {
1072       for (i = 0; i < n; i++) {
1073         for (j = 0; j < bss; j++) y[bss * i + idxs[j]] = PetscMax(y[bss * i + idxs[j]], x[bs * i + idxv[j]]);
1074       }
1075     }
1076 #endif
1077   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown insert type");
1078 
1079   PetscCall(VecRestoreArrayRead(v, &x));
1080   PetscCall(VecRestoreArray(s, &y));
1081   PetscFunctionReturn(0);
1082 }
1083 
1084 PetscErrorCode VecStrideSubSetScatter_Default(Vec s, PetscInt nidx, const PetscInt idxs[], const PetscInt idxv[], Vec v, InsertMode addv) {
1085   PetscInt           j, i, n, bs, ns, bss;
1086   PetscScalar       *x;
1087   const PetscScalar *y;
1088 
1089   PetscFunctionBegin;
1090   PetscCall(VecGetLocalSize(v, &n));
1091   PetscCall(VecGetLocalSize(s, &ns));
1092   PetscCall(VecGetArray(v, &x));
1093   PetscCall(VecGetArrayRead(s, &y));
1094 
1095   bs  = v->map->bs;
1096   bss = s->map->bs;
1097   n   = n / bs;
1098 
1099   if (PetscDefined(USE_DEBUG)) {
1100     PetscCheck(n == ns / bss, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Incompatible layout of vectors");
1101     for (j = 0; j < bss; j++) {
1102       if (idxs) {
1103         PetscCheck(idxs[j] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "idx[%" PetscInt_FMT "] %" PetscInt_FMT " is negative", j, idxs[j]);
1104         PetscCheck(idxs[j] < bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "idx[%" PetscInt_FMT "] %" PetscInt_FMT " is greater than or equal to vector blocksize %" PetscInt_FMT, j, idxs[j], bs);
1105       }
1106     }
1107     PetscCheck(idxs || bss == nidx, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must provide idxs when not scattering from all locations");
1108   }
1109 
1110   if (addv == INSERT_VALUES) {
1111     if (!idxs) {
1112       for (i = 0; i < n; i++) {
1113         for (j = 0; j < bss; j++) x[bs * i + idxv[j]] = y[bss * i + j];
1114       }
1115     } else {
1116       for (i = 0; i < n; i++) {
1117         for (j = 0; j < bss; j++) x[bs * i + idxv[j]] = y[bss * i + idxs[j]];
1118       }
1119     }
1120   } else if (addv == ADD_VALUES) {
1121     if (!idxs) {
1122       for (i = 0; i < n; i++) {
1123         for (j = 0; j < bss; j++) x[bs * i + idxv[j]] += y[bss * i + j];
1124       }
1125     } else {
1126       for (i = 0; i < n; i++) {
1127         for (j = 0; j < bss; j++) x[bs * i + idxv[j]] += y[bss * i + idxs[j]];
1128       }
1129     }
1130 #if !defined(PETSC_USE_COMPLEX)
1131   } else if (addv == MAX_VALUES) {
1132     if (!idxs) {
1133       for (i = 0; i < n; i++) {
1134         for (j = 0; j < bss; j++) x[bs * i + idxv[j]] = PetscMax(y[bss * i + j], x[bs * i + idxv[j]]);
1135       }
1136     } else {
1137       for (i = 0; i < n; i++) {
1138         for (j = 0; j < bss; j++) x[bs * i + idxv[j]] = PetscMax(y[bss * i + idxs[j]], x[bs * i + idxv[j]]);
1139       }
1140     }
1141 #endif
1142   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown insert type");
1143 
1144   PetscCall(VecRestoreArray(v, &x));
1145   PetscCall(VecRestoreArrayRead(s, &y));
1146   PetscFunctionReturn(0);
1147 }
1148 
1149 PetscErrorCode VecReciprocal_Default(Vec v) {
1150   PetscInt     i, n;
1151   PetscScalar *x;
1152 
1153   PetscFunctionBegin;
1154   PetscCall(VecGetLocalSize(v, &n));
1155   PetscCall(VecGetArray(v, &x));
1156   for (i = 0; i < n; i++) {
1157     if (x[i] != (PetscScalar)0.0) x[i] = (PetscScalar)1.0 / x[i];
1158   }
1159   PetscCall(VecRestoreArray(v, &x));
1160   PetscFunctionReturn(0);
1161 }
1162 
1163 /*@
1164   VecExp - Replaces each component of a vector by e^x_i
1165 
1166   Not collective
1167 
1168   Input Parameter:
1169 . v - The vector
1170 
1171   Output Parameter:
1172 . v - The vector of exponents
1173 
1174   Level: beginner
1175 
1176 .seealso: `VecLog()`, `VecAbs()`, `VecSqrtAbs()`, `VecReciprocal()`
1177 
1178 @*/
1179 PetscErrorCode VecExp(Vec v) {
1180   PetscScalar *x;
1181   PetscInt     i, n;
1182 
1183   PetscFunctionBegin;
1184   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1185   if (v->ops->exp) PetscUseTypeMethod(v, exp);
1186   else {
1187     PetscCall(VecGetLocalSize(v, &n));
1188     PetscCall(VecGetArray(v, &x));
1189     for (i = 0; i < n; i++) x[i] = PetscExpScalar(x[i]);
1190     PetscCall(VecRestoreArray(v, &x));
1191   }
1192   PetscFunctionReturn(0);
1193 }
1194 
1195 /*@
1196   VecLog - Replaces each component of a vector by log(x_i), the natural logarithm
1197 
1198   Not collective
1199 
1200   Input Parameter:
1201 . v - The vector
1202 
1203   Output Parameter:
1204 . v - The vector of logs
1205 
1206   Level: beginner
1207 
1208 .seealso: `VecExp()`, `VecAbs()`, `VecSqrtAbs()`, `VecReciprocal()`
1209 
1210 @*/
1211 PetscErrorCode VecLog(Vec v) {
1212   PetscScalar *x;
1213   PetscInt     i, n;
1214 
1215   PetscFunctionBegin;
1216   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1217   if (v->ops->log) PetscUseTypeMethod(v, log);
1218   else {
1219     PetscCall(VecGetLocalSize(v, &n));
1220     PetscCall(VecGetArray(v, &x));
1221     for (i = 0; i < n; i++) x[i] = PetscLogScalar(x[i]);
1222     PetscCall(VecRestoreArray(v, &x));
1223   }
1224   PetscFunctionReturn(0);
1225 }
1226 
1227 /*@
1228   VecSqrtAbs - Replaces each component of a vector by the square root of its magnitude.
1229 
1230   Not collective
1231 
1232   Input Parameter:
1233 . v - The vector
1234 
1235   Output Parameter:
1236 . v - The vector square root
1237 
1238   Level: beginner
1239 
1240   Note: The actual function is sqrt(|x_i|)
1241 
1242 .seealso: `VecLog()`, `VecExp()`, `VecReciprocal()`, `VecAbs()`
1243 
1244 @*/
1245 PetscErrorCode VecSqrtAbs(Vec v) {
1246   PetscScalar *x;
1247   PetscInt     i, n;
1248 
1249   PetscFunctionBegin;
1250   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1251   if (v->ops->sqrt) PetscUseTypeMethod(v, sqrt);
1252   else {
1253     PetscCall(VecGetLocalSize(v, &n));
1254     PetscCall(VecGetArray(v, &x));
1255     for (i = 0; i < n; i++) x[i] = PetscSqrtReal(PetscAbsScalar(x[i]));
1256     PetscCall(VecRestoreArray(v, &x));
1257   }
1258   PetscFunctionReturn(0);
1259 }
1260 
1261 /*@
1262   VecDotNorm2 - computes the inner product of two vectors and the 2-norm squared of the second vector
1263 
1264   Collective on Vec
1265 
1266   Input Parameters:
1267 + s - first vector
1268 - t - second vector
1269 
1270   Output Parameters:
1271 + dp - s'conj(t)
1272 - nm - t'conj(t)
1273 
1274   Level: advanced
1275 
1276   Notes:
1277     conj(x) is the complex conjugate of x when x is complex
1278 
1279 .seealso: `VecDot()`, `VecNorm()`, `VecDotBegin()`, `VecNormBegin()`, `VecDotEnd()`, `VecNormEnd()`
1280 
1281 @*/
1282 PetscErrorCode VecDotNorm2(Vec s, Vec t, PetscScalar *dp, PetscReal *nm) {
1283   const PetscScalar *sx, *tx;
1284   PetscScalar        dpx = 0.0, nmx = 0.0, work[2], sum[2];
1285   PetscInt           i, n;
1286 
1287   PetscFunctionBegin;
1288   PetscValidHeaderSpecific(s, VEC_CLASSID, 1);
1289   PetscValidHeaderSpecific(t, VEC_CLASSID, 2);
1290   PetscValidScalarPointer(dp, 3);
1291   PetscValidRealPointer(nm, 4);
1292   PetscValidType(s, 1);
1293   PetscValidType(t, 2);
1294   PetscCheckSameTypeAndComm(s, 1, t, 2);
1295   PetscCheck(s->map->N == t->map->N, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Incompatible vector global lengths");
1296   PetscCheck(s->map->n == t->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Incompatible vector local lengths");
1297 
1298   PetscCall(PetscLogEventBegin(VEC_DotNorm2, s, t, 0, 0));
1299   if (s->ops->dotnorm2) {
1300     PetscUseTypeMethod(s, dotnorm2, t, dp, &dpx);
1301     *nm = PetscRealPart(dpx);
1302   } else {
1303     PetscCall(VecGetLocalSize(s, &n));
1304     PetscCall(VecGetArrayRead(s, &sx));
1305     PetscCall(VecGetArrayRead(t, &tx));
1306 
1307     for (i = 0; i < n; i++) {
1308       dpx += sx[i] * PetscConj(tx[i]);
1309       nmx += tx[i] * PetscConj(tx[i]);
1310     }
1311     work[0] = dpx;
1312     work[1] = nmx;
1313 
1314     PetscCall(MPIU_Allreduce(work, sum, 2, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)s)));
1315     *dp = sum[0];
1316     *nm = PetscRealPart(sum[1]);
1317 
1318     PetscCall(VecRestoreArrayRead(t, &tx));
1319     PetscCall(VecRestoreArrayRead(s, &sx));
1320     PetscCall(PetscLogFlops(4.0 * n));
1321   }
1322   PetscCall(PetscLogEventEnd(VEC_DotNorm2, s, t, 0, 0));
1323   PetscFunctionReturn(0);
1324 }
1325 
1326 /*@
1327    VecSum - Computes the sum of all the components of a vector.
1328 
1329    Collective on Vec
1330 
1331    Input Parameter:
1332 .  v - the vector
1333 
1334    Output Parameter:
1335 .  sum - the result
1336 
1337    Level: beginner
1338 
1339 .seealso: `VecMean()`, `VecNorm()`
1340 @*/
1341 PetscErrorCode VecSum(Vec v, PetscScalar *sum) {
1342   PetscInt           i, n;
1343   const PetscScalar *x;
1344 
1345   PetscFunctionBegin;
1346   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1347   PetscValidScalarPointer(sum, 2);
1348   *sum = 0.0;
1349   if (v->ops->sum) {
1350     PetscUseTypeMethod(v, sum, sum);
1351   } else {
1352     PetscCall(VecGetLocalSize(v, &n));
1353     PetscCall(VecGetArrayRead(v, &x));
1354     for (i = 0; i < n; i++) *sum += x[i];
1355     PetscCall(VecRestoreArrayRead(v, &x));
1356   }
1357   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, sum, 1, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)v)));
1358   PetscFunctionReturn(0);
1359 }
1360 
1361 /*@
1362    VecMean - Computes the arithmetic mean of all the components of a vector.
1363 
1364    Collective on Vec
1365 
1366    Input Parameter:
1367 .  v - the vector
1368 
1369    Output Parameter:
1370 .  mean - the result
1371 
1372    Level: beginner
1373 
1374 .seealso: `VecSum()`, `VecNorm()`
1375 @*/
1376 PetscErrorCode VecMean(Vec v, PetscScalar *mean) {
1377   PetscInt n;
1378 
1379   PetscFunctionBegin;
1380   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1381   PetscValidScalarPointer(mean, 2);
1382   PetscCall(VecGetSize(v, &n));
1383   PetscCall(VecSum(v, mean));
1384   *mean /= n;
1385   PetscFunctionReturn(0);
1386 }
1387 
1388 /*@
1389    VecImaginaryPart - Replaces a complex vector with its imginary part
1390 
1391    Collective on Vec
1392 
1393    Input Parameter:
1394 .  v - the vector
1395 
1396    Level: beginner
1397 
1398 .seealso: `VecNorm()`, `VecRealPart()`
1399 @*/
1400 PetscErrorCode VecImaginaryPart(Vec v) {
1401   PetscInt     i, n;
1402   PetscScalar *x;
1403 
1404   PetscFunctionBegin;
1405   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1406   PetscCall(VecGetLocalSize(v, &n));
1407   PetscCall(VecGetArray(v, &x));
1408   for (i = 0; i < n; i++) x[i] = PetscImaginaryPart(x[i]);
1409   PetscCall(VecRestoreArray(v, &x));
1410   PetscFunctionReturn(0);
1411 }
1412 
1413 /*@
1414    VecRealPart - Replaces a complex vector with its real part
1415 
1416    Collective on Vec
1417 
1418    Input Parameter:
1419 .  v - the vector
1420 
1421    Level: beginner
1422 
1423 .seealso: `VecNorm()`, `VecImaginaryPart()`
1424 @*/
1425 PetscErrorCode VecRealPart(Vec v) {
1426   PetscInt     i, n;
1427   PetscScalar *x;
1428 
1429   PetscFunctionBegin;
1430   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1431   PetscCall(VecGetLocalSize(v, &n));
1432   PetscCall(VecGetArray(v, &x));
1433   for (i = 0; i < n; i++) x[i] = PetscRealPart(x[i]);
1434   PetscCall(VecRestoreArray(v, &x));
1435   PetscFunctionReturn(0);
1436 }
1437 
1438 /*@
1439    VecShift - Shifts all of the components of a vector by computing
1440    x[i] = x[i] + shift.
1441 
1442    Logically Collective on Vec
1443 
1444    Input Parameters:
1445 +  v - the vector
1446 -  shift - the shift
1447 
1448    Level: intermediate
1449 
1450 @*/
1451 PetscErrorCode VecShift(Vec v, PetscScalar shift) {
1452   PetscInt     i, n;
1453   PetscScalar *x;
1454 
1455   PetscFunctionBegin;
1456   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1457   PetscValidLogicalCollectiveScalar(v, shift, 2);
1458   PetscCall(VecSetErrorIfLocked(v, 1));
1459   if (shift == 0.0) PetscFunctionReturn(0);
1460 
1461   if (v->ops->shift) PetscUseTypeMethod(v, shift, shift);
1462   else {
1463     PetscCall(VecGetLocalSize(v, &n));
1464     PetscCall(VecGetArray(v, &x));
1465     for (i = 0; i < n; i++) x[i] += shift;
1466     PetscCall(VecRestoreArray(v, &x));
1467   }
1468   PetscFunctionReturn(0);
1469 }
1470 
1471 /*@
1472    VecAbs - Replaces every element in a vector with its absolute value.
1473 
1474    Logically Collective on Vec
1475 
1476    Input Parameters:
1477 .  v - the vector
1478 
1479    Level: intermediate
1480 
1481 @*/
1482 PetscErrorCode VecAbs(Vec v) {
1483   PetscInt     i, n;
1484   PetscScalar *x;
1485 
1486   PetscFunctionBegin;
1487   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
1488   PetscCall(VecSetErrorIfLocked(v, 1));
1489 
1490   if (v->ops->abs) {
1491     PetscUseTypeMethod(v, abs);
1492   } else {
1493     PetscCall(VecGetLocalSize(v, &n));
1494     PetscCall(VecGetArray(v, &x));
1495     for (i = 0; i < n; i++) x[i] = PetscAbsScalar(x[i]);
1496     PetscCall(VecRestoreArray(v, &x));
1497   }
1498   PetscFunctionReturn(0);
1499 }
1500 
1501 /*@
1502   VecPermute - Permutes a vector in place using the given ordering.
1503 
1504   Input Parameters:
1505 + vec   - The vector
1506 . order - The ordering
1507 - inv   - The flag for inverting the permutation
1508 
1509   Level: beginner
1510 
1511   Note: This function does not yet support parallel Index Sets with non-local permutations
1512 
1513 .seealso: `MatPermute()`
1514 @*/
1515 PetscErrorCode VecPermute(Vec x, IS row, PetscBool inv) {
1516   const PetscScalar *array;
1517   PetscScalar       *newArray;
1518   const PetscInt    *idx;
1519   PetscInt           i, rstart, rend;
1520 
1521   PetscFunctionBegin;
1522   PetscValidHeaderSpecific(x, VEC_CLASSID, 1);
1523   PetscValidHeaderSpecific(row, IS_CLASSID, 2);
1524   PetscCall(VecSetErrorIfLocked(x, 1));
1525   PetscCall(VecGetOwnershipRange(x, &rstart, &rend));
1526   PetscCall(ISGetIndices(row, &idx));
1527   PetscCall(VecGetArrayRead(x, &array));
1528   PetscCall(PetscMalloc1(x->map->n, &newArray));
1529   if (PetscDefined(USE_DEBUG)) {
1530     for (i = 0; i < x->map->n; i++) PetscCheck(!(idx[i] < rstart) && !(idx[i] >= rend), PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Permutation index %" PetscInt_FMT " is out of bounds: %" PetscInt_FMT, i, idx[i]);
1531   }
1532   if (!inv) {
1533     for (i = 0; i < x->map->n; i++) newArray[i] = array[idx[i] - rstart];
1534   } else {
1535     for (i = 0; i < x->map->n; i++) newArray[idx[i] - rstart] = array[i];
1536   }
1537   PetscCall(VecRestoreArrayRead(x, &array));
1538   PetscCall(ISRestoreIndices(row, &idx));
1539   PetscCall(VecReplaceArray(x, newArray));
1540   PetscFunctionReturn(0);
1541 }
1542 
1543 /*@
1544    VecEqual - Compares two vectors. Returns true if the two vectors are either pointing to the same memory buffer,
1545    or if the two vectors have the same local and global layout as well as bitwise equality of all entries.
1546    Does NOT take round-off errors into account.
1547 
1548    Collective on Vec
1549 
1550    Input Parameters:
1551 +  vec1 - the first vector
1552 -  vec2 - the second vector
1553 
1554    Output Parameter:
1555 .  flg - PETSC_TRUE if the vectors are equal; PETSC_FALSE otherwise.
1556 
1557    Level: intermediate
1558 @*/
1559 PetscErrorCode VecEqual(Vec vec1, Vec vec2, PetscBool *flg) {
1560   const PetscScalar *v1, *v2;
1561   PetscInt           n1, n2, N1, N2;
1562   PetscBool          flg1;
1563 
1564   PetscFunctionBegin;
1565   PetscValidHeaderSpecific(vec1, VEC_CLASSID, 1);
1566   PetscValidHeaderSpecific(vec2, VEC_CLASSID, 2);
1567   PetscValidBoolPointer(flg, 3);
1568   if (vec1 == vec2) *flg = PETSC_TRUE;
1569   else {
1570     PetscCall(VecGetSize(vec1, &N1));
1571     PetscCall(VecGetSize(vec2, &N2));
1572     if (N1 != N2) flg1 = PETSC_FALSE;
1573     else {
1574       PetscCall(VecGetLocalSize(vec1, &n1));
1575       PetscCall(VecGetLocalSize(vec2, &n2));
1576       if (n1 != n2) flg1 = PETSC_FALSE;
1577       else {
1578         PetscCall(VecGetArrayRead(vec1, &v1));
1579         PetscCall(VecGetArrayRead(vec2, &v2));
1580         PetscCall(PetscArraycmp(v1, v2, n1, &flg1));
1581         PetscCall(VecRestoreArrayRead(vec1, &v1));
1582         PetscCall(VecRestoreArrayRead(vec2, &v2));
1583       }
1584     }
1585     /* combine results from all processors */
1586     PetscCall(MPIU_Allreduce(&flg1, flg, 1, MPIU_BOOL, MPI_MIN, PetscObjectComm((PetscObject)vec1)));
1587   }
1588   PetscFunctionReturn(0);
1589 }
1590 
1591 /*@
1592    VecUniqueEntries - Compute the number of unique entries, and those entries
1593 
1594    Collective on Vec
1595 
1596    Input Parameter:
1597 .  vec - the vector
1598 
1599    Output Parameters:
1600 +  n - The number of unique entries
1601 -  e - The entries
1602 
1603    Level: intermediate
1604 
1605 @*/
1606 PetscErrorCode VecUniqueEntries(Vec vec, PetscInt *n, PetscScalar **e) {
1607   const PetscScalar *v;
1608   PetscScalar       *tmp, *vals;
1609   PetscMPIInt       *N, *displs, l;
1610   PetscInt           ng, m, i, j, p;
1611   PetscMPIInt        size;
1612 
1613   PetscFunctionBegin;
1614   PetscValidHeaderSpecific(vec, VEC_CLASSID, 1);
1615   PetscValidIntPointer(n, 2);
1616   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)vec), &size));
1617   PetscCall(VecGetLocalSize(vec, &m));
1618   PetscCall(VecGetArrayRead(vec, &v));
1619   PetscCall(PetscMalloc2(m, &tmp, size, &N));
1620   for (i = 0, j = 0, l = 0; i < m; ++i) {
1621     /* Can speed this up with sorting */
1622     for (j = 0; j < l; ++j) {
1623       if (v[i] == tmp[j]) break;
1624     }
1625     if (j == l) {
1626       tmp[j] = v[i];
1627       ++l;
1628     }
1629   }
1630   PetscCall(VecRestoreArrayRead(vec, &v));
1631   /* Gather serial results */
1632   PetscCallMPI(MPI_Allgather(&l, 1, MPI_INT, N, 1, MPI_INT, PetscObjectComm((PetscObject)vec)));
1633   for (p = 0, ng = 0; p < size; ++p) ng += N[p];
1634   PetscCall(PetscMalloc2(ng, &vals, size + 1, &displs));
1635   for (p = 1, displs[0] = 0; p <= size; ++p) displs[p] = displs[p - 1] + N[p - 1];
1636   PetscCallMPI(MPI_Allgatherv(tmp, l, MPIU_SCALAR, vals, N, displs, MPIU_SCALAR, PetscObjectComm((PetscObject)vec)));
1637   /* Find unique entries */
1638 #ifdef PETSC_USE_COMPLEX
1639   SETERRQ(PetscObjectComm((PetscObject)vec), PETSC_ERR_SUP, "Does not work with complex numbers");
1640 #else
1641   *n = displs[size];
1642   PetscCall(PetscSortRemoveDupsReal(n, (PetscReal *)vals));
1643   if (e) {
1644     PetscValidPointer(e, 3);
1645     PetscCall(PetscMalloc1(*n, e));
1646     for (i = 0; i < *n; ++i) (*e)[i] = vals[i];
1647   }
1648   PetscCall(PetscFree2(vals, displs));
1649   PetscCall(PetscFree2(tmp, N));
1650   PetscFunctionReturn(0);
1651 #endif
1652 }
1653