#ifndef CELLS_H #define CELLS_H #include #include #include #include #include #include using namespace dealii; template struct CellInfo { // what needs to be given to evaluator typename DoFHandler::active_cell_iterator cell; // usefull for locator Point lower; Point upper; double h; }; template struct CellLocation { const CellInfo *info; Point reference_point; }; template class CellLocator { public: using CellIterator = typename DoFHandler::active_cell_iterator; void rebuild(const DoFHandler &dof_handler, const Triangulation &triangulation); CellLocation locate(const Point &p) const; private: std::vector> cells; }; template void CellLocator::rebuild(const DoFHandler &dof_handler, const Triangulation &triangulation) { cells.clear(); cells.reserve(triangulation.n_active_cells()); for (const auto &cell : dof_handler.active_cell_iterators()) { CellInfo info; info.cell = cell; info.lower = cell->vertex(0); info.upper = cell->vertex(GeometryInfo::vertices_per_cell - 1); info.h = info.upper[0] - info.lower[0]; cells.push_back(info); } std::sort(cells.begin(), cells.end(), [](const CellInfo &a, const CellInfo &b) { return a.lower[0] < b.lower[0]; }); } template CellLocation CellLocator::locate(const Point &p) const { static_assert(dim == 1, "Current CellLocator implementation only supports 1D."); AssertThrow(!cells.empty(), ExcMessage("CellLocator::rebuild() has not been called.")); const double x = p[0]; auto it = std::upper_bound(cells.begin(), cells.end(), x, [](double value, const CellInfo &cell) { return value < cell.lower[0]; }); // returns cell to the right of cell with x if (it == cells.begin()) it = cells.begin(); else --it; // Safety check: make sure the point is really inside this cell AssertThrow(x >= it->lower[0] - 1e-12 && x <= it->upper[0] + 1e-12, ExcMessage("CellLocator failed to find containing cell.")); CellLocation location; location.info = &(*it); location.reference_point[0] = (p[0] - it->lower[0]) / it->h; return location; } #endif // !CELLS_H