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