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: }