#ifndef POISSON_NON_PERIODIC_H #define POISSON_NON_PERIODIC_H #include "nufi/parameters.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace dealii; template class Poisson_non_periodic { public: Poisson_non_periodic (); void run(); void initialize(); void solve_step(); 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(const Poisson_non_periodic &problem, // sampling to save as spline unsigned int Nx, double x_min, double x_max); void output_results(unsigned int n); private: void make_grid(); void setup_system(); void assemble_system(); void solve(); void output_results() const; Triangulation<1> triangulation; const FE_Q<1> fe; DoFHandler<1> dof_handler; SparsityPattern sparsity_pattern; SparseMatrix system_matrix; Vector solution; Vector system_rhs; std::unique_ptr> rhs_function; }; template Poisson_non_periodic::Poisson_non_periodic() : fe(/* polynomial degree = */ 1) , dof_handler(triangulation) {} template void Poisson_non_periodic::set_rhs_function(std::unique_ptr> rhs) { rhs_function = std::move(rhs); } template void Poisson_non_periodic::make_grid() { Point x0 = Parameters::X_DOMAIN_RIGHT; Point x1 = Parameters::X_DOMAIN_RIGHT; GridGenerator::hyper_rectangle(triangulation, x0, x1); triangulation.refine_global(Parameters::GLOBAL_REFINEMENT); std::cout << "Number of active cells: " << triangulation.n_active_cells() << std::endl; } template void Poisson_non_periodic::setup_system() { dof_handler.distribute_dofs(fe); std::cout << "Number of degrees of freedom: " << dof_handler.n_dofs() << std::endl; DynamicSparsityPattern dsp(dof_handler.n_dofs()); DoFTools::make_sparsity_pattern(dof_handler, dsp); 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 Poisson_non_periodic::assemble_system() { const QGauss<1> quadrature_formula(fe.degree + 1); FEValues<1> fe_values(fe, quadrature_formula, update_values | update_gradients | 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); for (const auto &cell : dof_handler.active_cell_iterators()) { fe_values.reinit(cell); cell_matrix = 0; cell_rhs = 0; for (const unsigned int q_index : fe_values.quadrature_point_indices()) { const double rho = rhs_function->value(fe_values.quadrature_point(q_index)); 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_index) * // grad phi_i(x_q) fe_values.shape_grad(j, q_index) * // grad phi_j(x_q) fe_values.JxW(q_index)); // dx for (const unsigned int i : fe_values.dof_indices()) cell_rhs(i) += (fe_values.shape_value(i, q_index) * // phi_i(x_q) rho * // f(x_q) fe_values.JxW(q_index)); // dx } cell->get_dof_indices(local_dof_indices); 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 Poisson_non_periodic::solve() { SolverControl solver_control(1000, 1e-6 * system_rhs.l2_norm()); SolverCG> solver(solver_control); solver.solve(system_matrix, solution, system_rhs, PreconditionIdentity()); std::cout << solver_control.last_step() << " CG iterations needed to obtain convergence." << std::endl; } template void Poisson_non_periodic::output_results(unsigned int n) { // --- extract DoF coordinates --- std::vector> support_points(dof_handler.n_dofs()); Vector x_coordinate(dof_handler.n_dofs()); for (unsigned int i = 0; i < support_points.size(); ++i) x_coordinate[i] = support_points[i][0]; // x-component in 1D //---- Output density ---- ChargeDensity rho(Parameters::EPS, Parameters::WAVE_NR, Parameters::NV); DataOut data_out_rho; data_out_rho.attach_dof_handler(dof_handler); Vector density(solution.size()); VectorTools::interpolate(dof_handler, rho, density); data_out_rho.add_data_vector(density, "density"); data_out_rho.add_data_vector(x_coordinate, "x_coordinate"); data_out_rho.build_patches(); std::ofstream out1("results/density_" + std::to_string(n) + ".vtk"); data_out_rho.write_vtk(out1); //---- Output electric field & potential ---- DataOut data_out_E; data_out_E.attach_dof_handler(dof_handler); ElectricFieldPostprocessor electric_field; Vector dummy(solution.size() * dim); data_out_E.add_data_vector(solution, "potential"); data_out_E.add_data_vector(solution, electric_field); data_out_E.add_data_vector(x_coordinate, "x_coordinate"); data_out_E.build_patches(); std::ofstream out2("results/electric_field_"+ std::to_string(n)+".vtk"); data_out_E.write_vtk(out2); } template void Poisson_non_periodic::initialize() { make_mesh(); // build grid setup_system(); // distribute DoFs and matrices } template void Poisson_non_periodic::solve_step() { assemble_system(); solve(); } #endif