Actual source code: comb.c
2: /*
3: Split phase global vector reductions with support for combining the
4: communication portion of several operations. Using MPI-1.1 support only
6: The idea for this and much of the initial code is contributed by
7: Victor Eijkhout.
9: Usage:
10: VecDotBegin(Vec,Vec,PetscScalar *);
11: VecNormBegin(Vec,NormType,PetscReal *);
12: ....
13: VecDotEnd(Vec,Vec,PetscScalar *);
14: VecNormEnd(Vec,NormType,PetscReal *);
16: Limitations:
17: - The order of the xxxEnd() functions MUST be in the same order
18: as the xxxBegin(). There is extensive error checking to try to
19: insure that the user calls the routines in the correct order
20: */
22: #include <private/vecimpl.h> /*I "petscvec.h" I*/
24: #define STATE_BEGIN 0
25: #define STATE_END 1
27: #define REDUCE_SUM 0
28: #define REDUCE_MAX 1
29: #define REDUCE_MIN 2
31: typedef struct {
32: MPI_Comm comm;
33: PetscScalar *lvalues; /* this are the reduced values before call to MPI_Allreduce() */
34: PetscScalar *gvalues; /* values after call to MPI_Allreduce() */
35: void **invecs; /* for debugging only, vector/memory used with each op */
36: PetscInt *reducetype; /* is particular value to be summed or maxed? */
37: PetscInt state; /* are we calling xxxBegin() or xxxEnd()? */
38: PetscInt maxops; /* total amount of space we have for requests */
39: PetscInt numopsbegin; /* number of requests that have been queued in */
40: PetscInt numopsend; /* number of requests that have been gotten by user */
41: } PetscSplitReduction;
42: /*
43: Note: the lvalues and gvalues are twice as long as maxops, this is to allow the second half of
44: the entries to have a flag indicating if they are REDUCE_SUM, REDUCE_MAX, or REDUCE_MIN these are used by
45: the custom reduction operation that replaces MPI_SUM, MPI_MAX, or MPI_MIN in the case when a reduction involves
46: some of each.
47: */
51: /*
52: PetscSplitReductionCreate - Creates a data structure to contain the queued information.
53: */
54: PetscErrorCode PetscSplitReductionCreate(MPI_Comm comm,PetscSplitReduction **sr)
55: {
59: PetscNew(PetscSplitReduction,sr);
60: (*sr)->numopsbegin = 0;
61: (*sr)->numopsend = 0;
62: (*sr)->state = STATE_BEGIN;
63: (*sr)->maxops = 32;
64: PetscMalloc(2*32*sizeof(PetscScalar),&(*sr)->lvalues);
65: PetscMalloc(2*32*sizeof(PetscScalar),&(*sr)->gvalues);
66: PetscMalloc(32*sizeof(void*),&(*sr)->invecs);
67: (*sr)->comm = comm;
68: PetscMalloc(32*sizeof(PetscInt),&(*sr)->reducetype);
69: return(0);
70: }
72: /*
73: This function is the MPI reduction operation used when there is
74: a combination of sums and max in the reduction. The call below to
75: MPI_Op_create() converts the function PetscSplitReduction_Local() to the
76: MPI operator PetscSplitReduction_Op.
77: */
78: MPI_Op PetscSplitReduction_Op = 0;
83: void MPIAPI PetscSplitReduction_Local(void *in,void *out,PetscMPIInt *cnt,MPI_Datatype *datatype)
84: {
85: PetscScalar *xin = (PetscScalar *)in,*xout = (PetscScalar*)out;
86: PetscInt i,count = (PetscInt)*cnt;
89: if (*datatype != MPIU_REAL) {
90: (*PetscErrorPrintf)("Can only handle MPIU_REAL data types");
91: MPI_Abort(MPI_COMM_WORLD,1);
92: }
93: #if defined(PETSC_USE_COMPLEX)
94: count = count/2;
95: #endif
96: count = count/2;
97: for (i=0; i<count; i++) {
98: if (((int)PetscRealPart(xin[count+i])) == REDUCE_SUM) { /* second half of xin[] is flags for reduction type */
99: xout[i] += xin[i];
100: } else if ((PetscInt)PetscRealPart(xin[count+i]) == REDUCE_MAX) {
101: xout[i] = PetscMax(*(PetscReal *)(xout+i),*(PetscReal *)(xin+i));
102: } else if ((PetscInt)PetscRealPart(xin[count+i]) == REDUCE_MIN) {
103: xout[i] = PetscMin(*(PetscReal *)(xout+i),*(PetscReal *)(xin+i));
104: } else {
105: (*PetscErrorPrintf)("Reduction type input is not REDUCE_SUM, REDUCE_MAX, or REDUCE_MIN");
106: MPI_Abort(MPI_COMM_WORLD,1);
107: }
108: }
109: PetscFunctionReturnVoid();
110: }
115: /*
116: PetscSplitReductionApply - Actually do the communication required for a split phase reduction
117: */
118: PetscErrorCode PetscSplitReductionApply(PetscSplitReduction *sr)
119: {
121: PetscInt i,numops = sr->numopsbegin,*reducetype = sr->reducetype;
122: PetscScalar *lvalues = sr->lvalues,*gvalues = sr->gvalues;
123: PetscInt sum_flg = 0,max_flg = 0, min_flg = 0;
124: MPI_Comm comm = sr->comm;
125: PetscMPIInt size;
128: if (sr->numopsend > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Cannot call this after VecxxxEnd() has been called");
129: PetscLogEventBarrierBegin(VEC_ReduceBarrier,0,0,0,0,comm);
130: MPI_Comm_size(sr->comm,&size);
131: if (size == 1) {
132: PetscMemcpy(gvalues,lvalues,numops*sizeof(PetscScalar));
133: } else {
134: /* determine if all reductions are sum, max, or min */
135: for (i=0; i<numops; i++) {
136: if (reducetype[i] == REDUCE_MAX) {
137: max_flg = 1;
138: } else if (reducetype[i] == REDUCE_SUM) {
139: sum_flg = 1;
140: } else if (reducetype[i] == REDUCE_MIN) {
141: min_flg = 1;
142: } else {
143: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error in PetscSplitReduction() data structure, probably memory corruption");
144: }
145: }
146: if (sum_flg + max_flg + min_flg > 1) {
147: /*
148: after all the entires in lvalues we store the reducetype flags to indicate
149: to the reduction operations what are sums and what are max
150: */
151: for (i=0; i<numops; i++) {
152: lvalues[numops+i] = reducetype[i];
153: }
154: #if defined(PETSC_USE_COMPLEX)
155: MPI_Allreduce(lvalues,gvalues,2*2*numops,MPIU_REAL,PetscSplitReduction_Op,comm);
156: #else
157: MPI_Allreduce(lvalues,gvalues,2*numops,MPIU_REAL,PetscSplitReduction_Op,comm);
158: #endif
159: } else if (max_flg) {
160: #if defined(PETSC_USE_COMPLEX)
161: /*
162: complex case we max both the real and imaginary parts, the imaginary part
163: is just ignored later
164: */
165: MPI_Allreduce(lvalues,gvalues,2*numops,MPIU_REAL,MPIU_MAX,comm);
166: #else
167: MPI_Allreduce(lvalues,gvalues,numops,MPIU_REAL,MPIU_MAX,comm);
168: #endif
169: } else if (min_flg) {
170: #if defined(PETSC_USE_COMPLEX)
171: /*
172: complex case we min both the real and imaginary parts, the imaginary part
173: is just ignored later
174: */
175: MPI_Allreduce(lvalues,gvalues,2*numops,MPIU_REAL,MPIU_MIN,comm);
176: #else
177: MPI_Allreduce(lvalues,gvalues,numops,MPIU_REAL,MPIU_MIN,comm);
178: #endif
179: } else {
180: MPI_Allreduce(lvalues,gvalues,numops,MPIU_SCALAR,MPIU_SUM,comm);
181: }
182: }
183: sr->state = STATE_END;
184: sr->numopsend = 0;
185: PetscLogEventBarrierEnd(VEC_ReduceBarrier,0,0,0,0,comm);
186: return(0);
187: }
192: /*
193: PetscSplitReductionExtend - Double the amount of space (slots) allocated for a split reduction object.
194: */
195: PetscErrorCode PetscSplitReductionExtend(PetscSplitReduction *sr)
196: {
198: PetscInt maxops = sr->maxops,*reducetype = sr->reducetype;
199: PetscScalar *lvalues = sr->lvalues,*gvalues = sr->gvalues;
200: void *invecs = sr->invecs;
203: sr->maxops = 2*maxops;
204: PetscMalloc(2*2*maxops*sizeof(PetscScalar),&sr->lvalues);
205: PetscMalloc(2*2*maxops*sizeof(PetscScalar),&sr->gvalues);
206: PetscMalloc(2*maxops*sizeof(PetscInt),&sr->reducetype);
207: PetscMalloc(2*maxops*sizeof(void*),&sr->invecs);
208: PetscMemcpy(sr->lvalues,lvalues,maxops*sizeof(PetscScalar));
209: PetscMemcpy(sr->gvalues,gvalues,maxops*sizeof(PetscScalar));
210: PetscMemcpy(sr->reducetype,reducetype,maxops*sizeof(PetscInt));
211: PetscMemcpy(sr->invecs,invecs,maxops*sizeof(void*));
212: PetscFree(lvalues);
213: PetscFree(gvalues);
214: PetscFree(reducetype);
215: PetscFree(invecs);
216: return(0);
217: }
221: PetscErrorCode PetscSplitReductionDestroy(PetscSplitReduction *sr)
222: {
226: PetscFree(sr->lvalues);
227: PetscFree(sr->gvalues);
228: PetscFree(sr->reducetype);
229: PetscFree(sr->invecs);
230: PetscFree(sr);
231: return(0);
232: }
234: static PetscMPIInt Petsc_Reduction_keyval = MPI_KEYVAL_INVALID;
239: /*
240: Private routine to delete internal storage when a communicator is freed.
241: This is called by MPI, not by users.
243: The binding for the first argument changed from MPI 1.0 to 1.1; in 1.0
244: it was MPI_Comm *comm.
245: */
246: int MPIAPI Petsc_DelReduction(MPI_Comm comm,int keyval,void* attr_val,void* extra_state)
247: {
251: PetscInfo1(0,"Deleting reduction data in an MPI_Comm %ld\n",(long)comm);
252: PetscSplitReductionDestroy((PetscSplitReduction *)attr_val);
253: return(0);
254: }
257: /*
258: PetscSplitReductionGet - Gets the split reduction object from a
259: PETSc vector, creates if it does not exit.
261: */
264: PetscErrorCode PetscSplitReductionGet(MPI_Comm comm,PetscSplitReduction **sr)
265: {
267: PetscMPIInt flag;
270: if (Petsc_Reduction_keyval == MPI_KEYVAL_INVALID) {
271: /*
272: The calling sequence of the 2nd argument to this function changed
273: between MPI Standard 1.0 and the revisions 1.1 Here we match the
274: new standard, if you are using an MPI implementation that uses
275: the older version you will get a warning message about the next line;
276: it is only a warning message and should do no harm.
277: */
278: MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelReduction,&Petsc_Reduction_keyval,0);
279: }
280: MPI_Attr_get(comm,Petsc_Reduction_keyval,(void **)sr,&flag);
281: if (!flag) { /* doesn't exist yet so create it and put it in */
282: PetscSplitReductionCreate(comm,sr);
283: MPI_Attr_put(comm,Petsc_Reduction_keyval,*sr);
284: PetscInfo1(0,"Putting reduction data in an MPI_Comm %ld\n",(long)comm);
285: }
286: return(0);
287: }
289: /* ----------------------------------------------------------------------------------------------------*/
293: /*@
294: VecDotBegin - Starts a split phase dot product computation.
296: Input Parameters:
297: + x - the first vector
298: . y - the second vector
299: - result - where the result will go (can be PETSC_NULL)
301: Level: advanced
303: Notes:
304: Each call to VecDotBegin() should be paired with a call to VecDotEnd().
306: seealso: VecDotEnd(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
307: VecTDotBegin(), VecTDotEnd()
308: @*/
309: PetscErrorCode VecDotBegin(Vec x,Vec y,PetscScalar *result)
310: {
311: PetscErrorCode ierr;
312: PetscSplitReduction *sr;
313: MPI_Comm comm;
316: PetscObjectGetComm((PetscObject)x,&comm);
317: PetscSplitReductionGet(comm,&sr);
318: if (sr->state == STATE_END) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
319: if (sr->numopsbegin >= sr->maxops) {
320: PetscSplitReductionExtend(sr);
321: }
322: sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
323: sr->invecs[sr->numopsbegin] = (void*)x;
324: if (!x->ops->dot_local) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Vector does not suppport local dots");
325: PetscLogEventBegin(VEC_ReduceArithmetic,0,0,0,0);
326: (*x->ops->dot_local)(x,y,sr->lvalues+sr->numopsbegin++);
327: PetscLogEventEnd(VEC_ReduceArithmetic,0,0,0,0);
328: return(0);
329: }
333: /*@
334: VecDotEnd - Ends a split phase dot product computation.
336: Input Parameters:
337: + x - the first vector (can be PETSC_NULL)
338: . y - the second vector (can be PETSC_NULL)
339: - result - where the result will go
341: Level: advanced
343: Notes:
344: Each call to VecDotBegin() should be paired with a call to VecDotEnd().
346: seealso: VecDotBegin(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
347: VecTDotBegin(),VecTDotEnd()
349: @*/
350: PetscErrorCode VecDotEnd(Vec x,Vec y,PetscScalar *result)
351: {
352: PetscErrorCode ierr;
353: PetscSplitReduction *sr;
354: MPI_Comm comm;
357: PetscObjectGetComm((PetscObject)x,&comm);
358: PetscSplitReductionGet(comm,&sr);
359:
360: if (sr->state != STATE_END) {
361: /* this is the first call to VecxxxEnd() so do the communication */
362: PetscSplitReductionApply(sr);
363: }
365: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
366: if (x && (void*) x != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
367: if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecDotEnd() on a reduction started with VecNormBegin()");
368: *result = sr->gvalues[sr->numopsend++];
370: /*
371: We are finished getting all the results so reset to no outstanding requests
372: */
373: if (sr->numopsend == sr->numopsbegin) {
374: sr->state = STATE_BEGIN;
375: sr->numopsend = 0;
376: sr->numopsbegin = 0;
377: }
378: return(0);
379: }
383: /*@
384: VecTDotBegin - Starts a split phase transpose dot product computation.
386: Input Parameters:
387: + x - the first vector
388: . y - the second vector
389: - result - where the result will go (can be PETSC_NULL)
391: Level: advanced
393: Notes:
394: Each call to VecTDotBegin() should be paired with a call to VecTDotEnd().
396: seealso: VecTDotEnd(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
397: VecDotBegin(), VecDotEnd()
399: @*/
400: PetscErrorCode VecTDotBegin(Vec x,Vec y,PetscScalar *result)
401: {
402: PetscErrorCode ierr;
403: PetscSplitReduction *sr;
404: MPI_Comm comm;
407: PetscObjectGetComm((PetscObject)x,&comm);
408: PetscSplitReductionGet(comm,&sr);
409: if (sr->state == STATE_END) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
410: if (sr->numopsbegin >= sr->maxops) {
411: PetscSplitReductionExtend(sr);
412: }
413: sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
414: sr->invecs[sr->numopsbegin] = (void*)x;
415: if (!x->ops->tdot_local) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Vector does not suppport local dots");
416: PetscLogEventBegin(VEC_ReduceArithmetic,0,0,0,0);
417: (*x->ops->dot_local)(x,y,sr->lvalues+sr->numopsbegin++);
418: PetscLogEventEnd(VEC_ReduceArithmetic,0,0,0,0);
419: return(0);
420: }
424: /*@
425: VecTDotEnd - Ends a split phase transpose dot product computation.
427: Input Parameters:
428: + x - the first vector (can be PETSC_NULL)
429: . y - the second vector (can be PETSC_NULL)
430: - result - where the result will go
432: Level: advanced
434: Notes:
435: Each call to VecTDotBegin() should be paired with a call to VecTDotEnd().
437: seealso: VecTDotBegin(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
438: VecDotBegin(), VecDotEnd()
439: @*/
440: PetscErrorCode VecTDotEnd(Vec x,Vec y,PetscScalar *result)
441: {
445: /*
446: TDotEnd() is the same as DotEnd() so reuse the code
447: */
448: VecDotEnd(x,y,result);
449: return(0);
450: }
452: /* -------------------------------------------------------------------------*/
456: /*@
457: VecNormBegin - Starts a split phase norm computation.
459: Input Parameters:
460: + x - the first vector
461: . ntype - norm type, one of NORM_1, NORM_2, NORM_MAX, NORM_1_AND_2
462: - result - where the result will go (can be PETSC_NULL)
464: Level: advanced
466: Notes:
467: Each call to VecNormBegin() should be paired with a call to VecNormEnd().
469: .seealso: VecNormEnd(), VecNorm(), VecDot(), VecMDot(), VecDotBegin(), VecDotEnd()
471: @*/
472: PetscErrorCode VecNormBegin(Vec x,NormType ntype,PetscReal *result)
473: {
474: PetscErrorCode ierr;
475: PetscSplitReduction *sr;
476: PetscReal lresult[2];
477: MPI_Comm comm;
480: PetscObjectGetComm((PetscObject)x,&comm);
481: PetscSplitReductionGet(comm,&sr);
482: if (sr->state == STATE_END) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
483: if (sr->numopsbegin >= sr->maxops || (sr->numopsbegin == sr->maxops-1 && ntype == NORM_1_AND_2)) {
484: PetscSplitReductionExtend(sr);
485: }
486:
487: sr->invecs[sr->numopsbegin] = (void*)x;
488: if (!x->ops->norm_local) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Vector does not support local norms");
489: PetscLogEventBegin(VEC_ReduceArithmetic,0,0,0,0);
490: (*x->ops->norm_local)(x,ntype,lresult);
491: PetscLogEventEnd(VEC_ReduceArithmetic,0,0,0,0);
492: if (ntype == NORM_2) lresult[0] = lresult[0]*lresult[0];
493: if (ntype == NORM_1_AND_2) lresult[1] = lresult[1]*lresult[1];
494: if (ntype == NORM_MAX) sr->reducetype[sr->numopsbegin] = REDUCE_MAX;
495: else sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
496: sr->lvalues[sr->numopsbegin++] = lresult[0];
497: if (ntype == NORM_1_AND_2) {
498: sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
499: sr->lvalues[sr->numopsbegin++] = lresult[1];
500: }
501: return(0);
502: }
506: /*@
507: VecNormEnd - Ends a split phase norm computation.
509: Input Parameters:
510: + x - the first vector (can be PETSC_NULL)
511: . ntype - norm type, one of NORM_1, NORM_2, NORM_MAX, NORM_1_AND_2
512: - result - where the result will go
514: Level: advanced
516: Notes:
517: Each call to VecNormBegin() should be paired with a call to VecNormEnd().
519: .seealso: VecNormBegin(), VecNorm(), VecDot(), VecMDot(), VecDotBegin(), VecDotEnd()
521: @*/
522: PetscErrorCode VecNormEnd(Vec x,NormType ntype,PetscReal *result)
523: {
524: PetscErrorCode ierr;
525: PetscSplitReduction *sr;
526: MPI_Comm comm;
529: PetscObjectGetComm((PetscObject)x,&comm);
530: PetscSplitReductionGet(comm,&sr);
531:
532: if (sr->state != STATE_END) {
533: /* this is the first call to VecxxxEnd() so do the communication */
534: PetscSplitReductionApply(sr);
535: }
537: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
538: if (x && (void*)x != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
539: if (sr->reducetype[sr->numopsend] != REDUCE_MAX && ntype == NORM_MAX) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecNormEnd(,NORM_MAX,) on a reduction started with VecDotBegin() or NORM_1 or NORM_2");
540: result[0] = PetscRealPart(sr->gvalues[sr->numopsend++]);
542: if (ntype == NORM_2) {
543: result[0] = sqrt(result[0]);
544: } else if (ntype == NORM_1_AND_2) {
545: result[1] = PetscRealPart(sr->gvalues[sr->numopsend++]);
546: result[1] = sqrt(result[1]);
547: }
548: if (ntype!=NORM_1_AND_2) {
549: PetscObjectComposedDataSetReal((PetscObject)x,NormIds[ntype],result[0]);
550: }
552: if (sr->numopsend == sr->numopsbegin) {
553: sr->state = STATE_BEGIN;
554: sr->numopsend = 0;
555: sr->numopsbegin = 0;
556: }
557: return(0);
558: }
560: /*
561: Possibly add
563: PetscReductionSumBegin/End()
564: PetscReductionMaxBegin/End()
565: PetscReductionMinBegin/End()
566: or have more like MPI with a single function with flag for Op? Like first better
567: */
571: /*@
572: VecMDotBegin - Starts a split phase multiple dot product computation.
574: Input Parameters:
575: + x - the first vector
576: . nv - number of vectors
577: . y - array of vectors
578: - result - where the result will go (can be PETSC_NULL)
580: Level: advanced
582: Notes:
583: Each call to VecMDotBegin() should be paired with a call to VecMDotEnd().
585: seealso: VecMDotEnd(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
586: VecTDotBegin(), VecTDotEnd(), VecMTDotBegin(), VecMTDotEnd()
587: @*/
588: PetscErrorCode VecMDotBegin(Vec x,PetscInt nv,const Vec y[],PetscScalar result[])
589: {
590: PetscErrorCode ierr;
591: PetscSplitReduction *sr;
592: MPI_Comm comm;
593: int i;
596: PetscObjectGetComm((PetscObject)x,&comm);
597: PetscSplitReductionGet(comm,&sr);
598: if (sr->state == STATE_END) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
599: for (i=0;i<nv;i++) {
600: if (sr->numopsbegin+i >= sr->maxops) {
601: PetscSplitReductionExtend(sr);
602: }
603: sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
604: sr->invecs[sr->numopsbegin+i] = (void*)x;
605: }
606: if (!x->ops->mdot_local) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Vector does not suppport local mdots");
607: PetscLogEventBegin(VEC_ReduceArithmetic,0,0,0,0);
608: (*x->ops->mdot_local)(x,nv,y,sr->lvalues+sr->numopsbegin);
609: PetscLogEventEnd(VEC_ReduceArithmetic,0,0,0,0);
610: sr->numopsbegin += nv;
611: return(0);
612: }
616: /*@
617: VecMDotEnd - Ends a split phase multiple dot product computation.
619: Input Parameters:
620: + x - the first vector (can be PETSC_NULL)
621: . nv - number of vectors
622: - y - array of vectors (can be PETSC_NULL)
624: Output Parameters:
625: . result - where the result will go
627: Level: advanced
629: Notes:
630: Each call to VecMDotBegin() should be paired with a call to VecMDotEnd().
632: seealso: VecMDotBegin(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
633: VecTDotBegin(),VecTDotEnd(), VecMTDotBegin(), VecMTDotEnd()
635: @*/
636: PetscErrorCode VecMDotEnd(Vec x,PetscInt nv,const Vec y[],PetscScalar result[])
637: {
638: PetscErrorCode ierr;
639: PetscSplitReduction *sr;
640: MPI_Comm comm;
641: int i;
644: PetscObjectGetComm((PetscObject)x,&comm);
645: PetscSplitReductionGet(comm,&sr);
646:
647: if (sr->state != STATE_END) {
648: /* this is the first call to VecxxxEnd() so do the communication */
649: PetscSplitReductionApply(sr);
650: }
652: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
653: if (x && (void*) x != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
654: if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecDotEnd() on a reduction started with VecNormBegin()");
655: for (i=0;i<nv;i++) {
656: result[i] = sr->gvalues[sr->numopsend++];
657: }
658:
659: /*
660: We are finished getting all the results so reset to no outstanding requests
661: */
662: if (sr->numopsend == sr->numopsbegin) {
663: sr->state = STATE_BEGIN;
664: sr->numopsend = 0;
665: sr->numopsbegin = 0;
666: }
667: return(0);
668: }
672: /*@
673: VecMTDotBegin - Starts a split phase transpose multiple dot product computation.
675: Input Parameters:
676: + x - the first vector
677: . nv - number of vectors
678: . y - array of vectors
679: - result - where the result will go (can be PETSC_NULL)
681: Level: advanced
683: Notes:
684: Each call to VecMTDotBegin() should be paired with a call to VecMTDotEnd().
686: seealso: VecMTDotEnd(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
687: VecDotBegin(), VecDotEnd(), VecMDotBegin(), VecMDotEnd()
689: @*/
690: PetscErrorCode VecMTDotBegin(Vec x,PetscInt nv,const Vec y[],PetscScalar result[])
691: {
692: PetscErrorCode ierr;
693: PetscSplitReduction *sr;
694: MPI_Comm comm;
695: int i;
698: PetscObjectGetComm((PetscObject)x,&comm);
699: PetscSplitReductionGet(comm,&sr);
700: if (sr->state == STATE_END) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
701: for (i=0;i<nv;i++) {
702: if (sr->numopsbegin+i >= sr->maxops) {
703: PetscSplitReductionExtend(sr);
704: }
705: sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
706: sr->invecs[sr->numopsbegin+i] = (void*)x;
707: }
708: if (!x->ops->mtdot_local) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Vector does not suppport local mdots");
709: PetscLogEventBegin(VEC_ReduceArithmetic,0,0,0,0);
710: (*x->ops->mdot_local)(x,nv,y,sr->lvalues+sr->numopsbegin);
711: PetscLogEventEnd(VEC_ReduceArithmetic,0,0,0,0);
712: sr->numopsbegin += nv;
713: return(0);
714: }
718: /*@
719: VecMTDotEnd - Ends a split phase transpose multiple dot product computation.
721: Input Parameters:
722: + x - the first vector (can be PETSC_NULL)
723: . nv - number of vectors
724: - y - array of vectors (can be PETSC_NULL)
726: Output Parameters
727: . result - where the result will go
729: Level: advanced
731: Notes:
732: Each call to VecTDotBegin() should be paired with a call to VecTDotEnd().
734: seealso: VecMTDotBegin(), VecNormBegin(), VecNormEnd(), VecNorm(), VecDot(), VecMDot(),
735: VecDotBegin(), VecDotEnd(), VecMDotBegin(), VecMdotEnd()
736: @*/
737: PetscErrorCode VecMTDotEnd(Vec x,PetscInt nv,const Vec y[],PetscScalar result[])
738: {
742: /*
743: MTDotEnd() is the same as MDotEnd() so reuse the code
744: */
745: VecMDotEnd(x,nv,y,result);
746: return(0);
747: }