mirror of
https://codeberg.org/vcbferreira/NuFI_deal.ii
synced 2026-08-12 14:33:18 +02:00
seems to be faster, to test
This commit is contained in:
@@ -1,17 +1,25 @@
|
|||||||
# Vlasov-Poisson model solver
|
# Vlasov-Poisson model solver
|
||||||
|
|
||||||
This simulation of the Vlasov-Poisson system dimensions uses
|
This simulation of the Vlasov-Poisson system dimensions uses
|
||||||
|
|
||||||
- [NuFI algorithm](https://doi.org/10.1002/pamm.202300162)
|
- [NuFI algorithm](https://doi.org/10.1002/pamm.202300162)
|
||||||
- [deal.ii](https://dealii.org/) FEM package
|
- [deal.ii](https://dealii.org/) FEM package
|
||||||
|
|
||||||
---
|
______________________________________________________________________
|
||||||
|
|
||||||
dimensions: 1x1v
|
dimensions: 1x1v
|
||||||
|
|
||||||
status: Working, to be re-re-viewed
|
notes:
|
||||||
|
|
||||||
|
- about 3 times slower than previous locator
|
||||||
|
|
||||||
|
status: Working, to be re-reviewed
|
||||||
|
|
||||||
Refinement working:
|
Refinement working:
|
||||||
|
|
||||||
- grid versions saved on a vector
|
- grid versions saved on a vector
|
||||||
- solutions point to a version of the grid
|
- solutions point to a version of the grid
|
||||||
|
|
||||||
todo:
|
todo:
|
||||||
|
|
||||||
- add ions
|
- add ions
|
||||||
|
|||||||
+87
-77
@@ -2,8 +2,10 @@
|
|||||||
#define CELLS_H
|
#define CELLS_H
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <deal.II/base/exceptions.h>
|
#include <deal.II/base/exceptions.h>
|
||||||
#include <deal.II/base/geometry_info.h>
|
#include <deal.II/base/geometry_info.h>
|
||||||
@@ -13,19 +15,18 @@
|
|||||||
|
|
||||||
using namespace dealii;
|
using namespace dealii;
|
||||||
|
|
||||||
// Current Locator needs Grid to be a hypercube !!
|
// Current Locator needs Grid to be a single hypercube coarse cell,
|
||||||
|
// uniformly refined to `base_level`, with isotropic local refinement on top.
|
||||||
template <int dim> struct CellLocation {
|
template <int dim> struct CellLocation {
|
||||||
using CellIterator = typename DoFHandler<dim>::cell_iterator;
|
typename DoFHandler<dim>::active_cell_iterator cell;
|
||||||
|
|
||||||
CellIterator cell;
|
|
||||||
Point<dim> reference_point;
|
Point<dim> reference_point;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int dim> class CellLocator {
|
template <int dim> class CellLocator {
|
||||||
public:
|
public:
|
||||||
void rebuild(const DoFHandler<dim> &dof_handler,
|
void rebuild(const DoFHandler<dim> &dof_handler,
|
||||||
const Triangulation<dim> &triangulation);
|
const Triangulation<dim> &triangulation,
|
||||||
|
unsigned int base_level);
|
||||||
|
|
||||||
CellLocation<dim> locate(const Point<dim> &point) const;
|
CellLocation<dim> locate(const Point<dim> &point) const;
|
||||||
|
|
||||||
@@ -34,125 +35,134 @@ private:
|
|||||||
|
|
||||||
Point<dim> domain_lower_;
|
Point<dim> domain_lower_;
|
||||||
Point<dim> domain_upper_;
|
Point<dim> domain_upper_;
|
||||||
|
std::array<unsigned int, dim> base_n_{};
|
||||||
|
std::array<double, dim> base_dx_{};
|
||||||
|
|
||||||
|
// Flat, O(1)-indexable array of the base_level cells.
|
||||||
|
std::vector<typename DoFHandler<dim>::cell_iterator> base_cells_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int dim>
|
template <int dim>
|
||||||
void CellLocator<dim>::rebuild(const DoFHandler<dim> &dof_handler,
|
void CellLocator<dim>::rebuild(const DoFHandler<dim> &dof_handler,
|
||||||
const Triangulation<dim> &triangulation) {
|
const Triangulation<dim> &triangulation,
|
||||||
|
unsigned int base_level) {
|
||||||
AssertThrow(&dof_handler.get_triangulation() == &triangulation,
|
AssertThrow(&dof_handler.get_triangulation() == &triangulation,
|
||||||
ExcMessage("CellLocator::rebuild(): DoFHandler and Triangulation "
|
ExcMessage("CellLocator::rebuild(): DoFHandler and Triangulation "
|
||||||
"do not refer to the same mesh."));
|
"do not refer to the same mesh."));
|
||||||
|
|
||||||
|
dof_handler_ = &dof_handler;
|
||||||
|
|
||||||
|
// --- bounding box of the (single) coarse cell ---
|
||||||
auto root = dof_handler.begin(0);
|
auto root = dof_handler.begin(0);
|
||||||
|
AssertThrow(root != dof_handler.end(0),
|
||||||
AssertThrow(
|
ExcMessage("CellLocator::rebuild(): no level-zero cell."));
|
||||||
root != dof_handler.end(0),
|
{
|
||||||
ExcMessage("CellLocator::rebuild(): triangulation has no level-zero "
|
|
||||||
"cell."));
|
|
||||||
|
|
||||||
auto after_root = root;
|
auto after_root = root;
|
||||||
++after_root;
|
++after_root;
|
||||||
|
AssertThrow(after_root == dof_handler.end(0),
|
||||||
AssertThrow(
|
ExcMessage("CellLocator currently requires exactly one "
|
||||||
after_root == dof_handler.end(0),
|
"coarse cell."));
|
||||||
ExcMessage("CellLocator currently requires exactly one coarse cell."));
|
}
|
||||||
|
|
||||||
dof_handler_ = &dof_handler;
|
|
||||||
|
|
||||||
for (unsigned int d = 0; d < dim; ++d) {
|
for (unsigned int d = 0; d < dim; ++d) {
|
||||||
domain_lower_[d] = std::numeric_limits<double>::max();
|
domain_lower_[d] = std::numeric_limits<double>::max();
|
||||||
domain_upper_[d] = std::numeric_limits<double>::lowest();
|
domain_upper_[d] = std::numeric_limits<double>::lowest();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
|
for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell; ++v)
|
||||||
for (unsigned int d = 0; d < dim; ++d) {
|
for (unsigned int d = 0; d < dim; ++d) {
|
||||||
domain_lower_[d] = std::min(domain_lower_[d], root->vertex(v)[d]);
|
domain_lower_[d] = std::min(domain_lower_[d], root->vertex(v)[d]);
|
||||||
|
|
||||||
domain_upper_[d] = std::max(domain_upper_[d], root->vertex(v)[d]);
|
domain_upper_[d] = std::max(domain_upper_[d], root->vertex(v)[d]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- build the O(1)-indexable array of base_level cells ---
|
||||||
|
unsigned int total = 1;
|
||||||
for (unsigned int d = 0; d < dim; ++d) {
|
for (unsigned int d = 0; d < dim; ++d) {
|
||||||
const double length = domain_upper_[d] - domain_lower_[d];
|
const double length = domain_upper_[d] - domain_lower_[d];
|
||||||
|
|
||||||
AssertThrow(length > 0.0,
|
AssertThrow(length > 0.0,
|
||||||
ExcMessage("CellLocator::rebuild(): coarse-cell domain has "
|
ExcMessage("CellLocator::rebuild(): non-positive domain "
|
||||||
"non-positive extent."));
|
"extent."));
|
||||||
|
base_n_[d] =
|
||||||
const double scale =
|
1u << base_level; // refine_global(base_level) -> 2^level per axis
|
||||||
std::max({1.0, std::abs(domain_lower_[d]), std::abs(domain_upper_[d])});
|
base_dx_[d] = length / base_n_[d];
|
||||||
|
total *= base_n_[d];
|
||||||
const double tolerance =
|
|
||||||
100.0 * std::numeric_limits<double>::epsilon() * scale;
|
|
||||||
|
|
||||||
for (unsigned int v = 0; v < GeometryInfo<dim>::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."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base_cells_.assign(total, typename DoFHandler<dim>::cell_iterator());
|
||||||
|
|
||||||
|
for (auto cell = dof_handler.begin(base_level);
|
||||||
|
cell != dof_handler.end(base_level); ++cell) {
|
||||||
|
const auto bb = cell->bounding_box();
|
||||||
|
const auto c_lower = bb.get_boundary_points().first;
|
||||||
|
|
||||||
|
unsigned int idx = 0, stride = 1;
|
||||||
|
for (unsigned int d = 0; d < dim; ++d) {
|
||||||
|
unsigned int i = static_cast<unsigned int>(
|
||||||
|
std::round((c_lower[d] - domain_lower_[d]) / base_dx_[d]));
|
||||||
|
i = std::min(i, base_n_[d] - 1);
|
||||||
|
idx += i * stride;
|
||||||
|
stride *= base_n_[d];
|
||||||
}
|
}
|
||||||
|
base_cells_[idx] = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &c : base_cells_)
|
||||||
|
AssertThrow(c.state() == IteratorState::valid,
|
||||||
|
ExcMessage("CellLocator::rebuild(): failed to fill the base "
|
||||||
|
"grid — mesh isn't uniformly refined to "
|
||||||
|
"'base_level' as expected."));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int dim>
|
template <int dim>
|
||||||
CellLocation<dim> CellLocator<dim>::locate(const Point<dim> &point) const {
|
CellLocation<dim> CellLocator<dim>::locate(const Point<dim> &point) const {
|
||||||
AssertThrow(
|
AssertThrow(dof_handler_ != nullptr,
|
||||||
dof_handler_ != nullptr,
|
ExcMessage("CellLocator::locate(): rebuild() has not been "
|
||||||
ExcMessage("CellLocator::locate(): rebuild() has not been called."));
|
"called."));
|
||||||
|
|
||||||
Point<dim> reference_point;
|
std::array<unsigned int, dim> base_index;
|
||||||
|
Point<dim> reference_point; // local coords, updated at each descent step
|
||||||
|
|
||||||
|
// 1) periodic wrap + O(1) base-cell index per axis
|
||||||
for (unsigned int d = 0; d < dim; ++d) {
|
for (unsigned int d = 0; d < dim; ++d) {
|
||||||
const double length = domain_upper_[d] - domain_lower_[d];
|
const double length = domain_upper_[d] - domain_lower_[d];
|
||||||
|
double shifted = point[d] - domain_lower_[d];
|
||||||
|
shifted -= length * std::floor(shifted / length);
|
||||||
|
if (shifted >= length)
|
||||||
|
shifted = 0.0;
|
||||||
|
|
||||||
const double shifted = point[d] - domain_lower_[d];
|
const double xi = shifted / base_dx_[d];
|
||||||
|
const unsigned int i =
|
||||||
double periodic_offset = shifted - length * std::floor(shifted / length);
|
std::min(base_n_[d] - 1, static_cast<unsigned int>(std::floor(xi)));
|
||||||
|
base_index[d] = i;
|
||||||
if (periodic_offset < 0.0)
|
reference_point[d] = xi - i; // fraction within the base cell
|
||||||
periodic_offset += length;
|
|
||||||
|
|
||||||
if (periodic_offset >= length)
|
|
||||||
periodic_offset = 0.0;
|
|
||||||
|
|
||||||
reference_point[d] = periodic_offset / length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cell = dof_handler_->begin(0);
|
// 2) O(1) lookup of the base-level cell
|
||||||
|
unsigned int idx = 0, stride = 1;
|
||||||
|
for (unsigned int d = 0; d < dim; ++d) {
|
||||||
|
idx += base_index[d] * stride;
|
||||||
|
stride *= base_n_[d];
|
||||||
|
}
|
||||||
|
auto cell = base_cells_[idx];
|
||||||
|
|
||||||
|
// 3) O(R_level_max) descent — only costs anything for cells that are
|
||||||
|
// actually locally refined beyond base_level
|
||||||
while (cell->has_children()) {
|
while (cell->has_children()) {
|
||||||
AssertThrow(
|
AssertThrow(cell->n_children() == GeometryInfo<dim>::max_children_per_cell,
|
||||||
cell->n_children() == GeometryInfo<dim>::max_children_per_cell,
|
ExcMessage("CellLocator currently supports isotropic "
|
||||||
ExcMessage(
|
"refinement only."));
|
||||||
"CellLocator currently supports isotropic refinement only."));
|
|
||||||
|
|
||||||
const unsigned int child_index =
|
const unsigned int child_index =
|
||||||
GeometryInfo<dim>::child_cell_from_point(reference_point);
|
GeometryInfo<dim>::child_cell_from_point(reference_point);
|
||||||
|
|
||||||
reference_point = GeometryInfo<dim>::cell_to_child_coordinates(
|
reference_point = GeometryInfo<dim>::cell_to_child_coordinates(
|
||||||
reference_point, child_index);
|
reference_point, child_index);
|
||||||
|
|
||||||
cell = cell->child(child_index);
|
cell = cell->child(child_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertThrow(
|
AssertThrow(cell->is_active(),
|
||||||
cell->is_active(),
|
ExcMessage("CellLocator tree traversal did not finish on an "
|
||||||
ExcMessage("CellLocator tree traversal did not finish on an active "
|
"active cell."));
|
||||||
"cell."));
|
|
||||||
|
|
||||||
AssertThrow(
|
return CellLocation<dim>{typename DoFHandler<dim>::active_cell_iterator(cell),
|
||||||
GeometryInfo<dim>::is_inside_unit_cell(reference_point, 1e-12),
|
reference_point};
|
||||||
ExcMessage(
|
|
||||||
"CellLocator produced a reference point outside the unit cell."));
|
|
||||||
|
|
||||||
return CellLocation<dim>{cell, reference_point};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CELLS_H
|
#endif // CELLS_H
|
||||||
|
|||||||
+2
-1
@@ -140,7 +140,8 @@ GridStructure<dim> make_grid_snapshot(PoissonProblem<dim> &poisson) {
|
|||||||
grid.constraints->close();
|
grid.constraints->close();
|
||||||
|
|
||||||
grid.locator = std::make_unique<CellLocator<dim>>();
|
grid.locator = std::make_unique<CellLocator<dim>>();
|
||||||
grid.locator->rebuild(*grid.dof_handler, *grid.triangulation);
|
grid.locator->rebuild(*grid.dof_handler, *grid.triangulation,
|
||||||
|
Parameters::GLOBAL_REFINEMENT);
|
||||||
|
|
||||||
// START: diagnostics
|
// START: diagnostics
|
||||||
AssertThrow(
|
AssertThrow(
|
||||||
|
|||||||
@@ -338,7 +338,8 @@ template <int dim> void PoissonProblem<dim>::setup_system() {
|
|||||||
system_rhs.reinit(dof_handler.n_dofs());
|
system_rhs.reinit(dof_handler.n_dofs());
|
||||||
|
|
||||||
// used for evaluator to avoid running it anytime there is an eval
|
// used for evaluator to avoid running it anytime there is an eval
|
||||||
cell_locator.rebuild(dof_handler, triangulation);
|
cell_locator.rebuild(dof_handler, triangulation,
|
||||||
|
Parameters::GLOBAL_REFINEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int dim> void PoissonProblem<dim>::assemble_system() {
|
template <int dim> void PoissonProblem<dim>::assemble_system() {
|
||||||
|
|||||||
Reference in New Issue
Block a user