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