void
CartCellDoubleBoundsPreservingConservativeLinearRefine::refine(Patch<NDIM>& fine,
                                                               const Patch<NDIM>& coarse,
                                                               const int dst_component,
                                                               const int src_component,
                                                               const Box<NDIM>& fine_box,
                                                               const IntVector<NDIM>& ratio)
    const
{
    // Determine the box over which we can apply the bounds-preserving
    // correction, and construct a list of boxes that will not be corrected.
    bool empty_correction_box = false;
    Box<NDIM> correction_box = Box<NDIM>::refine(Box<NDIM>::coarsen(fine_box, ratio), ratio);
    for (unsigned int axis = 0; axis < NDIM; ++axis)
    {
        int& lower = correction_box.lower()(axis);
        while (lower < fine_box.lower()(axis))
        {
            lower += ratio(axis);
        }

        int& upper = correction_box.upper()(axis);
        while (upper > fine_box.upper()(axis))
        {
            upper -= ratio(axis);
        }

        if (lower >= upper)
        {
            empty_correction_box = true;
        }
    }
    const Box<NDIM> coarse_correction_box = Box<NDIM>::coarsen(correction_box, ratio);

    BoxList<NDIM> uncorrected_boxes(fine_box);
    if (!empty_correction_box)
    {
        uncorrected_boxes.removeIntersections(correction_box);
    }

    // Employ limited conservative interpolation to prolong data on the
    // correction box.
    d_conservative_linear_refine_op.refine(
        fine, coarse, dst_component, src_component, correction_box, ratio);

    // Employ constant interpolation to prolong data on the rest of the fine
    // box.
    for (BoxList<NDIM>::Iterator b(uncorrected_boxes); b; b++)
    {
        d_constant_refine_op.refine(fine, coarse, dst_component, src_component, b(), ratio);
    }

    // There is nothing left to do if the correction box is empty.
    if (empty_correction_box) return;

    // Correct the data within the correction box.
    Pointer<CellData<NDIM, double> > fdata = fine.getPatchData(dst_component);
    Pointer<CellData<NDIM, double> > cdata = coarse.getPatchData(src_component);
#if !defined(NDEBUG)
    TBOX_ASSERT(fdata);
    TBOX_ASSERT(cdata);
    TBOX_ASSERT(fdata->getDepth() == cdata->getDepth());
#endif
    const int data_depth = fdata->getDepth();
    const Box<NDIM>& patch_box_crse = coarse.getBox();
    const Index<NDIM>& patch_lower_crse = patch_box_crse.lower();
    const Index<NDIM>& patch_upper_crse = patch_box_crse.upper();
    Pointer<CartesianPatchGeometry<NDIM> > pgeom_crse = coarse.getPatchGeometry();
    for (int depth = 0; depth < data_depth; ++depth)
    {
        for (Box<NDIM>::Iterator b(coarse_correction_box); b; b++)
        {
            const Index<NDIM>& i_crse = b();
            const Index<NDIM> i_fine = i_crse * ratio;

            // Determine the lower/upper bounds.
            Box<NDIM> stencil_box_crse(i_crse, i_crse);
            for (unsigned int axis = 0; axis < NDIM; ++axis)
            {
                if (i_crse(axis) > patch_lower_crse(axis) ||
                    !pgeom_crse->getTouchesRegularBoundary(axis, 0))
                {
                    stencil_box_crse.growLower(axis, 1);
                }
                if (i_crse(axis) < patch_upper_crse(axis) ||
                    !pgeom_crse->getTouchesRegularBoundary(axis, 1))
                {
                    stencil_box_crse.growUpper(axis, 1);
                }
            }

            double l = std::numeric_limits<double>::max();
            double u = -(l - std::numeric_limits<double>::epsilon());
            for (Box<NDIM>::Iterator b(stencil_box_crse); b; b++)
            {
                const double& m = (*cdata)(b(), depth);
                l = std::min(l, m);
                u = std::max(u, m);
            }

            // Force all refined data to lie within the bounds, accumulating the
            // discrepancy.
            Box<NDIM> stencil_box_fine(i_fine, i_fine);
            stencil_box_fine.growUpper(ratio - IntVector<NDIM>(1));
            double Delta = 0.0;
            for (Box<NDIM>::Iterator b(stencil_box_fine); b; b++)
            {
                double& m = (*fdata)(b(), depth);
                Delta += std::max(0.0, m - u) - std::max(0.0, l - m);
                m = std::max(std::min(m, u), l);
            }

            // Distribute the discrepancy to maintain conservation.
            if (Delta >= std::numeric_limits<double>::epsilon())
            {
                double K = 0.0;
                for (Box<NDIM>::Iterator b(stencil_box_fine); b; b++)
                {
                    const double& m = (*fdata)(b(), depth);
                    double k = u - m;
                    K += k;
                }
                for (Box<NDIM>::Iterator b(stencil_box_fine); b; b++)
                {
                    double& m = (*fdata)(b(), depth);
                    double k = u - m;
                    m += Delta * k / K;
                }
            }
            else if (Delta <= -std::numeric_limits<double>::epsilon())
            {
                double K = 0.0;
                for (Box<NDIM>::Iterator b(stencil_box_fine); b; b++)
                {
                    const double& m = (*fdata)(b(), depth);
                    double k = m - l;
                    K += k;
                }
                for (Box<NDIM>::Iterator b(stencil_box_fine); b; b++)
                {
                    double& m = (*fdata)(b(), depth);
                    double k = m - l;
                    m += Delta * k / K;
                }
            }
        }
    }
    return;
} // refine
void CartCellDoubleQuadraticRefine::refine(Patch<NDIM>& fine,
                                           const Patch<NDIM>& coarse,
                                           const int dst_component,
                                           const int src_component,
                                           const Box<NDIM>& fine_box,
                                           const IntVector<NDIM>& ratio) const
{
    // Get the patch data.
    Pointer<CellData<NDIM, double> > fdata = fine.getPatchData(dst_component);
    Pointer<CellData<NDIM, double> > cdata = coarse.getPatchData(src_component);
#if !defined(NDEBUG)
    TBOX_ASSERT(fdata);
    TBOX_ASSERT(cdata);
    TBOX_ASSERT(fdata->getDepth() == cdata->getDepth());
#endif
    const int data_depth = fdata->getDepth();

    const Box<NDIM>& patch_box_fine = fine.getBox();
    const Index<NDIM>& patch_lower_fine = patch_box_fine.lower();
    Pointer<CartesianPatchGeometry<NDIM> > pgeom_fine = fine.getPatchGeometry();
    const double* const XLower_fine = pgeom_fine->getXLower();
    const double* const dx_fine = pgeom_fine->getDx();

    const Box<NDIM>& patch_box_crse = coarse.getBox();
    const Index<NDIM>& patch_lower_crse = patch_box_crse.lower();
    Pointer<CartesianPatchGeometry<NDIM> > pgeom_crse = coarse.getPatchGeometry();
    const double* const XLower_crse = pgeom_crse->getXLower();
    const double* const dx_crse = pgeom_crse->getDx();

    // Set all values in the fine box via quadratic interpolation from the
    // overlying coarse grid data.
    for (Box<NDIM>::Iterator b(fine_box); b; b++)
    {
        const Index<NDIM>& i_fine = b();
        const Index<NDIM> i_crse = coarsen(i_fine, ratio);

        // Determine the interpolation stencil in the coarse index space.
        Box<NDIM> stencil_box_crse(i_crse, i_crse);
        stencil_box_crse.grow(IntVector<NDIM>(1));

        // Determine the interpolation weights.
        static const int degree = 2;
        boost::array<boost::array<double, degree + 1>, NDIM> wgts(
            array_constant<boost::array<double, degree + 1>, NDIM>(
                boost::array<double, degree + 1>(array_constant<double, degree + 1>(0.0))));
        for (unsigned int axis = 0; axis < NDIM; ++axis)
        {
            const double X =
                XLower_fine[axis] + dx_fine[axis] * (static_cast<double>(i_fine(axis) - patch_lower_fine(axis)) + 0.5);
            std::vector<double> X_crse(degree + 1, 0.0);
            for (int i_crse = stencil_box_crse.lower()(axis), k = 0; i_crse <= stencil_box_crse.upper()(axis);
                 ++i_crse, ++k)
            {
                X_crse[k] =
                    XLower_crse[axis] + dx_crse[axis] * (static_cast<double>(i_crse - patch_lower_crse(axis)) + 0.5);
            }
            wgts[axis][0] = ((X - X_crse[1]) * (X - X_crse[2])) / ((X_crse[0] - X_crse[1]) * (X_crse[0] - X_crse[2]));
            wgts[axis][1] = ((X - X_crse[0]) * (X - X_crse[2])) / ((X_crse[1] - X_crse[0]) * (X_crse[1] - X_crse[2]));
            wgts[axis][2] = ((X - X_crse[0]) * (X - X_crse[1])) / ((X_crse[2] - X_crse[0]) * (X_crse[2] - X_crse[1]));
        }

        // Interpolate from the coarse grid to the fine grid.
        Index<NDIM> i_intrp;
        for (int d = 0; d < data_depth; ++d)
        {
            (*fdata)(i_fine, d) = 0.0;
#if (NDIM > 2)
            for (int i2 = 0; i2 <= degree; ++i2)
            {
                const double& wgt2 = wgts[2][i2];
                i_intrp(2) = stencil_box_crse.lower()(2) + i2;
#else
            const double wgt2 = 1.0;
#endif
#if (NDIM > 1)
                for (int i1 = 0; i1 <= degree; ++i1)
                {
                    const double& wgt1 = wgts[1][i1];
                    i_intrp(1) = stencil_box_crse.lower()(1) + i1;
#else
            const double wgt1 = 1.0;
#endif
                    for (int i0 = 0; i0 <= degree; ++i0)
                    {
                        const double& wgt0 = wgts[0][i0];
                        i_intrp(0) = stencil_box_crse.lower()(0) + i0;

                        (*fdata)(i_fine, d) += wgt0 * wgt1 * wgt2 * (*cdata)(i_intrp, d);
                    }
#if (NDIM > 1)
                }
#endif
#if (NDIM > 2)
            }
#endif
        }
    }
    return;
} // refine