#ifndef POISSON_PROBLEM_H #define POISSON_PROBLEM_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nufi/parameters.h" using namespace dealii; // =-=-=-=-= Poisson Solver =-=-=-=-= template class PoissonProblem { public: PoissonProblem(unsigned int degree); void initialize(); void solve_step(); void run(); void set_rhs_function(std::unique_ptr> rhs_function); const Vector &get_solution() const { return solution; } const DoFHandler &get_dof_handler() const { return dof_handler; } std::vector sample_electric_field(double x_min, double x_max, unsigned int Nx); std::vector sample_electric_potential(double x_min, double x_max, unsigned int Nx); private: void create_mesh(); void setup_system(); void assemble_system(); void solve(); Triangulation triangulation; FE_Q fe; DoFHandler dof_handler; AffineConstraints constraints; SparsityPattern sparsity_pattern; SparseMatrix system_matrix; Vector solution; // phi Vector system_rhs; std::unique_ptr> rhs_function; MappingQ mapping; }; // Utilities template void PoissonProblem::set_rhs_function(std::unique_ptr> rhs) { rhs_function = std::move(rhs); } template PoissonProblem::PoissonProblem(unsigned int degree) : fe(degree) , dof_handler(triangulation) , mapping(degree) {} template std::vector PoissonProblem::sample_electric_field(double x_min,double x_max,unsigned int Nx) { std::vector E_values(Nx); const double dx = (x_max - x_min) / (Nx - 1); for (unsigned int i = 0; i < Nx; ++i) { const double x = x_min + i * dx; const Point point(x); // 1. Find the active cell containing x const auto cell_point_pair = GridTools::find_active_cell_around_point(mapping, dof_handler, point); const auto cell = cell_point_pair.first; const Point &unit_point = cell_point_pair.second; // 2. FEPointEvaluation expects an ArrayView of points std::vector> points(1, unit_point); ArrayView> point_view(points); FEPointEvaluation<1, dim> evaluator(mapping, dof_handler.get_fe(), update_gradients); // reinit with ArrayView of points evaluator.reinit(cell, point_view); Vector local_dofs(dof_handler.get_fe().dofs_per_cell); cell->get_dof_values(solution, local_dofs); // 3. Evaluate gradient at this point evaluator.evaluate(local_dofs, EvaluationFlags::gradients); const Tensor<1, dim> grad_phi = evaluator.get_gradient(0); // 4. Compute E = -grad(phi) E_values[i] = -grad_phi[0]; } return E_values; } template std::vector PoissonProblem::sample_electric_potential( double x_min, double x_max, unsigned int Nx) { std::vector values(Nx); std::vector> eval_points(Nx); double Lx = x_max - x_min; double dx = Lx / Nx; for(unsigned int i=0 ; i(x_min + i * dx); Utilities::MPI::RemotePointEvaluation cache; cache.reinit(eval_points, triangulation, mapping); values = VectorTools::point_values(cache, dof_handler, solution); return values; } // dealii Poisson template void PoissonProblem::create_mesh() { GridGenerator::hyper_cube(triangulation, Parameters::X_DOMAIN_LEFT, Parameters::X_DOMAIN_RIGHT); std::vector::cell_iterator>> periodic_faces; GridTools::collect_periodic_faces(triangulation, 0, 1, // boundary IDs 0, periodic_faces); triangulation.add_periodicity(periodic_faces); triangulation.refine_global(Parameters::GLOBAL_REFINEMENT); } template void PoissonProblem::setup_system() { dof_handler.distribute_dofs(fe); constraints.clear(); DoFTools::make_hanging_node_constraints(dof_handler, constraints); DoFTools::make_periodicity_constraints(dof_handler, 0, 1, 0, constraints); constraints.close(); DynamicSparsityPattern dsp(dof_handler.n_dofs()); DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints); sparsity_pattern.copy_from(dsp); system_matrix.reinit(sparsity_pattern); solution.reinit(dof_handler.n_dofs()); system_rhs.reinit(dof_handler.n_dofs()); } template void PoissonProblem::assemble_system() { QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, quadrature_formula, update_values | update_gradients | update_quadrature_points | update_JxW_values); const unsigned int dofs_per_cell = fe.n_dofs_per_cell(); FullMatrix cell_matrix(dofs_per_cell, dofs_per_cell); Vector cell_rhs(dofs_per_cell); std::vector local_dof_indices(dofs_per_cell); Assert(rhs_function != nullptr, ExcMessage("RHS function not set")); for (const auto &cell : dof_handler.active_cell_iterators()) { fe_values.reinit(cell); cell_matrix = 0; cell_rhs = 0; for (const auto q : fe_values.quadrature_point_indices()) { const double rho = rhs_function->value(fe_values.quadrature_point(q)); for (const unsigned int i : fe_values.dof_indices()) for (const unsigned int j : fe_values.dof_indices()) cell_matrix(i, j) += (fe_values.shape_grad(i, q) * // grad phi_i(x_q) fe_values.shape_grad(j, q) * // grad phi_j(x_q) fe_values.JxW(q)); // dx for (const unsigned int i : fe_values.dof_indices()) cell_rhs(i) += (fe_values.shape_value(i, q) * // phi_i(x_q) rho * // f(x_q) fe_values.JxW(q)); // dx } cell->get_dof_indices(local_dof_indices); constraints.distribute_local_to_global(cell_matrix, cell_rhs, local_dof_indices, system_matrix, system_rhs); for (const unsigned int i : fe_values.dof_indices()) for (const unsigned int j : fe_values.dof_indices()) system_matrix.add(local_dof_indices[i], local_dof_indices[j], cell_matrix(i, j)); for (const unsigned int i : fe_values.dof_indices()) system_rhs(local_dof_indices[i]) += cell_rhs(i); } std::map boundary_values; // VectorTools::interpolate_boundary_values(dof_handler, // types::boundary_id(0), // Functions::ZeroFunction<1>(), // boundary_values); MatrixTools::apply_boundary_values(boundary_values, system_matrix, solution, system_rhs); } template void PoissonProblem::solve() { SolverControl solver_control(Parameters::CONVERGENCE_ITERATIONS, Parameters::CONVERGENCE_LIMIT); SolverCG> solver(solver_control); // PreconditionSSOR> preconditioner; // preconditioner.initialize(system_matrix, 1.2); // solver.solve(system_matrix, solution, system_rhs, preconditioner); solver.solve(system_matrix, solution, system_rhs, PreconditionIdentity()); // constraints.distribute(solution); } template void PoissonProblem::initialize() { create_mesh(); // build grid setup_system(); // distribute DoFs and matrices } template void PoissonProblem::solve_step() { assemble_system(); solve(); } // NuFI doesnt use this, kept only for testing PoissonProblem template void PoissonProblem::run() { create_mesh(); setup_system(); assemble_system(); solve(); } #endif