#ifndef NUFI_SOLVER_HPP #define NUFI_SOLVER_HPP #include #include #include #include #include #include #include #include #include #include #include "parameters.hpp" #include "save_results.hpp" #include "poisson_problem.hpp" #include "fields.hpp" using namespace dealii; class NuFISolver { public: NuFISolver(); void run(); double eval_rho(unsigned int n, double x, const double *E_coeffs, unsigned int Nv = Parameters::NV); double eval_ftilda(unsigned int n, double x, double u, const double *E_coeffs); // void save_ftilda(unsigned int n, const double *E_coeffs, unsigned int Nx_out, unsigned int Nv_out, const std::string &filename); // void save_rho(unsigned int n, const double *E_coeffs, unsigned int Nx_out, const std::string &filename); // void save_Efield(unsigned int n, const double *E_coeffs, unsigned int Nx_out, const std::string &filename); private: unsigned int Nt = std::floor(Parameters::TMAX/Parameters::DT); unsigned int Nx = Parameters::SPLINE_NX; double Lx = Parameters::LX; std::vector rho; unsigned int order; PoissonProblem<1> poisson; }; inline double NuFISolver::eval_ftilda(unsigned int n, double x, double u, const double *E_coeffs) { if ( n == 0 ) return f0(x,u); const size_t stride_x = 1; const size_t stride_t = stride_x*(Parameters::SPLINE_NX + Parameters::SPLINE_ORDER - 1); double Ex; const double *c; // We omit the initial half-step. while ( --n ) { x = x - Parameters::DT *u; c = E_coeffs + n*stride_t; Ex = -eval<1>(x, c); u = u + Parameters::DT *Ex; } // The final half-step. x -= Parameters::DT*u; c = E_coeffs + n*stride_t; Ex = -eval<1>(x, c); u += 0.5*Parameters::DT*Ex; return f0(x,u); } inline double NuFISolver::eval_rho(const unsigned int n, const double x, const double *E_coeffs, const unsigned int Nv) { const double dv = (Parameters::V_DOMAIN_RIGHT - Parameters::V_DOMAIN_LEFT) / Nv; const double v_min = Parameters::V_DOMAIN_LEFT; double integral = 0.0; for (unsigned int i = 0; i < Nv; ++i) integral += eval_ftilda(n, x, v_min + i * dv, E_coeffs) * dv; return 1.0 - integral; } template class ChargeDensity_NuFI : public Function { public: ChargeDensity_NuFI(const double *rho_values, unsigned int Nx) : Function(), rho(rho_values), Nx(Nx) {} virtual double value(const Point &p, [[maybe_unused]] const unsigned int component = 0) const override { const double x = p[0]; // Map x -> grid index const double L = Parameters::LX; const double dx = L / (Nx-1); int i = static_cast(std::floor((x - Parameters::X_DOMAIN_LEFT) / dx)); // periodic wrap i = (i % Nx + Nx) % Nx; return rho[i]; } private: const double *rho; const unsigned int Nx; }; inline void NuFISolver::run() { std::cout << "Building E_sline\n\n"; using std::abs; using std::max; const size_t stride_t = Nx + order - 1; std::unique_ptr coeffs { new double[ Nt*stride_t ] {} }; std::unique_ptr rho { reinterpret_cast(std::aligned_alloc(64,sizeof(double)*Nx)), std::free }; if ( rho == nullptr ) throw std::bad_alloc {}; for (unsigned int it = 0; it < Nt; ++it) { std::cout << "Timestep " << it << " / " << Nt << std::endl << std::endl; // compute rho double dx = Parameters::SPLINE_DX; double x = Parameters::X_DOMAIN_LEFT; for(size_t i = 0; i>(rho.get(), Parameters::SPLINE_NX)); poisson.solve_step(); if (it % Parameters::PLOT_FREQUENCY == 0) { std::cout << "Saving results... \n\n"; save_ftilda(*this, it, coeffs.get(), 128, 128, "results/ftilda_" + std::to_string(it) + ".dat"); save_rho(*this, it, coeffs.get(), 128, "results/rho_" + std::to_string(it) + ".dat"); save_Efield(it, coeffs.get(), 128, "results/field_" + std::to_string(it) + ".dat"); } } std::cout << "NuFI simulation finished.\n"; } inline NuFISolver::NuFISolver() : order(Parameters::FE_DEGREE), poisson(order) { std::cout << "Initializing dealii Poisson Solver\n"; poisson.initialize(); } #endif