BoundaryBox<NDIM>
PhysicalBoundaryUtilities::trimBoundaryCodim1Box(const BoundaryBox<NDIM>& bdry_box,
                                                 const Patch<NDIM>& patch)
{
#if !defined(NDEBUG)
    TBOX_ASSERT(bdry_box.getBoundaryType() == 1);
#endif
    // Trim a boundary box so it does not stick out past the corners of a patch.
    const Box<NDIM>& b_box = bdry_box.getBox();
    const Box<NDIM>& patch_box = patch.getBox();
    const unsigned int bdry_normal_axis = bdry_box.getLocationIndex() / 2;

    Box<NDIM> trimmed_b_box = b_box;
    for (unsigned int d = 0; d < NDIM; ++d)
    {
        if (d != bdry_normal_axis)
        {
            trimmed_b_box.lower()[d] = std::max(b_box.lower()[d], patch_box.lower()[d]);
            trimmed_b_box.upper()[d] = std::min(b_box.upper()[d], patch_box.upper()[d]);
        }
    }
    const BoundaryBox<NDIM> trimmed_bdry_box(
        trimmed_b_box, bdry_box.getBoundaryType(), bdry_box.getLocationIndex());
    return trimmed_bdry_box;
} // trimBoundaryCodim1Box
void CartCellRobinPhysBdryOp::fillGhostCellValuesCodim2(
    const int patch_data_idx,
    const Array<BoundaryBox<NDIM> >& physical_codim2_boxes,
    const IntVector<NDIM>& ghost_width_to_fill,
    const Patch<NDIM>& patch,
    const bool adjoint_op)
{
    const int n_physical_codim2_boxes = physical_codim2_boxes.size();
    if (n_physical_codim2_boxes == 0) return;

    const Box<NDIM>& patch_box = patch.getBox();
    Pointer<CartesianPatchGeometry<NDIM> > pgeom = patch.getPatchGeometry();
    Pointer<CellData<NDIM, double> > patch_data = patch.getPatchData(patch_data_idx);
    const int patch_data_depth = patch_data->getDepth();
    const int patch_data_gcw = (patch_data->getGhostCellWidth()).max();
#if !defined(NDEBUG)
    if (patch_data_gcw != (patch_data->getGhostCellWidth()).min())
    {
        TBOX_ERROR(
            "CartCellRobinPhysBdryOp::fillGhostCellValuesCodim2():\n"
            "  patch data for patch data index "
            << patch_data_idx << " does not have uniform ghost cell widths." << std::endl);
    }
#endif
    const IntVector<NDIM> gcw_to_fill =
        IntVector<NDIM>::min(patch_data->getGhostCellWidth(), ghost_width_to_fill);

    for (int n = 0; n < n_physical_codim2_boxes; ++n)
    {
        const BoundaryBox<NDIM>& bdry_box = physical_codim2_boxes[n];
        const unsigned int location_index = bdry_box.getLocationIndex();
        const Box<NDIM> bc_fill_box =
            pgeom->getBoundaryFillBox(bdry_box, patch_box, gcw_to_fill);
        for (int d = 0; d < patch_data_depth; ++d)
        {
            CC_ROBIN_PHYS_BDRY_OP_2_FC(patch_data->getPointer(d),
                                       patch_data_gcw,
                                       location_index,
                                       patch_box.lower(0),
                                       patch_box.upper(0),
                                       patch_box.lower(1),
                                       patch_box.upper(1),
#if (NDIM == 3)
                                       patch_box.lower(2),
                                       patch_box.upper(2),
#endif
                                       bc_fill_box.lower(0),
                                       bc_fill_box.upper(0),
                                       bc_fill_box.lower(1),
                                       bc_fill_box.upper(1),
#if (NDIM == 3)
                                       bc_fill_box.lower(2),
                                       bc_fill_box.upper(2),
#endif
                                       adjoint_op ? 1 : 0);
        }
    }
    return;
} // fillGhostCellValuesCodim2
void
VecCellRefineAdapter::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
{
    Pointer<VecCellData<double> > dst_data = fine  .getPatchData(dst_component);
    Pointer<VecCellData<double> > src_data = coarse.getPatchData(src_component);
#ifdef DEBUG_CHECK_ASSERTIONS
    TBOX_ASSERT(!dst_data.isNull());
    TBOX_ASSERT(!src_data.isNull());
#endif
    // Create "dummy" patches.
    Patch<NDIM> fine_cell(fine.getBox(), fine.getPatchDescriptor());
    fine_cell.setPatchGeometry(fine.getPatchGeometry());
    fine_cell.setPatchInHierarchy(fine.inHierarchy());
    fine_cell.setPatchLevelNumber(fine.getPatchLevelNumber());
    fine_cell.setPatchNumber(fine.getPatchNumber());

    Patch<NDIM> coarse_cell(coarse.getBox(), coarse.getPatchDescriptor());
    coarse_cell.setPatchGeometry(coarse.getPatchGeometry());
    coarse_cell.setPatchInHierarchy(coarse.inHierarchy());
    coarse_cell.setPatchLevelNumber(coarse.getPatchLevelNumber());
    coarse_cell.setPatchNumber(coarse.getPatchNumber());

    // Make copies of the dst and src data.
    CellData<NDIM,double> dst_cell_data(dst_data->getBox(), dst_data->getDepth(), dst_data->getGhostCellWidth());
    dst_data->copy2(dst_cell_data);
    fine_cell.allocatePatchData(dst_component);
    fine_cell.setPatchData(dst_component,Pointer<PatchData<NDIM> >(&dst_cell_data,false));

    CellData<NDIM,double> src_cell_data(src_data->getBox(), src_data->getDepth(), src_data->getGhostCellWidth());
    src_data->copy2(src_cell_data);
    coarse_cell.allocatePatchData(src_component);
    coarse_cell.setPatchData(src_component,Pointer<PatchData<NDIM> >(&src_cell_data,false));

    // Refine data from the coarse dummy patch to the fine dummy patch.
    d_cell_refine_op->refine(fine_cell, coarse_cell, dst_component, src_component, fine_box, ratio);

    // Copy the result into the VecCellData.
    dst_data->copy(dst_cell_data);
    return;
}// refine
Beispiel #4
0
void LMarkerRefine::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
{
    Pointer<LMarkerSetData> dst_mark_data = fine.getPatchData(dst_component);
    Pointer<LMarkerSetData> src_mark_data = coarse.getPatchData(src_component);

    const Box<NDIM>& fine_patch_box = fine.getBox();
    const Pointer<CartesianPatchGeometry<NDIM> > fine_patch_geom = fine.getPatchGeometry();
    const Index<NDIM>& fine_patch_lower = fine_patch_box.lower();
    const Index<NDIM>& fine_patch_upper = fine_patch_box.upper();
    const double* const fine_patchXLower = fine_patch_geom->getXLower();
    const double* const fine_patchXUpper = fine_patch_geom->getXUpper();
    const double* const fine_patchDx = fine_patch_geom->getDx();

    const Pointer<CartesianPatchGeometry<NDIM> > coarse_patch_geom = coarse.getPatchGeometry();
    const double* const coarse_patchDx = coarse_patch_geom->getDx();

    const Box<NDIM> coarse_box = Box<NDIM>::coarsen(fine_box, ratio);
    for (LMarkerSetData::SetIterator it(*src_mark_data); it; it++)
    {
        const Index<NDIM>& coarse_i = it.getIndex();
        if (coarse_box.contains(coarse_i))
        {
            const LMarkerSet& coarse_mark_set = it();
            for (LMarkerSet::const_iterator cit = coarse_mark_set.begin(); cit != coarse_mark_set.end(); ++cit)
            {
                const LMarkerSet::value_type& coarse_mark = *cit;
                const Point& X = coarse_mark->getPosition();
                const IntVector<NDIM>& offset = coarse_mark->getPeriodicOffset();
                boost::array<double, NDIM> X_shifted;
                for (unsigned int d = 0; d < NDIM; ++d)
                {
                    X_shifted[d] = X[d] + static_cast<double>(offset(d)) * coarse_patchDx[d];
                }

                const Index<NDIM> fine_i = IndexUtilities::getCellIndex(
                    X_shifted, fine_patchXLower, fine_patchXUpper, fine_patchDx, fine_patch_lower, fine_patch_upper);
                if (fine_box.contains(fine_i))
                {
                    if (!dst_mark_data->isElement(fine_i))
                    {
                        dst_mark_data->appendItemPointer(fine_i, new LMarkerSet());
                    }
                    LMarkerSet& fine_mark_set = *(dst_mark_data->getItem(fine_i));
                    fine_mark_set.push_back(coarse_mark);
                }
            }
        }
    }
    return;
} // refine
void CartCellDoubleLinearCFInterpolation::computeNormalExtension(
    Patch<NDIM>& patch,
    const IntVector<NDIM>& ratio,
    const IntVector<NDIM>& /*ghost_width_to_fill*/)
{
#if !defined(NDEBUG)
    TBOX_ASSERT(d_hierarchy);
    TBOX_ASSERT(!d_consistent_type_2_bdry);
    TBOX_ASSERT(ratio.min() == ratio.max());
#endif
    // Ensure that the fine patch is located on the expected destination level;
    // if not, we are not guaranteed to have appropriate coarse-fine interface
    // boundary box information.
    if (!patch.inHierarchy()) return;

    // Get the co-dimension 1 cf boundary boxes.
    const int patch_num = patch.getPatchNumber();
    const int patch_level_num = patch.getPatchLevelNumber();
#if !defined(NDEBUG)
    Pointer<PatchLevel<NDIM> > level = d_hierarchy->getPatchLevel(patch_level_num);
    TBOX_ASSERT(&patch == level->getPatch(patch_num).getPointer());
#endif
    const Array<BoundaryBox<NDIM> >& cf_bdry_codim1_boxes =
        d_cf_boundary[patch_level_num]->getBoundaries(patch_num, 1);
    const int n_cf_bdry_codim1_boxes = cf_bdry_codim1_boxes.size();

    // Check to see if there are any co-dimension 1 coarse-fine boundary boxes
    // associated with the patch; if not, there is nothing to do.
    if (n_cf_bdry_codim1_boxes == 0) return;

    // Get the patch data.
    for (std::set<int>::const_iterator cit = d_patch_data_indices.begin();
            cit != d_patch_data_indices.end();
            ++cit)
    {
        const int& patch_data_index = *cit;
        Pointer<CellData<NDIM, double> > data = patch.getPatchData(patch_data_index);
#if !defined(NDEBUG)
        TBOX_ASSERT(data);
#endif
        const int U_ghosts = (data->getGhostCellWidth()).max();
#if !defined(NDEBUG)
        if (U_ghosts != (data->getGhostCellWidth()).min())
        {
            TBOX_ERROR("CartCellDoubleLinearCFInterpolation::computeNormalExtension():\n"
                       << "   patch data does not have uniform ghost cell widths"
                       << std::endl);
        }
#endif
        const int data_depth = data->getDepth();
        const IntVector<NDIM> ghost_width_to_fill = GHOST_WIDTH_TO_FILL;
        Pointer<CartesianPatchGeometry<NDIM> > pgeom = patch.getPatchGeometry();
        const Box<NDIM>& patch_box = patch.getBox();
        for (int k = 0; k < n_cf_bdry_codim1_boxes; ++k)
        {
            const BoundaryBox<NDIM>& bdry_box = cf_bdry_codim1_boxes[k];
            const Box<NDIM> bc_fill_box =
                pgeom->getBoundaryFillBox(bdry_box, patch_box, ghost_width_to_fill);
            const unsigned int location_index = bdry_box.getLocationIndex();
            for (int depth = 0; depth < data_depth; ++depth)
            {
                double* const U = data->getPointer(depth);
                const int r = ratio.min();
                CC_LINEAR_NORMAL_INTERPOLATION_FC(U,
                                                  U_ghosts,
                                                  patch_box.lower(0),
                                                  patch_box.upper(0),
                                                  patch_box.lower(1),
                                                  patch_box.upper(1),
#if (NDIM == 3)
                                                  patch_box.lower(2),
                                                  patch_box.upper(2),
#endif
                                                  location_index,
                                                  r,
                                                  bc_fill_box.lower(),
                                                  bc_fill_box.upper());
            }
        }
    }
    return;
} // computeNormalExtension
void
CartSideDoubleDivPreservingRefine::postprocessRefine(Patch<NDIM>& fine,
                                                     const Patch<NDIM>& coarse,
                                                     const Box<NDIM>& unrestricted_fine_box,
                                                     const IntVector<NDIM>& ratio)
{
    // NOTE: This operator cannot fill the full ghost cell width of the
    // destination data.  We instead restrict the size of the fine box to ensure
    // that we have adequate data to apply the divergence- and curl-preserving
    // corrections.
    const Box<NDIM> fine_box = unrestricted_fine_box * Box<NDIM>::grow(fine.getBox(), 2);

#if !defined(NDEBUG)
    for (int d = 0; d < NDIM; ++d)
    {
        if (ratio(d) % 2 != 0)
        {
            TBOX_ERROR("CartSideDoubleDivPreservingRefine::postprocessRefine():\n"
                       << "  refinement ratio must be a power of 2 for divergence- and "
                          "curl-preserving refinement operator."
                       << std::endl);
        }
    }
#endif

    Pointer<SideData<NDIM, double> > fdata = fine.getPatchData(d_u_dst_idx);
#if !defined(NDEBUG)
    TBOX_ASSERT(fdata);
#endif
    const int fdata_ghosts = fdata->getGhostCellWidth().max();
#if !defined(NDEBUG)
    TBOX_ASSERT(fdata_ghosts == fdata->getGhostCellWidth().min());
#endif
    const int fdata_depth = fdata->getDepth();

    Pointer<SideData<NDIM, double> > cdata = coarse.getPatchData(d_u_dst_idx);
#if !defined(NDEBUG)
    TBOX_ASSERT(cdata);
    const int cdata_ghosts = cdata->getGhostCellWidth().max();
    TBOX_ASSERT(cdata_ghosts == cdata->getGhostCellWidth().min());
    const int cdata_depth = cdata->getDepth();
    TBOX_ASSERT(cdata_depth == fdata_depth);
#endif

    if (ratio == IntVector<NDIM>(2))
    {
        // Perform (limited) conservative prolongation of the coarse grid data.
        d_refine_op->refine(fine, coarse, d_u_dst_idx, d_u_dst_idx, fine_box, ratio);

        Pointer<SideData<NDIM, double> > u_src_data = fine.getPatchData(d_u_src_idx);
        Pointer<SideData<NDIM, double> > indicator_data = fine.getPatchData(d_indicator_idx);

        // Ensure that we do not modify any of the data from the old level by
        // setting the value of the fine grid data to equal u_src wherever the
        // indicator data equals "1".
        if (u_src_data && indicator_data)
        {
            for (unsigned int axis = 0; axis < NDIM; ++axis)
            {
                for (Box<NDIM>::Iterator b(SideGeometry<NDIM>::toSideBox(fine_box, axis)); b; b++)
                {
                    const Index<NDIM>& i = b();
                    const SideIndex<NDIM> i_s(i, axis, 0);
                    if (std::abs((*indicator_data)(i_s)-1.0) < 1.0e-12)
                    {
                        for (int depth = 0; depth < fdata_depth; ++depth)
                        {
                            (*fdata)(i_s, depth) = (*u_src_data)(i_s, depth);
                        }
                    }
                }
            }
        }

        // Reinterpolate data in the normal direction in the newly refined part
        // of the level wherever the indicator data does NOT equal "1".  Notice
        // that this loop actually modifies only data that is NOT covered by an
        // overlying coarse grid cell face.
        if (indicator_data)
        {
            for (unsigned int axis = 0; axis < NDIM; ++axis)
            {
                for (Box<NDIM>::Iterator b(SideGeometry<NDIM>::toSideBox(fine_box, axis)); b; b++)
                {
                    const Index<NDIM>& i = b();
                    const SideIndex<NDIM> i_s(i, axis, 0);
                    if (!(std::abs((*indicator_data)(i_s)-1.0) < 1.0e-12))
                    {
                        const Index<NDIM> i_coarse_lower = IndexUtilities::coarsen(i, ratio);
                        const Index<NDIM> i_lower = IndexUtilities::refine(i_coarse_lower, ratio);
                        if (i(axis) == i_lower(axis)) continue;

                        Index<NDIM> i_coarse_upper = i_coarse_lower;
                        i_coarse_upper(axis) += 1;
                        const Index<NDIM> i_upper = IndexUtilities::refine(i_coarse_upper, ratio);

                        const double w1 =
                            static_cast<double>(i(axis) - i_lower(axis)) / static_cast<double>(ratio(axis));
                        const double w0 = 1.0 - w1;

                        const SideIndex<NDIM> i_s_lower(i_lower, axis, 0);
                        const SideIndex<NDIM> i_s_upper(i_upper, axis, 0);
                        for (int depth = 0; depth < fdata_depth; ++depth)
                        {
                            (*fdata)(i_s, depth) = w0 * (*fdata)(i_s_lower, depth) + w1 * (*fdata)(i_s_upper, depth);
                        }
                    }
                }
            }
        }

        // Determine the box on which we need to compute the divergence- and
        // curl-preserving correction.
        const Box<NDIM> correction_box = Box<NDIM>::refine(Box<NDIM>::coarsen(fine_box, 2), 2);
#if !defined(NDEBUG)
        TBOX_ASSERT(fdata->getGhostBox().contains(correction_box));
#endif
        // Apply the divergence- and curl-preserving correction to the fine grid
        // data.
        Pointer<CartesianPatchGeometry<NDIM> > pgeom_fine = fine.getPatchGeometry();
        const double* const dx_fine = pgeom_fine->getDx();
        for (int d = 0; d < fdata_depth; ++d)
        {
            DIV_PRESERVING_CORRECTION_FC(fdata->getPointer(0, d),
                                         fdata->getPointer(1, d),
#if (NDIM == 3)
                                         fdata->getPointer(2, d),
#endif
                                         fdata_ghosts,
                                         fdata->getBox().lower()(0),
                                         fdata->getBox().upper()(0),
                                         fdata->getBox().lower()(1),
                                         fdata->getBox().upper()(1),
#if (NDIM == 3)
                                         fdata->getBox().lower()(2),
                                         fdata->getBox().upper()(2),
#endif
                                         correction_box.lower()(0),
                                         correction_box.upper()(0),
                                         correction_box.lower()(1),
                                         correction_box.upper()(1),
#if (NDIM == 3)
                                         correction_box.lower()(2),
                                         correction_box.upper()(2),
#endif
                                         ratio,
                                         dx_fine);
        }
    }
    else
    {
        // Setup an intermediate patch.
        const Box<NDIM> intermediate_patch_box = Box<NDIM>::refine(coarse.getBox(), 2);
        Patch<NDIM> intermediate(intermediate_patch_box, coarse.getPatchDescriptor());
        intermediate.allocatePatchData(d_u_dst_idx);

        // Setup a patch geometry object for the intermediate patch.
        Pointer<CartesianPatchGeometry<NDIM> > pgeom_coarse = coarse.getPatchGeometry();
        const IntVector<NDIM>& ratio_to_level_zero_coarse = pgeom_coarse->getRatio();
        Array<Array<bool> > touches_regular_bdry(NDIM), touches_periodic_bdry(NDIM);
        for (int axis = 0; axis < NDIM; ++axis)
        {
            touches_regular_bdry[axis].resizeArray(2);
            touches_periodic_bdry[axis].resizeArray(2);
            for (int upperlower = 0; upperlower < 2; ++upperlower)
            {
                touches_regular_bdry[axis][upperlower] = pgeom_coarse->getTouchesRegularBoundary(axis, upperlower);
                touches_periodic_bdry[axis][upperlower] = pgeom_coarse->getTouchesPeriodicBoundary(axis, upperlower);
            }
        }
        const double* const dx_coarse = pgeom_coarse->getDx();

        const IntVector<NDIM> ratio_to_level_zero_intermediate = ratio_to_level_zero_coarse * 2;
        double dx_intermediate[NDIM], x_lower_intermediate[NDIM], x_upper_intermediate[NDIM];
        for (int d = 0; d < NDIM; ++d)
        {
            dx_intermediate[d] = 0.5 * dx_coarse[d];
            x_lower_intermediate[d] = pgeom_coarse->getXLower()[d];
            x_upper_intermediate[d] = pgeom_coarse->getXUpper()[d];
        }
        intermediate.setPatchGeometry(new CartesianPatchGeometry<NDIM>(ratio_to_level_zero_intermediate,
                                                                       touches_regular_bdry,
                                                                       touches_periodic_bdry,
                                                                       dx_intermediate,
                                                                       x_lower_intermediate,
                                                                       x_upper_intermediate));

        // The intermediate box where we need to fill data must be large enough
        // to provide ghost cell values for the fine fill box.
        const Box<NDIM> intermediate_box = Box<NDIM>::grow(Box<NDIM>::coarsen(fine_box, ratio / 2), 2);

        // Setup the original velocity and indicator data.
        if (fine.checkAllocated(d_u_src_idx) && fine.checkAllocated(d_indicator_idx))
        {
            intermediate.allocatePatchData(d_u_src_idx);
            intermediate.allocatePatchData(d_indicator_idx);
            Pointer<SideData<NDIM, double> > u_src_idata = intermediate.getPatchData(d_u_src_idx);
            Pointer<SideData<NDIM, double> > indicator_idata = intermediate.getPatchData(d_indicator_idx);
            u_src_idata->fillAll(std::numeric_limits<double>::quiet_NaN());
            indicator_idata->fillAll(-1.0);
#if !defined(NDEBUG)
            Pointer<SideData<NDIM, double> > u_src_fdata = fine.getPatchData(d_u_src_idx);
            Pointer<SideData<NDIM, double> > indicator_fdata = fine.getPatchData(d_indicator_idx);
            TBOX_ASSERT(u_src_fdata->getGhostBox().contains(Box<NDIM>::refine(intermediate_box, ratio / 2)));
            TBOX_ASSERT(indicator_fdata->getGhostBox().contains(Box<NDIM>::refine(intermediate_box, ratio / 2)));
#endif
            d_coarsen_op->coarsen(intermediate, fine, d_u_src_idx, d_u_src_idx, intermediate_box, ratio / 2);
            d_coarsen_op->coarsen(intermediate, fine, d_indicator_idx, d_indicator_idx, intermediate_box, ratio / 2);
        }

        // Recursively refine from the coarse patch to the fine patch.
        postprocessRefine(intermediate, coarse, intermediate_box, 2);
        postprocessRefine(fine, intermediate, fine_box, ratio / 2);

        // Deallocate any allocated patch data.
        intermediate.deallocatePatchData(d_u_dst_idx);
        if (fine.checkAllocated(d_u_src_idx) && fine.checkAllocated(d_indicator_idx))
        {
            intermediate.deallocatePatchData(d_u_src_idx);
            intermediate.deallocatePatchData(d_indicator_idx);
        }
    }
    return;
} // postprocessRefine
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 CartCellRobinPhysBdryOp::fillGhostCellValuesCodim1(
    const int patch_data_idx,
    const Array<BoundaryBox<NDIM> >& physical_codim1_boxes,
    const double fill_time,
    const IntVector<NDIM>& ghost_width_to_fill,
    Patch<NDIM>& patch,
    const bool adjoint_op)
{
    const int n_physical_codim1_boxes = physical_codim1_boxes.size();
    if (n_physical_codim1_boxes == 0) return;

    const Box<NDIM>& patch_box = patch.getBox();
    Pointer<CartesianPatchGeometry<NDIM> > pgeom = patch.getPatchGeometry();
    const double* const dx = pgeom->getDx();
    Pointer<CellData<NDIM, double> > patch_data = patch.getPatchData(patch_data_idx);
    const int patch_data_depth = patch_data->getDepth();
    VariableDatabase<NDIM>* var_db = VariableDatabase<NDIM>::getDatabase();
    Pointer<Variable<NDIM> > var;
    var_db->mapIndexToVariable(patch_data_idx, var);
    const int patch_data_gcw = (patch_data->getGhostCellWidth()).max();
#if !defined(NDEBUG)
    if (patch_data_gcw != (patch_data->getGhostCellWidth()).min())
    {
        TBOX_ERROR(
            "CartCellRobinPhysBdryOp::fillGhostCellValuesCodim1():\n"
            "  patch data for patch data index "
            << patch_data_idx << " does not have uniform ghost cell widths." << std::endl);
    }
#endif
    const IntVector<NDIM> gcw_to_fill =
        IntVector<NDIM>::min(patch_data->getGhostCellWidth(), ghost_width_to_fill);

    // Set the boundary condition coefficients and then set the ghost cell
    // values.
    for (int n = 0; n < n_physical_codim1_boxes; ++n)
    {
        const BoundaryBox<NDIM>& bdry_box = physical_codim1_boxes[n];
        const unsigned int location_index = bdry_box.getLocationIndex();
        const Box<NDIM> bc_fill_box =
            pgeom->getBoundaryFillBox(bdry_box, patch_box, gcw_to_fill);
        const BoundaryBox<NDIM> trimmed_bdry_box(bdry_box.getBox() * bc_fill_box,
                                                 bdry_box.getBoundaryType(),
                                                 bdry_box.getLocationIndex());
        const Box<NDIM> bc_coef_box =
            PhysicalBoundaryUtilities::makeSideBoundaryCodim1Box(trimmed_bdry_box);
        Pointer<ArrayData<NDIM, double> > acoef_data =
            new ArrayData<NDIM, double>(bc_coef_box, 1);
        Pointer<ArrayData<NDIM, double> > bcoef_data =
            new ArrayData<NDIM, double>(bc_coef_box, 1);
        Pointer<ArrayData<NDIM, double> > gcoef_data =
            new ArrayData<NDIM, double>(bc_coef_box, 1);
        for (int d = 0; d < patch_data_depth; ++d)
        {
            RobinBcCoefStrategy<NDIM>* bc_coef = d_bc_coefs[d];
            ExtendedRobinBcCoefStrategy* const extended_bc_coef =
                dynamic_cast<ExtendedRobinBcCoefStrategy*>(bc_coef);
            if (extended_bc_coef)
            {
                extended_bc_coef->setTargetPatchDataIndex(patch_data_idx);
                extended_bc_coef->setHomogeneousBc(d_homogeneous_bc);
            }
            bc_coef->setBcCoefs(
                acoef_data, bcoef_data, gcoef_data, var, patch, trimmed_bdry_box, fill_time);
            if (d_homogeneous_bc && !extended_bc_coef) gcoef_data->fillAll(0.0);
            if (extended_bc_coef) extended_bc_coef->clearTargetPatchDataIndex();
            switch (location_index)
            {
            case 0: // lower x
            case 1: // upper x
                CC_ROBIN_PHYS_BDRY_OP_1_X_FC(patch_data->getPointer(d),
                                             patch_data_gcw,
                                             acoef_data->getPointer(),
                                             bcoef_data->getPointer(),
                                             gcoef_data->getPointer(),
                                             location_index,
                                             patch_box.lower(0),
                                             patch_box.upper(0),
                                             patch_box.lower(1),
                                             patch_box.upper(1),
#if (NDIM == 3)
                                             patch_box.lower(2),
                                             patch_box.upper(2),
#endif
                                             bc_fill_box.lower(1),
                                             bc_fill_box.upper(1),
#if (NDIM == 3)
                                             bc_fill_box.lower(2),
                                             bc_fill_box.upper(2),
#endif
                                             dx,
                                             adjoint_op ? 1 : 0);
                break;
            case 2: // lower y
            case 3: // upper y
                CC_ROBIN_PHYS_BDRY_OP_1_Y_FC(patch_data->getPointer(d),
                                             patch_data_gcw,
                                             acoef_data->getPointer(),
                                             bcoef_data->getPointer(),
                                             gcoef_data->getPointer(),
                                             location_index,
                                             patch_box.lower(0),
                                             patch_box.upper(0),
                                             patch_box.lower(1),
                                             patch_box.upper(1),
#if (NDIM == 3)
                                             patch_box.lower(2),
                                             patch_box.upper(2),
#endif
                                             bc_fill_box.lower(0),
                                             bc_fill_box.upper(0),
#if (NDIM == 3)
                                             bc_fill_box.lower(2),
                                             bc_fill_box.upper(2),
#endif
                                             dx,
                                             adjoint_op ? 1 : 0);
                break;
#if (NDIM == 3)
            case 4: // lower z
            case 5: // upper z
                CC_ROBIN_PHYS_BDRY_OP_1_Z_FC(patch_data->getPointer(d),
                                             patch_data_gcw,
                                             acoef_data->getPointer(),
                                             bcoef_data->getPointer(),
                                             gcoef_data->getPointer(),
                                             location_index,
                                             patch_box.lower(0),
                                             patch_box.upper(0),
                                             patch_box.lower(1),
                                             patch_box.upper(1),
                                             patch_box.lower(2),
                                             patch_box.upper(2),
                                             bc_fill_box.lower(0),
                                             bc_fill_box.upper(0),
                                             bc_fill_box.lower(1),
                                             bc_fill_box.upper(1),
                                             dx,
                                             adjoint_op ? 1 : 0);
                break;
#endif
            default:
                TBOX_ASSERT(false);
            }
        }
    }
    return;
} // fillGhostCellValuesCodim1
void muParserRobinBcCoefs::setBcCoefs(Pointer<ArrayData<NDIM, double> >& acoef_data,
                                      Pointer<ArrayData<NDIM, double> >& bcoef_data,
                                      Pointer<ArrayData<NDIM, double> >& gcoef_data,
                                      const Pointer<Variable<NDIM> >& /*variable*/,
                                      const Patch<NDIM>& patch,
                                      const BoundaryBox<NDIM>& bdry_box,
                                      double fill_time) const
{
    const Box<NDIM>& patch_box = patch.getBox();
    const Index<NDIM>& patch_lower = patch_box.lower();
    Pointer<CartesianPatchGeometry<NDIM> > pgeom = patch.getPatchGeometry();

    const double* const x_lower = pgeom->getXLower();
    const double* const dx = pgeom->getDx();

    // Loop over the boundary box and set the coefficients.
    const unsigned int location_index = bdry_box.getLocationIndex();
    const unsigned int bdry_normal_axis = location_index / 2;
    const Box<NDIM>& bc_coef_box =
        (acoef_data ? acoef_data->getBox() : bcoef_data ? bcoef_data->getBox() : gcoef_data ? gcoef_data->getBox() :
                                                                                              Box<NDIM>());
#if !defined(NDEBUG)
    TBOX_ASSERT(!acoef_data || bc_coef_box == acoef_data->getBox());
    TBOX_ASSERT(!bcoef_data || bc_coef_box == bcoef_data->getBox());
    TBOX_ASSERT(!gcoef_data || bc_coef_box == gcoef_data->getBox());
#endif

    const mu::Parser& acoef_parser = d_acoef_parsers[location_index];
    const mu::Parser& bcoef_parser = d_bcoef_parsers[location_index];
    const mu::Parser& gcoef_parser = d_gcoef_parsers[location_index];
    *d_parser_time = fill_time;
    for (Box<NDIM>::Iterator b(bc_coef_box); b; b++)
    {
        const Index<NDIM>& i = b();
        for (unsigned int d = 0; d < NDIM; ++d)
        {
            if (d != bdry_normal_axis)
            {
                (*d_parser_posn)[d] = x_lower[d] + dx[d] * (static_cast<double>(i(d) - patch_lower(d)) + 0.5);
            }
            else
            {
                (*d_parser_posn)[d] = x_lower[d] + dx[d] * (static_cast<double>(i(d) - patch_lower(d)));
            }
        }
        try
        {
            if (acoef_data) (*acoef_data)(i, 0) = acoef_parser.Eval();
            if (bcoef_data) (*bcoef_data)(i, 0) = bcoef_parser.Eval();
            if (gcoef_data) (*gcoef_data)(i, 0) = gcoef_parser.Eval();
        }
        catch (mu::ParserError& e)
        {
            TBOX_ERROR("muParserRobinBcCoefs::setDataOnPatch():\n"
                       << "  error: " << e.GetMsg() << "\n"
                       << "  in:    " << e.GetExpr() << "\n");
        }
        catch (...)
        {
            TBOX_ERROR("muParserRobinBcCoefs::setDataOnPatch():\n"
                       << "  unrecognized exception generated by muParser library.\n");
        }
    }
    return;
} // setBcCoefs
Beispiel #10
0
void
AdvDiffHypPatchOps::conservativeDifferenceOnPatch(
    Patch<NDIM>& patch,
    const double /*time*/,
    const double dt,
    bool /*at_synchronization*/)
{
    const Box<NDIM>& patch_box = patch.getBox();
    const Index<NDIM>& ilower = patch_box.lower();
    const Index<NDIM>& iupper = patch_box.upper();

    const Pointer<CartesianPatchGeometry<NDIM> > patch_geom = patch.getPatchGeometry();
    const double* const dx = patch_geom->getDx();

    for (std::set<Pointer<CellVariable<NDIM,double> > >::const_iterator cit = d_Q_var.begin();
         cit != d_Q_var.end(); ++cit)
    {
        Pointer<CellVariable<NDIM,double> > Q_var = *cit;
        Pointer<FaceVariable<NDIM,double> > u_var = d_Q_u_map[Q_var];

        if (u_var.isNull())
        {
            Pointer<CellData<NDIM,double> > Q_data = patch.getPatchData(Q_var, getDataContext());
            Q_data->fillAll(0.0);
            continue;
        }

        const bool conservation_form = d_Q_difference_form[Q_var] == CONSERVATIVE;
        const bool u_is_div_free = d_u_is_div_free[u_var];

        Pointer<FaceVariable<NDIM,double> > flux_integral_var = d_flux_integral_var[Q_var];
        Pointer<FaceVariable<NDIM,double> > q_integral_var = d_q_integral_var[Q_var];
        Pointer<FaceVariable<NDIM,double> > u_integral_var = d_u_integral_var[u_var];

        Pointer<CellData<NDIM,double> > Q_data = patch.getPatchData(Q_var, getDataContext());
        Pointer<FaceData<NDIM,double> > flux_integral_data =
            (conservation_form
             ? patch.getPatchData(flux_integral_var, getDataContext())
             : Pointer<PatchData<NDIM> >(NULL));
        Pointer<FaceData<NDIM,double> > q_integral_data =
            (!conservation_form || !u_is_div_free
             ? patch.getPatchData(q_integral_var, getDataContext())
             : Pointer<PatchData<NDIM> >(NULL));
        Pointer<FaceData<NDIM,double> > u_integral_data =
            (!conservation_form || !u_is_div_free
             ? patch.getPatchData(u_integral_var, getDataContext())
             : Pointer<PatchData<NDIM> >(NULL));

        const IntVector<NDIM>& Q_data_ghost_cells = Q_data->getGhostCellWidth();
        const IntVector<NDIM>& flux_integral_data_ghost_cells =
            (!flux_integral_data.isNull()
             ? flux_integral_data->getGhostCellWidth()
             : 0);
        const IntVector<NDIM>& q_integral_data_ghost_cells =
            (!q_integral_data.isNull()
             ? q_integral_data->getGhostCellWidth()
             : 0);
        const IntVector<NDIM>& u_integral_data_ghost_cells =
            (!u_integral_data.isNull()
             ? u_integral_data->getGhostCellWidth()
             : 0);

        switch (d_Q_difference_form[Q_var])
        {
            case CONSERVATIVE:
            {
                for (int depth = 0; depth < Q_data->getDepth(); ++depth)
                {
                    if (u_is_div_free)
                    {
#if (NDIM == 2)
                        ADV_DIFF_CONSDIFF_FC(
                            dx,dt,
                            ilower(0),iupper(0),ilower(1),iupper(1),
                            flux_integral_data_ghost_cells(0),flux_integral_data_ghost_cells(1),
                            Q_data_ghost_cells(0),Q_data_ghost_cells(1),
                            flux_integral_data->getPointer(0,depth),
                            flux_integral_data->getPointer(1,depth),
                            Q_data->getPointer(depth));
#endif
#if (NDIM == 3)
                        ADV_DIFF_CONSDIFF_FC(
                            dx,dt,
                            ilower(0),iupper(0),ilower(1),iupper(1),ilower(2),iupper(2),
                            flux_integral_data_ghost_cells(0),flux_integral_data_ghost_cells(1),flux_integral_data_ghost_cells(2),
                            Q_data_ghost_cells(0),Q_data_ghost_cells(1),Q_data_ghost_cells(2),
                            flux_integral_data->getPointer(0,depth),
                            flux_integral_data->getPointer(1,depth),
                            flux_integral_data->getPointer(2,depth),
                            Q_data->getPointer(depth));
#endif
                    }
                    else
                    {
#if (NDIM == 2)
                        ADV_DIFF_CONSDIFFWITHDIVSOURCE_FC(
                            dx,dt,
                            ilower(0),iupper(0),ilower(1),iupper(1),
                            flux_integral_data_ghost_cells(0),flux_integral_data_ghost_cells(1),
                            q_integral_data_ghost_cells(0),q_integral_data_ghost_cells(1),
                            u_integral_data_ghost_cells(0),u_integral_data_ghost_cells(1),
                            Q_data_ghost_cells(0),Q_data_ghost_cells(1),
                            flux_integral_data->getPointer(0,depth),
                            flux_integral_data->getPointer(1,depth),
                            q_integral_data->getPointer(0,depth),
                            q_integral_data->getPointer(1,depth),
                            u_integral_data->getPointer(0),
                            u_integral_data->getPointer(1),
                            Q_data->getPointer(depth));
#endif
#if (NDIM == 3)
                        ADV_DIFF_CONSDIFFWITHDIVSOURCE_FC(
                            dx,dt,
                            ilower(0),iupper(0),ilower(1),iupper(1),ilower(2),iupper(2),
                            flux_integral_data_ghost_cells(0),flux_integral_data_ghost_cells(1),flux_integral_data_ghost_cells(2),
                            q_integral_data_ghost_cells(0),q_integral_data_ghost_cells(1),q_integral_data_ghost_cells(2),
                            u_integral_data_ghost_cells(0),u_integral_data_ghost_cells(1),u_integral_data_ghost_cells(2),
                            Q_data_ghost_cells(0),Q_data_ghost_cells(1),Q_data_ghost_cells(2),
                            flux_integral_data->getPointer(0,depth),
                            flux_integral_data->getPointer(1,depth),
                            flux_integral_data->getPointer(2,depth),
                            q_integral_data->getPointer(0,depth),
                            q_integral_data->getPointer(1,depth),
                            q_integral_data->getPointer(2,depth),
                            u_integral_data->getPointer(0),
                            u_integral_data->getPointer(1),
                            u_integral_data->getPointer(2),
                            Q_data->getPointer(depth));
#endif
                    }
                }
                break;
            }
            case ADVECTIVE:
            {
                CellData<NDIM,double> N_data(patch_box,Q_data->getDepth(),0);
                d_godunov_advector->computeAdvectiveDerivative(N_data, *u_integral_data, *q_integral_data, patch);
                PatchCellDataOpsReal<NDIM,double> patch_cc_data_ops;
                patch_cc_data_ops.scale(Q_data, -1.0/(dt*dt), Pointer<CellData<NDIM,double> >(&N_data,false), patch_box);
                break;
            }
            default:
            {
                TBOX_ERROR("AdvDiffHypPatchOps::conservativeDifferenceOnPatch():\n"
                           << "  unsupported differencing form: " << enum_to_string<ConvectiveDifferencingType>(d_Q_difference_form[Q_var]) << " \n"
                           << "  valid choices are: ADVECTIVE, CONSERVATIVE\n");
            }
        }
    }
    return;
}// conservativeDifferenceOnPatch
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