diff --git a/nufi/cells.h b/nufi/cells.h index 9451c41..8bcb9b7 100644 --- a/nufi/cells.h +++ b/nufi/cells.h @@ -2,116 +2,157 @@ #define CELLS_H #include -#include +#include +#include + +#include #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; - // for locator - Point lower; - Point upper; - double h; -}; +// Current Locator needs Grid to be a hypercube !! template struct CellLocation { - const CellInfo *info; + using CellIterator = typename DoFHandler::cell_iterator; + + CellIterator cell; 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; - const std::vector> &get_cell_centers() const; + CellLocation locate(const Point &point) const; private: - std::vector> cells; - std::vector> cell_centers; + const DoFHandler *dof_handler_ = nullptr; + + Point domain_lower_; + Point domain_upper_; }; template void CellLocator::rebuild(const DoFHandler &dof_handler, const Triangulation &triangulation) { + AssertThrow(&dof_handler.get_triangulation() == &triangulation, + ExcMessage("CellLocator::rebuild(): DoFHandler and Triangulation " + "do not refer to the same mesh.")); - cells.clear(); - cells.reserve(triangulation.n_active_cells()); + auto root = dof_handler.begin(0); - for (const auto &cell : dof_handler.active_cell_iterators()) { - CellInfo info; + AssertThrow( + root != dof_handler.end(0), + ExcMessage("CellLocator::rebuild(): triangulation has no level-zero " + "cell.")); - info.cell = cell; - info.lower = cell->vertex(0); - info.upper = cell->vertex(GeometryInfo::vertices_per_cell - 1); + auto after_root = root; + ++after_root; - info.h = info.upper[0] - info.lower[0]; + AssertThrow( + after_root == dof_handler.end(0), + ExcMessage("CellLocator currently requires exactly one coarse cell.")); - cells.push_back(info); + dof_handler_ = &dof_handler; + + for (unsigned int d = 0; d < dim; ++d) { + domain_lower_[d] = std::numeric_limits::max(); + domain_upper_[d] = std::numeric_limits::lowest(); } - std::sort(cells.begin(), cells.end(), - [](const CellInfo &a, const CellInfo &b) { - return a.lower[0] < b.lower[0]; - }); + for (unsigned int v = 0; v < GeometryInfo::vertices_per_cell; ++v) + for (unsigned int d = 0; d < dim; ++d) { + domain_lower_[d] = std::min(domain_lower_[d], root->vertex(v)[d]); - cell_centers.clear(); - cell_centers.reserve(cells.size()); + domain_upper_[d] = std::max(domain_upper_[d], root->vertex(v)[d]); + } - for (const auto &cell : cells) { - Point center; - for (unsigned int d = 0; d < dim; ++d) - center[d] = 0.5 * (cell.lower[d] + cell.upper[d]); + for (unsigned int d = 0; d < dim; ++d) { + const double length = domain_upper_[d] - domain_lower_[d]; - cell_centers.push_back(center); + AssertThrow(length > 0.0, + ExcMessage("CellLocator::rebuild(): coarse-cell domain has " + "non-positive extent.")); + + const double scale = + std::max({1.0, std::abs(domain_lower_[d]), std::abs(domain_upper_[d])}); + + const double tolerance = + 100.0 * std::numeric_limits::epsilon() * scale; + + for (unsigned int v = 0; v < GeometryInfo::vertices_per_cell; ++v) { + const double coordinate = root->vertex(v)[d]; + + const bool lies_on_lower = + std::abs(coordinate - domain_lower_[d]) <= tolerance; + + const bool lies_on_upper = + std::abs(coordinate - domain_upper_[d]) <= tolerance; + + AssertThrow( + lies_on_lower || lies_on_upper, + ExcMessage( + "CellLocator requires an axis-aligned hypercube coarse cell.")); + } } } template -CellLocation CellLocator::locate(const Point &p) const { - static_assert(dim == 1, - "Current CellLocator implementation only supports 1D."); +CellLocation CellLocator::locate(const Point &point) const { + AssertThrow( + dof_handler_ != nullptr, + ExcMessage("CellLocator::locate(): rebuild() has not been called.")); - AssertThrow(!cells.empty(), - ExcMessage("CellLocator::rebuild() has not been called.")); + Point reference_point; - const double x = p[0]; + for (unsigned int d = 0; d < dim; ++d) { + const double length = domain_upper_[d] - domain_lower_[d]; - 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 + const double shifted = point[d] - domain_lower_[d]; - if (it == cells.begin()) - it = cells.begin(); - else - --it; + double periodic_offset = shifted - length * std::floor(shifted / length); - // 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.")); + if (periodic_offset < 0.0) + periodic_offset += length; - CellLocation location; + if (periodic_offset >= length) + periodic_offset = 0.0; - location.info = &(*it); - location.reference_point[0] = (p[0] - it->lower[0]) / it->h; + reference_point[d] = periodic_offset / length; + } - return location; + auto cell = dof_handler_->begin(0); + + while (cell->has_children()) { + AssertThrow( + cell->n_children() == GeometryInfo::max_children_per_cell, + ExcMessage( + "CellLocator currently supports isotropic refinement only.")); + + const unsigned int child_index = + GeometryInfo::child_cell_from_point(reference_point); + + reference_point = GeometryInfo::cell_to_child_coordinates( + reference_point, child_index); + + cell = cell->child(child_index); + } + + AssertThrow( + cell->is_active(), + ExcMessage("CellLocator tree traversal did not finish on an active " + "cell.")); + + AssertThrow( + GeometryInfo::is_inside_unit_cell(reference_point, 1e-12), + ExcMessage( + "CellLocator produced a reference point outside the unit cell.")); + + return CellLocation{cell, reference_point}; } -template -const std::vector> &CellLocator::get_cell_centers() const { - return cell_centers; -} - -#endif // !CELLS_H +#endif // CELLS_H diff --git a/nufi/fields.h b/nufi/fields.h index 9ab0a82..2693c5d 100644 --- a/nufi/fields.h +++ b/nufi/fields.h @@ -89,20 +89,18 @@ inline double f0(const double x, const double v, inline std::vector eval(std::vector &X, const GridStructure<1> &grid, const Vector &solution) noexcept { + AssertThrow(grid.dof_handler->n_dofs() == solution.size(), ExcMessage("@ eval(...) grid's number of DoFs doesn't correspond " "to solution's size")); - size_t x_size = X.size(); - std::vector> Points(x_size); - for (size_t i = 0; i < x_size; ++i) { - X[i] = X[i] - Parameters::X_DOMAIN_LEFT; - X[i] = X[i] - Parameters::LX * std::floor(X[i] * Parameters::LX_INV); + const size_t x_size = X.size(); + std::vector> points(x_size); - Points[i][0] = X[i]; - } + for (size_t i = 0; i < x_size; ++i) + points[i][0] = X[i]; - return grid.eval_vector_grad(solution, Points); + return grid.eval_vector_grad(solution, points); } inline double integral_space_vector(const GridStructure<1> &grid, diff --git a/nufi/grids.h b/nufi/grids.h index 2d90bdf..65ce753 100644 --- a/nufi/grids.h +++ b/nufi/grids.h @@ -72,12 +72,12 @@ template struct GridStructure { const auto cell_location = locator->locate(points[p]); - cell_location.info->cell->get_dof_values(solution, - local_solution_buffer.begin(), - local_solution_buffer.end()); + cell_location.cell->get_dof_values(solution, + local_solution_buffer.begin(), + local_solution_buffer.end()); evaluator.reinit( - cell_location.info->cell, + cell_location.cell, ArrayView>(&cell_location.reference_point, 1)); evaluator.evaluate(local_solution_buffer, EvaluationFlags::gradients); diff --git a/nufi/parameters.h b/nufi/parameters.h index 4e81530..cd8eeea 100644 --- a/nufi/parameters.h +++ b/nufi/parameters.h @@ -28,7 +28,7 @@ constexpr double DV = std::abs(V_DOMAIN_RIGHT - V_DOMAIN_LEFT) / NV; // 1 -> landau-damping // 2 -> maxwellian // 3 -> bump-on-tail -constexpr size_t f0_TYPE = 3; +constexpr size_t f0_TYPE = 0; // deal.ii options constexpr unsigned int GLOBAL_REFINEMENT = 7;