Actual source code: cdf.c


  2: #include <petsc/private/vecimpl.h>
  3: #include "../src/vec/vec/utils/tagger/impls/simple.h"

  5: const char *const VecTaggerCDFMethods[VECTAGGER_CDF_NUM_METHODS] = {"gather", "iterative"};

  7: #if !defined(PETSC_USE_COMPLEX)
  8: typedef VecTaggerBox VecTaggerBoxReal;
  9: #else
 10: typedef struct {
 11:   PetscReal min;
 12:   PetscReal max;
 13: } VecTaggerBoxReal;
 14: #endif

 16: typedef struct {
 17:   VecTagger_Simple   smpl;
 18:   PetscReal          atol;
 19:   PetscReal          rtol;
 20:   PetscInt           maxit;
 21:   PetscInt           numMoments;
 22:   VecTaggerCDFMethod method;
 23: } VecTagger_CDF;

 25: static PetscErrorCode VecTaggerComputeBox_CDF_SortedArray(const PetscReal *cArray, PetscInt m, const VecTaggerBoxReal *bxs, VecTaggerBoxReal *boxes)
 26: {
 27:   PetscInt  minInd, maxInd;
 28:   PetscReal minCDF, maxCDF;

 30:   minCDF     = PetscMax(0., bxs->min);
 31:   maxCDF     = PetscMin(1., bxs->max);
 32:   minInd     = (PetscInt)(minCDF * m);
 33:   maxInd     = (PetscInt)(maxCDF * m);
 34:   boxes->min = cArray[PetscMin(minInd, m - 1)];
 35:   boxes->max = cArray[PetscMax(minInd, maxInd - 1)];
 36:   return 0;
 37: }

 39: static PetscErrorCode VecTaggerComputeBoxes_CDF_Serial(VecTagger tagger, Vec vec, PetscInt bs, VecTaggerBox *boxes)
 40: {
 41:   VecTagger_Simple *smpl = (VecTagger_Simple *)tagger->data;
 42:   Vec               vComp;
 43:   PetscInt          n, m;
 44:   PetscInt          i;
 45: #if defined(PETSC_USE_COMPLEX)
 46:   PetscReal *cReal, *cImag;
 47: #endif

 49:   VecGetLocalSize(vec, &n);
 50:   m = n / bs;
 51:   VecCreateSeq(PETSC_COMM_SELF, m, &vComp);
 52: #if defined(PETSC_USE_COMPLEX)
 53:   PetscMalloc2(m, &cReal, m, &cImag);
 54: #endif
 55:   for (i = 0; i < bs; i++) {
 56:     IS           isStride;
 57:     VecScatter   vScat;
 58:     PetscScalar *cArray;

 60:     ISCreateStride(PETSC_COMM_SELF, m, i, bs, &isStride);
 61:     VecScatterCreate(vec, isStride, vComp, NULL, &vScat);
 62:     VecScatterBegin(vScat, vec, vComp, INSERT_VALUES, SCATTER_FORWARD);
 63:     VecScatterEnd(vScat, vec, vComp, INSERT_VALUES, SCATTER_FORWARD);
 64:     VecScatterDestroy(&vScat);
 65:     ISDestroy(&isStride);

 67:     VecGetArray(vComp, &cArray);
 68: #if !defined(PETSC_USE_COMPLEX)
 69:     PetscSortReal(m, cArray);
 70:     VecTaggerComputeBox_CDF_SortedArray(cArray, m, &smpl->box[i], &boxes[i]);
 71: #else
 72:     {
 73:       PetscInt         j;
 74:       VecTaggerBoxReal realBxs, imagBxs;
 75:       VecTaggerBoxReal realBoxes, imagBoxes;

 77:       for (j = 0; j < m; j++) {
 78:         cReal[j] = PetscRealPart(cArray[j]);
 79:         cImag[j] = PetscImaginaryPart(cArray[j]);
 80:       }
 81:       PetscSortReal(m, cReal);
 82:       PetscSortReal(m, cImag);

 84:       realBxs.min = PetscRealPart(smpl->box[i].min);
 85:       realBxs.max = PetscRealPart(smpl->box[i].max);
 86:       imagBxs.min = PetscImaginaryPart(smpl->box[i].min);
 87:       imagBxs.max = PetscImaginaryPart(smpl->box[i].max);
 88:       VecTaggerComputeBox_CDF_SortedArray(cReal, m, &realBxs, &realBoxes);
 89:       VecTaggerComputeBox_CDF_SortedArray(cImag, m, &imagBxs, &imagBoxes);
 90:       boxes[i].min = PetscCMPLX(realBoxes.min, imagBoxes.min);
 91:       boxes[i].max = PetscCMPLX(realBoxes.max, imagBoxes.max);
 92:     }
 93: #endif
 94:     VecRestoreArray(vComp, &cArray);
 95:   }
 96: #if defined(PETSC_USE_COMPLEX)
 97:   PetscFree2(cReal, cImag);
 98: #endif
 99:   VecDestroy(&vComp);
100:   return 0;
101: }

103: static PetscErrorCode VecTaggerComputeBoxes_CDF_Gather(VecTagger tagger, Vec vec, PetscInt bs, VecTaggerBox *boxes)
104: {
105:   Vec         gVec = NULL;
106:   VecScatter  vScat;
107:   PetscMPIInt rank;

109:   VecScatterCreateToZero(vec, &vScat, &gVec);
110:   VecScatterBegin(vScat, vec, gVec, INSERT_VALUES, SCATTER_FORWARD);
111:   VecScatterEnd(vScat, vec, gVec, INSERT_VALUES, SCATTER_FORWARD);
112:   VecScatterDestroy(&vScat);
113:   MPI_Comm_rank(PetscObjectComm((PetscObject)vec), &rank);
114:   if (rank == 0) VecTaggerComputeBoxes_CDF_Serial(tagger, gVec, bs, boxes);
115:   MPI_Bcast((PetscScalar *)boxes, 2 * bs, MPIU_SCALAR, 0, PetscObjectComm((PetscObject)vec));
116:   VecDestroy(&gVec);
117:   return 0;
118: }

120: typedef struct _n_CDFStats {
121:   PetscReal min;
122:   PetscReal max;
123:   PetscReal moment[3];
124: } CDFStats;

126: static void MPIAPI VecTaggerCDFStatsReduce(void *a, void *b, int *len, MPI_Datatype *datatype)
127: {
128:   PetscInt  i, j, N = *len;
129:   CDFStats *A = (CDFStats *)a;
130:   CDFStats *B = (CDFStats *)b;

132:   for (i = 0; i < N; i++) {
133:     B[i].min = PetscMin(A[i].min, B[i].min);
134:     B[i].max = PetscMax(A[i].max, B[i].max);
135:     for (j = 0; j < 3; j++) B[i].moment[j] += A[i].moment[j];
136:   }
137: }

139: static PetscErrorCode CDFUtilInverseEstimate(const CDFStats *stats, PetscReal cdfTarget, PetscReal *absEst)
140: {
141:   PetscReal min, max;

143:   min     = stats->min;
144:   max     = stats->max;
145:   *absEst = min + cdfTarget * (max - min);
146:   return 0;
147: }

149: static PetscErrorCode VecTaggerComputeBox_CDF_SortedArray_Iterative(VecTagger tagger, MPI_Datatype statType, MPI_Op statReduce, const PetscReal *cArray, PetscInt m, const VecTaggerBoxReal *cdfBox, VecTaggerBoxReal *absBox)
150: {
151:   MPI_Comm       comm;
152:   VecTagger_CDF *cdf;
153:   PetscInt       maxit, i, j, k, l, M;
154:   PetscInt       bounds[2][2];
155:   PetscInt       offsets[2];
156:   PetscReal      intervalLen = cdfBox->max - cdfBox->min;
157:   PetscReal      rtol, atol;

159:   comm  = PetscObjectComm((PetscObject)tagger);
160:   cdf   = (VecTagger_CDF *)tagger->data;
161:   maxit = cdf->maxit;
162:   rtol  = cdf->rtol;
163:   atol  = cdf->atol;
164:   /* local range of sorted values that can contain the sought radix */
165:   offsets[0]   = 0;
166:   offsets[1]   = 0;
167:   bounds[0][0] = 0;
168:   bounds[0][1] = m;
169:   bounds[1][0] = 0;
170:   bounds[1][1] = m;
171:   VecTaggerComputeBox_CDF_SortedArray(cArray, m, cdfBox, absBox); /* compute a local estimate of the interval */
172:   {
173:     CDFStats stats[3];

175:     for (i = 0; i < 2; i++) { /* compute statistics of those local estimates */
176:       PetscReal val = i ? absBox->max : absBox->min;

178:       stats[i].min       = m ? val : PETSC_MAX_REAL;
179:       stats[i].max       = m ? val : PETSC_MIN_REAL;
180:       stats[i].moment[0] = m;
181:       stats[i].moment[1] = m * val;
182:       stats[i].moment[2] = m * val * val;
183:     }
184:     stats[2].min = PETSC_MAX_REAL;
185:     stats[2].max = PETSC_MAX_REAL;
186:     for (i = 0; i < 3; i++) stats[2].moment[i] = 0.;
187:     for (i = 0; i < m; i++) {
188:       PetscReal val = cArray[i];

190:       stats[2].min = PetscMin(stats[2].min, val);
191:       stats[2].max = PetscMax(stats[2].max, val);
192:       stats[2].moment[0]++;
193:       stats[2].moment[1] += val;
194:       stats[2].moment[2] += val * val;
195:     }
196:     /* reduce those statistics */
197:     MPI_Allreduce(MPI_IN_PLACE, stats, 3, statType, statReduce, comm);
198:     M = (PetscInt)stats[2].moment[0];
199:     /* use those initial statistics to get the initial (globally agreed-upon) choices for the absolute box bounds */
200:     for (i = 0; i < 2; i++) CDFUtilInverseEstimate(&stats[i], i ? cdfBox->max : cdfBox->min, (i ? &absBox->max : &absBox->min));
201:   }
202:   /* refine the estimates by computing how close they come to the desired box and refining */
203:   for (k = 0; k < maxit; k++) {
204:     PetscReal maxDiff = 0.;

206:     CDFStats stats[2][2];
207:     PetscInt newBounds[2][2][2];
208:     for (i = 0; i < 2; i++) {
209:       for (j = 0; j < 2; j++) {
210:         stats[i][j].min = PETSC_MAX_REAL;
211:         stats[i][j].max = PETSC_MIN_REAL;
212:         for (l = 0; l < 3; l++) stats[i][j].moment[l] = 0.;
213:         newBounds[i][j][0] = PetscMax(bounds[i][0], bounds[i][1]);
214:         newBounds[i][j][1] = PetscMin(bounds[i][0], bounds[i][1]);
215:       }
216:     }
217:     for (i = 0; i < 2; i++) {
218:       for (j = 0; j < bounds[i][1] - bounds[i][0]; j++) {
219:         PetscInt  thisInd = bounds[i][0] + j;
220:         PetscReal val     = cArray[thisInd];
221:         PetscInt  section;
222:         if (!i) {
223:           section = (val < absBox->min) ? 0 : 1;
224:         } else {
225:           section = (val <= absBox->max) ? 0 : 1;
226:         }
227:         stats[i][section].min = PetscMin(stats[i][section].min, val);
228:         stats[i][section].max = PetscMax(stats[i][section].max, val);
229:         stats[i][section].moment[0]++;
230:         stats[i][section].moment[1] += val;
231:         stats[i][section].moment[2] += val * val;
232:         newBounds[i][section][0] = PetscMin(newBounds[i][section][0], thisInd);
233:         newBounds[i][section][1] = PetscMax(newBounds[i][section][0], thisInd + 1);
234:       }
235:     }
236:     MPI_Allreduce(MPI_IN_PLACE, stats, 4, statType, statReduce, comm);
237:     for (i = 0; i < 2; i++) {
238:       PetscInt  totalLessThan = offsets[i] + stats[i][0].moment[0];
239:       PetscReal cdfOfAbs      = (PetscReal)totalLessThan / (PetscReal)M;
240:       PetscReal diff;
241:       PetscInt  section;

243:       if (cdfOfAbs == (i ? cdfBox->max : cdfBox->min)) {
244:         offsets[i]   = totalLessThan;
245:         bounds[i][0] = bounds[i][1] = 0;
246:         continue;
247:       }
248:       if (cdfOfAbs > (i ? cdfBox->max : cdfBox->min)) { /* the correct absolute value lies in the lower section */
249:         section = 0;
250:       } else {
251:         section    = 1;
252:         offsets[i] = totalLessThan;
253:       }
254:       for (j = 0; j < 2; j++) bounds[i][j] = newBounds[i][section][j];
255:       CDFUtilInverseEstimate(&stats[i][section], ((i ? cdfBox->max : cdfBox->min) - ((PetscReal)offsets[i] / (PetscReal)M)) / stats[i][section].moment[0], (i ? &absBox->max : &absBox->min));
256:       diff    = PetscAbs(cdfOfAbs - (i ? cdfBox->max : cdfBox->min));
257:       maxDiff = PetscMax(maxDiff, diff);
258:     }
259:     if (!maxDiff) return 0;
260:     if ((atol || rtol) && ((!atol) || (maxDiff <= atol)) && ((!rtol) || (maxDiff <= rtol * intervalLen))) break;
261:   }
262:   return 0;
263: }

265: static PetscErrorCode VecTaggerComputeBoxes_CDF_Iterative(VecTagger tagger, Vec vec, PetscInt bs, VecTaggerBox *boxes)
266: {
267:   VecTagger_CDF    *cdf  = (VecTagger_CDF *)tagger->data;
268:   VecTagger_Simple *smpl = &(cdf->smpl);
269:   Vec               vComp;
270:   PetscInt          i, N, M, n, m, rstart;
271: #if defined(PETSC_USE_COMPLEX)
272:   PetscReal *cReal, *cImag;
273: #endif
274:   MPI_Comm     comm;
275:   MPI_Datatype statType;
276:   MPI_Op       statReduce;

278:   comm = PetscObjectComm((PetscObject)vec);
279:   VecGetSize(vec, &N);
280:   VecGetLocalSize(vec, &n);
281:   M = N / bs;
282:   m = n / bs;
283:   VecCreateMPI(comm, m, M, &vComp);
284:   VecSetUp(vComp);
285:   VecGetOwnershipRange(vComp, &rstart, NULL);
286: #if defined(PETSC_USE_COMPLEX)
287:   PetscMalloc2(m, &cReal, m, &cImag);
288: #endif
289:   MPI_Type_contiguous(5, MPIU_REAL, &statType);
290:   MPI_Type_commit(&statType);
291:   MPI_Op_create(VecTaggerCDFStatsReduce, 1, &statReduce);
292:   for (i = 0; i < bs; i++) {
293:     IS           isStride;
294:     VecScatter   vScat;
295:     PetscScalar *cArray;

297:     ISCreateStride(comm, m, bs * rstart + i, bs, &isStride);
298:     VecScatterCreate(vec, isStride, vComp, NULL, &vScat);
299:     VecScatterBegin(vScat, vec, vComp, INSERT_VALUES, SCATTER_FORWARD);
300:     VecScatterEnd(vScat, vec, vComp, INSERT_VALUES, SCATTER_FORWARD);
301:     VecScatterDestroy(&vScat);
302:     ISDestroy(&isStride);

304:     VecGetArray(vComp, &cArray);
305: #if !defined(PETSC_USE_COMPLEX)
306:     PetscSortReal(m, cArray);
307:     VecTaggerComputeBox_CDF_SortedArray_Iterative(tagger, statType, statReduce, cArray, m, &smpl->box[i], &boxes[i]);
308: #else
309:     {
310:       PetscInt         j;
311:       VecTaggerBoxReal realBxs, imagBxs;
312:       VecTaggerBoxReal realBoxes, imagBoxes;

314:       for (j = 0; j < m; j++) {
315:         cReal[j] = PetscRealPart(cArray[j]);
316:         cImag[j] = PetscImaginaryPart(cArray[j]);
317:       }
318:       PetscSortReal(m, cReal);
319:       PetscSortReal(m, cImag);

321:       realBxs.min = PetscRealPart(smpl->box[i].min);
322:       realBxs.max = PetscRealPart(smpl->box[i].max);
323:       imagBxs.min = PetscImaginaryPart(smpl->box[i].min);
324:       imagBxs.max = PetscImaginaryPart(smpl->box[i].max);
325:       VecTaggerComputeBox_CDF_SortedArray_Iterative(tagger, statType, statReduce, cReal, m, &realBxs, &realBoxes);
326:       VecTaggerComputeBox_CDF_SortedArray_Iterative(tagger, statType, statReduce, cImag, m, &imagBxs, &imagBoxes);
327:       boxes[i].min = PetscCMPLX(realBoxes.min, imagBoxes.min);
328:       boxes[i].max = PetscCMPLX(realBoxes.max, imagBoxes.max);
329:     }
330: #endif
331:     VecRestoreArray(vComp, &cArray);
332:   }
333:   MPI_Op_free(&statReduce);
334:   MPI_Type_free(&statType);
335: #if defined(PETSC_USE_COMPLEX)
336:   PetscFree2(cReal, cImag);
337: #endif
338:   VecDestroy(&vComp);
339:   return 0;
340: }

342: static PetscErrorCode VecTaggerComputeBoxes_CDF(VecTagger tagger, Vec vec, PetscInt *numBoxes, VecTaggerBox **boxes, PetscBool *listed)
343: {
344:   VecTagger_CDF *cuml = (VecTagger_CDF *)tagger->data;
345:   PetscMPIInt    size;
346:   PetscInt       bs;
347:   VecTaggerBox  *bxs;

349:   VecTaggerGetBlockSize(tagger, &bs);
350:   *numBoxes = 1;
351:   PetscMalloc1(bs, &bxs);
352:   MPI_Comm_size(PetscObjectComm((PetscObject)tagger), &size);
353:   if (size == 1) {
354:     VecTaggerComputeBoxes_CDF_Serial(tagger, vec, bs, bxs);
355:     *boxes = bxs;
356:     return 0;
357:   }
358:   switch (cuml->method) {
359:   case VECTAGGER_CDF_GATHER:
360:     VecTaggerComputeBoxes_CDF_Gather(tagger, vec, bs, bxs);
361:     break;
362:   case VECTAGGER_CDF_ITERATIVE:
363:     VecTaggerComputeBoxes_CDF_Iterative(tagger, vec, bs, bxs);
364:     break;
365:   default:
366:     SETERRQ(PetscObjectComm((PetscObject)tagger), PETSC_ERR_SUP, "Unknown CDF calculation/estimation method.");
367:   }
368:   *boxes = bxs;
369:   if (listed) *listed = PETSC_TRUE;
370:   return 0;
371: }

373: static PetscErrorCode VecTaggerView_CDF(VecTagger tagger, PetscViewer viewer)
374: {
375:   VecTagger_CDF *cuml = (VecTagger_CDF *)tagger->data;
376:   PetscBool      iascii;
377:   PetscMPIInt    size;

379:   VecTaggerView_Simple(tagger, viewer);
380:   MPI_Comm_size(PetscObjectComm((PetscObject)tagger), &size);
381:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);
382:   if (size > 1 && iascii) {
383:     PetscViewerASCIIPrintf(viewer, "CDF computation method: %s\n", VecTaggerCDFMethods[cuml->method]);
384:     if (cuml->method == VECTAGGER_CDF_ITERATIVE) {
385:       PetscViewerASCIIPushTab(viewer);
386:       PetscViewerASCIIPrintf(viewer, "max its: %" PetscInt_FMT ", abs tol: %g, rel tol %g\n", cuml->maxit, (double)cuml->atol, (double)cuml->rtol);
387:       PetscViewerASCIIPopTab(viewer);
388:     }
389:   }
390:   return 0;
391: }

393: static PetscErrorCode VecTaggerSetFromOptions_CDF(VecTagger tagger, PetscOptionItems *PetscOptionsObject)
394: {
395:   VecTagger_CDF *cuml = (VecTagger_CDF *)tagger->data;
396:   PetscInt       method;
397:   PetscBool      set;

399:   VecTaggerSetFromOptions_Simple(tagger, PetscOptionsObject);
400:   PetscOptionsHeadBegin(PetscOptionsObject, "VecTagger options for CDF boxes");
401:   PetscOptionsEList("-vec_tagger_cdf_method", "Method for computing absolute boxes from CDF boxes", "VecTaggerCDFSetMethod()", VecTaggerCDFMethods, VECTAGGER_CDF_NUM_METHODS, VecTaggerCDFMethods[cuml->method], &method, &set);
402:   if (set) cuml->method = (VecTaggerCDFMethod)method;
403:   PetscOptionsInt("-vec_tagger_cdf_max_it", "Maximum iterations for iterative computation of absolute boxes from CDF boxes", "VecTaggerCDFIterativeSetTolerances()", cuml->maxit, &cuml->maxit, NULL);
404:   PetscOptionsReal("-vec_tagger_cdf_rtol", "Maximum relative tolerance for iterative computation of absolute boxes from CDF boxes", "VecTaggerCDFIterativeSetTolerances()", cuml->rtol, &cuml->rtol, NULL);
405:   PetscOptionsReal("-vec_tagger_cdf_atol", "Maximum absolute tolerance for iterative computation of absolute boxes from CDF boxes", "VecTaggerCDFIterativeSetTolerances()", cuml->atol, &cuml->atol, NULL);
406:   PetscOptionsHeadEnd();
407:   return 0;
408: }

410: /*@C
411:   VecTaggerCDFSetMethod - Set the method used to compute absolute boxes from CDF boxes

413:   Logically Collective on tagger

415:   Level: advanced

417:   Input Parameters:
418: + tagger - the `VecTagger` context
419: - method - the method

421: .seealso: `Vec`, `VecTagger`, `VecTaggerCDFMethod`
422: @*/
423: PetscErrorCode VecTaggerCDFSetMethod(VecTagger tagger, VecTaggerCDFMethod method)
424: {
425:   VecTagger_CDF *cuml = (VecTagger_CDF *)tagger->data;

429:   cuml->method = method;
430:   return 0;
431: }

433: /*@C
434:   VecTaggerCDFGetMethod - Get the method used to compute absolute boxes from CDF boxes

436:   Logically Collective on tagger

438:   Level: advanced

440:   Input Parameters:
441: . tagger - the `VecTagger` context

443:   Output Parameters:
444: . method - the method

446: .seealso: `Vec`, `VecTagger`, `VecTaggerCDFMethod`
447: @*/
448: PetscErrorCode VecTaggerCDFGetMethod(VecTagger tagger, VecTaggerCDFMethod *method)
449: {
450:   VecTagger_CDF *cuml = (VecTagger_CDF *)tagger->data;

454:   *method = cuml->method;
455:   return 0;
456: }

458: /*@C
459:   VecTaggerCDFIterativeSetTolerances - Set the tolerances for iterative computation of absolute boxes from CDF boxes.

461:   Logically Collective on VecTagger

463:   Input Parameters:
464: + tagger - the VecTagger context
465: . maxit - the maximum number of iterations: 0 indicates the absolute values will be estimated from an initial guess based only on the minimum, maximum, mean, and standard deviation of the box endpoints.
466: . rtol - the acceptable relative tolerance in the absolute values from the initial guess
467: - atol - the acceptable absolute tolerance in the absolute values from the initial guess

469:   Level: advanced

471: .seealso: `VecTaggerCDFSetMethod()`
472: @*/
473: PetscErrorCode VecTaggerCDFIterativeSetTolerances(VecTagger tagger, PetscInt maxit, PetscReal rtol, PetscReal atol)
474: {
475:   VecTagger_CDF *cuml = (VecTagger_CDF *)tagger->data;

481:   cuml->maxit = maxit;
482:   cuml->rtol  = rtol;
483:   cuml->atol  = atol;
484:   return 0;
485: }

487: /*@C
488:   VecTaggerCDFIterativeGetTolerances - Get the tolerances for iterative computation of absolute boxes from CDF boxes.

490:   Logically Collective on VecTagger

492:   Input Parameter:
493: . tagger - the VecTagger context

495:   Output Parameters:
496: + maxit - the maximum number of iterations: 0 indicates the absolute values will be estimated from an initial guess based only on the minimum, maximum, mean, and standard deviation of the box endpoints.
497: . rtol - the acceptable relative tolerance in the absolute values from the initial guess
498: - atol - the acceptable absolute tolerance in the absolute values from the initial guess

500:   Level: advanced

502: .seealso: `VecTaggerCDFSetMethod()`
503: @*/
504: PetscErrorCode VecTaggerCDFIterativeGetTolerances(VecTagger tagger, PetscInt *maxit, PetscReal *rtol, PetscReal *atol)
505: {
506:   VecTagger_CDF *cuml = (VecTagger_CDF *)tagger->data;

509:   if (maxit) *maxit = cuml->maxit;
510:   if (rtol) *rtol = cuml->rtol;
511:   if (atol) *atol = cuml->atol;
512:   return 0;
513: }

515: /*@C
516:   VecTaggerCDFSetBox - Set the cumulative box defining the values to be tagged by the tagger, where cumulative boxes are subsets of [0,1], where 0 indicates the smallest value present in the vector and 1 indicates the largest.

518:   Logically Collective

520:   Input Parameters:
521: + tagger - the VecTagger context
522: - boxes - a blocksize array of VecTaggerBox boxes

524:   Level: advanced

526: .seealso: `VecTaggerCDFGetBox()`
527: @*/
528: PetscErrorCode VecTaggerCDFSetBox(VecTagger tagger, VecTaggerBox *box)
529: {
530:   VecTaggerSetBox_Simple(tagger, box);
531:   return 0;
532: }

534: /*@C
535:   VecTaggerCDFGetBox - Get the cumulative box (multi-dimensional box) defining the values to be tagged by the tagger, where cumulative boxes are subsets of [0,1], where 0 indicates the smallest value present in the vector and 1 indicates the largest.

537:   Logically Collective

539:   Input Parameter:
540: . tagger - the VecTagger context

542:   Output Parameter:
543: . boxes - a blocksize array of VecTaggerBox boxes

545:   Level: advanced

547: .seealso: `VecTaggerCDFSetBox()`
548: @*/
549: PetscErrorCode VecTaggerCDFGetBox(VecTagger tagger, const VecTaggerBox **box)
550: {
551:   VecTaggerGetBox_Simple(tagger, box);
552:   return 0;
553: }

555: PETSC_INTERN PetscErrorCode VecTaggerCreate_CDF(VecTagger tagger)
556: {
557:   VecTagger_CDF *cuml;

559:   VecTaggerCreate_Simple(tagger);
560:   PetscNew(&cuml);
561:   PetscMemcpy(&cuml->smpl, tagger->data, sizeof(VecTagger_Simple));
562:   PetscFree(tagger->data);
563:   tagger->data                = cuml;
564:   tagger->ops->view           = VecTaggerView_CDF;
565:   tagger->ops->setfromoptions = VecTaggerSetFromOptions_CDF;
566:   tagger->ops->computeboxes   = VecTaggerComputeBoxes_CDF;
567:   return 0;
568: }