Skip to content

Commit

Permalink
Gpu Poisson Solver
Browse files Browse the repository at this point in the history
Poisson solver operator ported on gpu, it includes FFT and FEM solvers. Sheath simulation give expected results on both periodic and non periodic cases.
  • Loading branch information
EmilyBourne committed Jan 16, 2024
1 parent a108571 commit fd97369
Show file tree
Hide file tree
Showing 15 changed files with 146 additions and 73 deletions.
5 changes: 4 additions & 1 deletion src/geometryXVx/poisson/chargedensitycalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ChargeDensityCalculator::ChargeDensityCalculator(Quadrature<IDimVx> const& quad)
DSpanX ChargeDensityCalculator::operator()(DSpanX const rho, DViewSpXVx const allfdistribu) const
{
Kokkos::Profiling::pushRegion("ChargeDensityCalculator");
DFieldVx f_vx_slice(allfdistribu.domain<IDimVx>());
IndexSp const last_kin_species = allfdistribu.domain<IDimSp>().back();
IndexSp const last_species = ddc::discrete_space<IDimSp>().charges().domain().back();
double chargedens_adiabspecies = 0.;
Expand All @@ -23,7 +24,9 @@ DSpanX ChargeDensityCalculator::operator()(DSpanX const rho, DViewSpXVx const al
ddc::for_each(rho.domain(), [&](IndexX const ix) {
rho(ix) = chargedens_adiabspecies;
ddc::for_each(ddc::get_domain<IDimSp>(allfdistribu), [&](IndexSp const isp) {
rho(ix) += charge(isp) * m_quad(allfdistribu[isp][ix]);
ddc::deepcopy(f_vx_slice, allfdistribu[isp][ix]);

rho(ix) += charge(isp) * m_quad(f_vx_slice.span_view());
});
});
Kokkos::Profiling::popRegion();
Expand Down
11 changes: 8 additions & 3 deletions src/geometryXVx/poisson/femnonperiodicpoissonsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,14 @@ void FemNonPeriodicPoissonSolver::solve_matrix_system(
// with Lagrangian multipliers
//----------------------------------------------------------------------------
void FemNonPeriodicPoissonSolver::operator()(
DSpanX const electrostatic_potential,
DSpanX const electric_field,
DViewSpXVx const allfdistribu) const
device_t<DSpanX> electrostatic_potential_device,
device_t<DSpanX> electric_field_device,
device_t<DViewSpXVx> allfdistribu_device) const
{
Kokkos::Profiling::pushRegion("PoissonSolver");
auto electrostatic_potential = ddc::create_mirror_and_copy(electrostatic_potential_device);
auto electric_field = ddc::create_mirror_and_copy(electric_field_device);
auto allfdistribu = ddc::create_mirror_and_copy(allfdistribu_device);
assert(electrostatic_potential.domain() == ddc::get_domain<IDimX>(allfdistribu));
IDomainX const dom_x = electrostatic_potential.domain();

Expand All @@ -202,5 +205,7 @@ void FemNonPeriodicPoissonSolver::operator()(
electrostatic_potential(ix) = m_spline_x_nu_evaluator(ddc::coordinate(ix), phi_spline_coef);
electric_field(ix) = -m_spline_x_nu_evaluator.deriv(ddc::coordinate(ix), phi_spline_coef);
});
ddc::deepcopy(electrostatic_potential_device, electrostatic_potential);
ddc::deepcopy(electric_field_device, electric_field);
Kokkos::Profiling::popRegion();
}
12 changes: 7 additions & 5 deletions src/geometryXVx/poisson/femnonperiodicpoissonsolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,14 @@ class FemNonPeriodicPoissonSolver : public IPoissonSolver
/**
* The operator which solves the equation using the method described by the class.
*
* @param[out] electrostatic_potential The electrostatic potential, the result of the poisson solver.
* @param[out] electric_field The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu The distribution function.
* @param[out] electrostatic_potential_device The electrostatic potential, the result of the poisson solver.
* @param[out] electric_field_device The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu_device The distribution function.
*/
void operator()(DSpanX electrostatic_potential, DSpanX electric_field, DViewSpXVx allfdistribu)
const override;
void operator()(
device_t<DSpanX> electrostatic_potential_device,
device_t<DSpanX> electric_field_device,
device_t<DViewSpXVx> allfdistribu_device) const override;

private:
void build_matrix();
Expand Down
13 changes: 9 additions & 4 deletions src/geometryXVx/poisson/femperiodicpoissonsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,19 @@ void FemPeriodicPoissonSolver::solve_matrix_system(
// with Lagrangian multipliers
//----------------------------------------------------------------------------
void FemPeriodicPoissonSolver::operator()(
DSpanX const electrostatic_potential,
DSpanX const electric_field,
DViewSpXVx const allfdistribu) const
device_t<DSpanX> electrostatic_potential_device,
device_t<DSpanX> electric_field_device,
device_t<DViewSpXVx> allfdistribu_device) const
{
Kokkos::Profiling::pushRegion("PoissonSolver");
auto electrostatic_potential = ddc::create_mirror_and_copy(electrostatic_potential_device);
auto electric_field = ddc::create_mirror_and_copy(electric_field_device);
auto allfdistribu = ddc::create_mirror_and_copy(allfdistribu_device);
assert(electrostatic_potential.domain() == ddc::get_domain<IDimX>(allfdistribu));
IDomainX const dom_x = electrostatic_potential.domain();

// Compute the RHS of the Poisson equation
ddc::Chunk<double, IDomainX> rho(dom_x);
DFieldX rho(dom_x);
m_compute_rho(rho, allfdistribu);

//
Expand All @@ -188,5 +191,7 @@ void FemPeriodicPoissonSolver::operator()(
electrostatic_potential(ix) = m_spline_x_evaluator(ddc::coordinate(ix), phi_spline_coef);
electric_field(ix) = -m_spline_x_evaluator.deriv(ddc::coordinate(ix), phi_spline_coef);
});
ddc::deepcopy(electrostatic_potential_device, electrostatic_potential);
ddc::deepcopy(electric_field_device, electric_field);
Kokkos::Profiling::popRegion();
}
12 changes: 7 additions & 5 deletions src/geometryXVx/poisson/femperiodicpoissonsolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,14 @@ class FemPeriodicPoissonSolver : public IPoissonSolver
/**
* The operator which solves the equation using the method described by the class.
*
* @param[out] electrostatic_potential The electrostatic potential, the result of the poisson solver.
* @param[out] electric_field The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu The distribution function.
* @param[out] electrostatic_potential_device The electrostatic potential, the result of the poisson solver.
* @param[out] electric_field_device The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu_device The distribution function.
*/
void operator()(DSpanX electrostatic_potential, DSpanX electric_field, DViewSpXVx allfdistribu)
const override;
void operator()(
device_t<DSpanX> electrostatic_potential_device,
device_t<DSpanX> electric_field_device,
device_t<DViewSpXVx> allfdistribu_device) const override;

private:
void build_matrix();
Expand Down
57 changes: 36 additions & 21 deletions src/geometryXVx/poisson/fftpoissonsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,48 +29,63 @@ FftPoissonSolver::FftPoissonSolver(
// 1- Inner solvers shall be passed in the constructor
// 2- Should it take an array of distribution functions ?
void FftPoissonSolver::operator()(
DSpanX const electrostatic_potential,
DSpanX const electric_field,
DViewSpXVx const allfdistribu) const
device_t<DSpanX> const electrostatic_potential,
device_t<DSpanX> const electric_field,
device_t<DViewSpXVx> const allfdistribu) const
{
Kokkos::Profiling::pushRegion("PoissonSolver");
assert(electrostatic_potential.domain() == ddc::get_domain<IDimX>(allfdistribu));
IDomainX const x_dom = electrostatic_potential.domain();

// Compute the RHS of the Poisson equation.
ddc::Chunk<double, IDomainX> rho(x_dom);
DFieldVx contiguous_slice_vx(allfdistribu.domain<IDimVx>());
m_compute_rho(rho, allfdistribu);
DFieldX rho_host(x_dom);
auto allfdistribu_host = ddc::create_mirror_and_copy(allfdistribu);

m_compute_rho(rho_host, allfdistribu_host);
device_t<DFieldX> rho(x_dom);
ddc::deepcopy(rho, rho_host);

// Build a mesh in the fourier space, for N points
IDomainFx const k_mesh = ddc::FourierMesh(x_dom, false);

ddc::Chunk<Kokkos::complex<double>, IDomainFx> intermediate_chunk
= ddc::Chunk(k_mesh, ddc::HostAllocator<Kokkos::complex<double>>());

device_t<ddc::Chunk<Kokkos::complex<double>, IDomainFx>> intermediate_chunk_alloc(k_mesh);
ddc::ChunkSpan intermediate_chunk = intermediate_chunk_alloc.span_view();
// Compute FFT(rho)
ddc::FFT_Normalization norm = ddc::FFT_Normalization::BACKWARD;
ddc::
fft(Kokkos::DefaultHostExecutionSpace(),
intermediate_chunk.span_view(),
fft(Kokkos::DefaultExecutionSpace(),
intermediate_chunk,
rho.span_view(),
ddc::kwArgs_fft {norm});

// Solve Poisson's equation -d2Phi/dx2 = rho
// in Fourier space as -kx*kx*FFT(Phi)=FFT(rho))
intermediate_chunk(k_mesh.front()) = 0.;
ddc::for_each(k_mesh.remove_first(IVectFx(1)), [&](IndexFx const ikx) {
intermediate_chunk(ikx) = intermediate_chunk(ikx) / (coordinate(ikx) * coordinate(ikx));
});
// in Fourier space as -kx*kx*FFT(Phi)=FFT(rho))

// First, 0 mode of Phi is set to 0 to avoid divergency. Note: to allow writing in the GPU memory, starting a device kernel is necessary which is performed by iterating on a 0D domain (single element).
ddc::for_each(
ddc::policies::parallel_device,
ddc::DiscreteDomain<>(),
KOKKOS_LAMBDA(ddc::DiscreteElement<>) {
intermediate_chunk(k_mesh.front()) = Kokkos::complex<double>(0.);
});

ddc::for_each(
ddc::policies::parallel_device,
k_mesh.remove_first(IVectFx(1)),
KOKKOS_LAMBDA(IndexFx const ikx) {
intermediate_chunk(ikx)
= intermediate_chunk(ikx) / (coordinate(ikx) * coordinate(ikx));
});
// Perform the inverse 1D FFT of the solution to deduce the electrostatic potential
ddc::
ifft(Kokkos::DefaultHostExecutionSpace(),
ifft(Kokkos::DefaultExecutionSpace(),
electrostatic_potential.span_view(),
intermediate_chunk.span_view(),
intermediate_chunk,
ddc::kwArgs_fft {norm});

// Compute efield = -dPhi/dx where Phi is the electrostatic potential
m_electric_field(electric_field, electrostatic_potential);
DFieldX electrostatic_potential_host(x_dom);
DFieldX electric_field_host(x_dom);
ddc::deepcopy(electrostatic_potential_host, electrostatic_potential);
m_electric_field(electric_field_host, electrostatic_potential_host);
ddc::deepcopy(electric_field, electric_field_host);
Kokkos::Profiling::popRegion();
}
6 changes: 4 additions & 2 deletions src/geometryXVx/poisson/fftpoissonsolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class FftPoissonSolver : public IPoissonSolver
* @param[out] electric_field The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu The distribution function.
*/
void operator()(DSpanX electrostatic_potential, DSpanX electric_field, DViewSpXVx allfdistribu)
const override;
void operator()(
device_t<DSpanX> electrostatic_potential,
device_t<DSpanX> electric_field,
device_t<DViewSpXVx> allfdistribu) const override;
};
12 changes: 6 additions & 6 deletions src/geometryXVx/poisson/ipoissonsolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ class IPoissonSolver
/**
* The operator which solves the equation using the method described by the class.
*
* @param[out] electrostatic_potential The electrostatic potential, the result of the poisson solver.
* @param[out] electric_field The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu The distribution function.
* @param[out] electrostatic_potential_device The electrostatic potential, the result of the poisson solver.
* @param[out] electric_field_device The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu_device The distribution function.
*/
virtual void operator()(
DSpanX electrostatic_potential,
DSpanX electric_field,
DViewSpXVx allfdistribu) const = 0;
device_t<DSpanX> electrostatic_potential_device,
device_t<DSpanX> electric_field_device,
device_t<DViewSpXVx> allfdistribu_device) const = 0;
};
7 changes: 6 additions & 1 deletion src/geometryXVx/poisson/nullpoissonsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@

#include "nullpoissonsolver.hpp"

void NullPoissonSolver::operator()(DSpanX const, DSpanX const, DViewSpXVx const) const {}
void NullPoissonSolver::operator()(
device_t<DSpanX> const electrostatic_potential_device,
device_t<DSpanX> const electric_field_device,
device_t<DViewSpXVx> const allfdistribu_device) const
{
}
22 changes: 18 additions & 4 deletions src/geometryXVx/poisson/nullpoissonsolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,28 @@
#include <geometry.hpp>

#include "ipoissonsolver.hpp"

/**
* @brief Null operator.
*
* An operator which does not solve any equation.
* It could be passed in operators which needs it, and used when solving poisson
* equation not relevant for the physics to study.
*/
class NullPoissonSolver : public IPoissonSolver
{
public:
NullPoissonSolver() = default;

~NullPoissonSolver() override = default;

void operator()(DSpanX electrostatic_potential, DSpanX electric_field, DViewSpXVx allfdistribu)
const override;
/**
* The operator which does not solves the equation.
*
* @param[out] electrostatic_potential_device The electrostatic potential, the result of the poisson solver.
* @param[out] electric_field_device The electric field, the derivative of the electrostatic potential.
* @param[in] allfdistribu_device The distribution function.
*/
void operator()(
device_t<DSpanX> const electrostatic_potential_device,
device_t<DSpanX> const electric_field_device,
device_t<DViewSpXVx> const allfdistribu_device) const override;
};
25 changes: 16 additions & 9 deletions src/geometryXVx/time_integration/predcorr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,29 @@ device_t<DSpanSpXVx> PredCorr::operator()(

// electrostatic potential and electric field (depending only on x)
DFieldX electrostatic_potential(allfdistribu.domain<IDimX>());
DFieldX electric_field(allfdistribu.domain<IDimX>());
device_t<DFieldX> electrostatic_potential_device(allfdistribu.domain<IDimX>());

device_t<DFieldX> electric_field_device(allfdistribu.domain<IDimX>());

// a 2D chunk of the same size as fdistribu
DFieldSpXVx allfdistribu_half_t(allfdistribu.domain());
device_t<DFieldSpXVx> allfdistribu_half_t_device(allfdistribu_device.domain());

m_poisson_solver(electrostatic_potential, electric_field, allfdistribu);
m_poisson_solver(electrostatic_potential_device, electric_field_device, allfdistribu_device);

int iter = 0;
for (; iter < steps; ++iter) {
double const iter_time = time_start + iter * dt;

// computation of the electrostatic potential at time tn and
// the associated electric field
m_poisson_solver(
electrostatic_potential_device,
electric_field_device,
allfdistribu_device);
// copies necessary to PDI
ddc::deepcopy(allfdistribu, allfdistribu_device);
m_poisson_solver(electrostatic_potential, electric_field, allfdistribu);

ddc::deepcopy(electrostatic_potential, electrostatic_potential_device);
ddc::PdiEvent("iteration")
.with("iter", iter)
.and_with("time_saved", iter_time)
Expand All @@ -53,23 +58,25 @@ device_t<DSpanSpXVx> PredCorr::operator()(

// copy fdistribu
ddc::deepcopy(allfdistribu_half_t_device, allfdistribu_device);
ddc::deepcopy(electric_field_device, electric_field);

// predictor
m_boltzmann_solver(allfdistribu_half_t_device, electric_field_device, dt / 2);

// computation of the electrostatic potential at time tn+1/2
// and the associated electric field
ddc::deepcopy(allfdistribu_half_t, allfdistribu_half_t_device);
m_poisson_solver(electrostatic_potential, electric_field, allfdistribu_half_t);
m_poisson_solver(
electrostatic_potential_device,
electric_field_device,
allfdistribu_half_t_device);
// correction on a dt
ddc::deepcopy(electric_field_device, electric_field);
m_boltzmann_solver(allfdistribu_device, electric_field_device, dt);
}

double const final_time = time_start + iter * dt;
m_poisson_solver(electrostatic_potential_device, electric_field_device, allfdistribu_device);
//copies necessary to PDI
ddc::deepcopy(allfdistribu, allfdistribu_device);
m_poisson_solver(electrostatic_potential, electric_field, allfdistribu);
ddc::deepcopy(electrostatic_potential, electrostatic_potential_device);
ddc::PdiEvent("last_iteration")
.with("iter", iter)
.and_with("time_saved", final_time)
Expand Down
3 changes: 0 additions & 3 deletions tests/geometryXVx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ target_link_libraries(unit_tests_lagrange
gtest_discover_tests(unit_tests_lagrange
TEST_SUFFIX "_${lagrange}")




target_sources(unit_tests_xperiod_vx
PRIVATE
femperiodicpoissonsolver.cpp
Expand Down
10 changes: 8 additions & 2 deletions tests/geometryXVx/femnonperiodicpoissonsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,14 @@ TEST(FemNonPeriodicPoissonSolver, Ordering)
}
}
}

poisson(electrostatic_potential, electric_field, allfdistribu);
device_t<DFieldX> electrostatic_potential_device(gridx);
device_t<DFieldX> electric_field_device(gridx);
device_t<DFieldSpXVx> allfdistribu_device(mesh);

ddc::deepcopy(allfdistribu_device, allfdistribu);
poisson(electrostatic_potential_device, electric_field_device, allfdistribu_device);
ddc::deepcopy(electric_field, electric_field_device);
ddc::deepcopy(electrostatic_potential, electrostatic_potential_device);

double error_pot = 0.0;
double error_field = 0.0;
Expand Down
Loading

0 comments on commit fd97369

Please sign in to comment.