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