From 03152258384e91c82a7801d0f89661a67282759a Mon Sep 17 00:00:00 2001 From: Emily Bourne Date: Tue, 9 Apr 2024 08:52:29 +0000 Subject: [PATCH] Fluid species dimensions implementation This merge request adds the support for describing a fluid species in prevision for the neutral model added in another merge request. This is done by adding a new dimension: - the `M`dimension (for Moments): a discrete space for describing the fluid moments of the fluid species. This dimension can be initialized with a varying number of moments that should be taken into account by the underlying physical model (ex. the code can solve only for the density, or for the density and velocity, etc.). - A new version of the predictor corrector scheme is added, to solve fluid models for these fluid species on top of the Vlasov-Poisson system. - A bunch of tests are added. See merge request gysela-developpers/gyselalibxx!385 -------------------------------------------- Co-authored-by: Emily Bourne Co-authored-by: yannm Co-authored-by: Baptiste LEGOUIX --- src/README.md | 2 +- src/geometryXVx/CMakeLists.txt | 2 + src/geometryXVx/README.md | 2 + src/geometryXVx/geometry/CMakeLists.txt | 1 + src/geometryXVx/geometry/geometry.hpp | 129 ++++++--- src/geometryXVx/geometryMX/CMakeLists.txt | 4 + src/geometryXVx/geometryMX/README.md | 6 + .../fluidinitialization/CMakeLists.txt | 26 ++ .../geometryMX/fluidinitialization/README.md | 6 + .../constantfluidinitialization.cpp | 24 ++ .../constantfluidinitialization.hpp | 31 ++ .../ifluidinitialization.hpp | 22 ++ .../geometryMX/fluidsolver/CMakeLists.txt | 31 ++ .../geometryMX/fluidsolver/README.md | 6 + .../geometryMX/fluidsolver/ifluidsolver.hpp | 30 ++ .../fluidsolver/nullfluidsolver.cpp | 20 ++ .../fluidsolver/nullfluidsolver.hpp | 37 +++ src/geometryXVx/rhs/CMakeLists.txt | 2 +- src/geometryXVx/rhs/README.md | 2 +- .../time_integration_hybrid/CMakeLists.txt | 31 ++ .../time_integration_hybrid/README.md | 15 + .../itimesolver_hybrid.hpp | 34 +++ .../predcorr_hybrid.cpp | 96 +++++++ .../predcorr_hybrid.hpp | 66 +++++ src/speciesinfo/CMakeLists.txt | 9 + src/speciesinfo/README.md | 5 + src/speciesinfo/moments.hpp | 38 +++ tests/geometryXVx/CMakeLists.txt | 9 +- tests/geometryXVx/geometryMX/CMakeLists.txt | 39 +++ tests/geometryXVx/geometryMX/fluidspecies.cpp | 211 ++++++++++++++ tests/geometryXVx/geometryMX/moments.cpp | 142 +++++++++ .../geometryMX/predcorr_hybrid.cpp | 269 ++++++++++++++++++ 32 files changed, 1302 insertions(+), 45 deletions(-) create mode 100644 src/geometryXVx/geometryMX/CMakeLists.txt create mode 100644 src/geometryXVx/geometryMX/README.md create mode 100644 src/geometryXVx/geometryMX/fluidinitialization/CMakeLists.txt create mode 100644 src/geometryXVx/geometryMX/fluidinitialization/README.md create mode 100644 src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.cpp create mode 100644 src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.hpp create mode 100644 src/geometryXVx/geometryMX/fluidinitialization/ifluidinitialization.hpp create mode 100644 src/geometryXVx/geometryMX/fluidsolver/CMakeLists.txt create mode 100644 src/geometryXVx/geometryMX/fluidsolver/README.md create mode 100644 src/geometryXVx/geometryMX/fluidsolver/ifluidsolver.hpp create mode 100644 src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.cpp create mode 100644 src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.hpp create mode 100644 src/geometryXVx/time_integration_hybrid/CMakeLists.txt create mode 100644 src/geometryXVx/time_integration_hybrid/README.md create mode 100644 src/geometryXVx/time_integration_hybrid/itimesolver_hybrid.hpp create mode 100644 src/geometryXVx/time_integration_hybrid/predcorr_hybrid.cpp create mode 100644 src/geometryXVx/time_integration_hybrid/predcorr_hybrid.hpp create mode 100644 src/speciesinfo/README.md create mode 100644 src/speciesinfo/moments.hpp create mode 100644 tests/geometryXVx/geometryMX/CMakeLists.txt create mode 100644 tests/geometryXVx/geometryMX/fluidspecies.cpp create mode 100644 tests/geometryXVx/geometryMX/moments.cpp create mode 100644 tests/geometryXVx/geometryMX/predcorr_hybrid.cpp diff --git a/src/README.md b/src/README.md index 01d3ad1c6..a40ce24dc 100644 --- a/src/README.md +++ b/src/README.md @@ -10,6 +10,6 @@ The `src/` folder contains all the code necessary to build a gyrokinetic semi-La - [interpolation](./interpolation/README.md) - Code describing interpolation methods. - [quadrature](./quadrature/README.md) - Code describing different quadrature methods. - +- [speciesinfo](./speciesinfo/README.md) - Code used to describe the different species. - [timestepper](./timestepper/README.md) - Code used to describe time-stepping methods (e.g. Runge-Kutta methods). - [utils](./utils/README.md) - Code describing utility functions. diff --git a/src/geometryXVx/CMakeLists.txt b/src/geometryXVx/CMakeLists.txt index 2fa22f0f9..b0ed78116 100644 --- a/src/geometryXVx/CMakeLists.txt +++ b/src/geometryXVx/CMakeLists.txt @@ -4,7 +4,9 @@ cmake_minimum_required(VERSION 3.15) add_subdirectory(poisson) add_subdirectory(geometry) +add_subdirectory(geometryMX) add_subdirectory(time_integration) +add_subdirectory(time_integration_hybrid) add_subdirectory(rhs) add_subdirectory(boltzmann) add_subdirectory(initialization) diff --git a/src/geometryXVx/README.md b/src/geometryXVx/README.md index e8358bbbe..fd29d0188 100644 --- a/src/geometryXVx/README.md +++ b/src/geometryXVx/README.md @@ -4,8 +4,10 @@ The `geometryXVx` folder contains all the code describing methods which are spec - [boltzmann](./boltzmann/README.md) : Solvers for a Boltzmann equation. - [geometry](./geometry/README.md) : All the dimension tags used for a simulation in the geometry. +- [geometryMX](./geometryMX/README.md) : Code describing a geometry with a single spatial dimension and a single fluid moment dimension. - [initialization](./initialization/README.md) : Initialization methods for the distribution function. - [poisson](./poisson/README.md) : Code describing the polar Poisson solver. - [rhs](./rhs/README.md) : Code describing the operators on the right hand side of the Boltzmann equation; namely sources, sinks and collisions. - [time\_integration](./time_integration/README.md) : Time integrators for a Boltzmann-Poisson system of equations. +- [time\_integration\_neutrals](./time_integration_neutrals/README.md) : Time integrators for a Boltzmann-Poisson system of equations, with a fluid neutral species. - [utils](./utils/README.md) : Miscellaneous utility functions. diff --git a/src/geometryXVx/geometry/CMakeLists.txt b/src/geometryXVx/geometry/CMakeLists.txt index 6fc2ac96b..a0b96a43a 100644 --- a/src/geometryXVx/geometry/CMakeLists.txt +++ b/src/geometryXVx/geometry/CMakeLists.txt @@ -12,6 +12,7 @@ target_include_directories("geometry_${GEOMETRY_VARIANT}" target_link_libraries("geometry_${GEOMETRY_VARIANT}" INTERFACE DDC::DDC gslx::speciesinfo + gslx::moments gslx::utils ) add_library("gslx::geometry_${GEOMETRY_VARIANT}" ALIAS "geometry_${GEOMETRY_VARIANT}") diff --git a/src/geometryXVx/geometry/geometry.hpp b/src/geometryXVx/geometry/geometry.hpp index b08fb2de4..689dce103 100644 --- a/src/geometryXVx/geometry/geometry.hpp +++ b/src/geometryXVx/geometry/geometry.hpp @@ -7,6 +7,7 @@ #include #include +#include #include /** @@ -47,9 +48,7 @@ struct RDimT }; - using CoordT = ddc::Coordinate; - using CoordX = ddc::Coordinate; using CoordVx = ddc::Coordinate; @@ -186,74 +185,106 @@ using SplineVxEvaluator_1d = ddc::SplineEvaluator< // Species dimension using IDimSp = SpeciesInformation; +using IDimM = Moments; -using IndexX = ddc::DiscreteElement; +using IndexM = ddc::DiscreteElement; + +using IndexSp = ddc::DiscreteElement; using IndexVx = ddc::DiscreteElement; -using IndexSp = ddc::DiscreteElement; +using IndexX = ddc::DiscreteElement; -using IndexSpX = ddc::DiscreteElement; -using IndexXVx = ddc::DiscreteElement; +using IndexSpM = ddc::DiscreteElement; + +using IndexSpMX = ddc::DiscreteElement; + +using IndexSpX = ddc::DiscreteElement; using IndexSpVx = ddc::DiscreteElement; using IndexSpXVx = ddc::DiscreteElement; +using IndexXVx = ddc::DiscreteElement; -using IVectX = ddc::DiscreteVector; + +using IVectM = ddc::DiscreteVector; + +using IVectSp = ddc::DiscreteVector; using IVectVx = ddc::DiscreteVector; -using IVectXVx = ddc::DiscreteVector; +using IVectX = ddc::DiscreteVector; -using IVectSpXVx = ddc::DiscreteVector; -using IVectSp = ddc::DiscreteVector; +using IVectSpM = ddc::DiscreteVector; -using IVectSpX = ddc::DiscreteVector; +using IVectSpMX = ddc::DiscreteVector; using IVectSpVx = ddc::DiscreteVector; +using IVectSpX = ddc::DiscreteVector; + +using IVectSpXVx = ddc::DiscreteVector; + +using IVectXVx = ddc::DiscreteVector; + using BSDomainX = ddc::DiscreteDomain; using BSDomainVx = ddc::DiscreteDomain; -using IDomainX = ddc::DiscreteDomain; -using IDomainVx = ddc::DiscreteDomain; -using IDomainXVx = ddc::DiscreteDomain; +using IDomainM = ddc::DiscreteDomain; using IDomainSp = ddc::DiscreteDomain; -using IDomainSpX = ddc::DiscreteDomain; +using IDomainVx = ddc::DiscreteDomain; + +using IDomainX = ddc::DiscreteDomain; + + + +using IDomainSpM = ddc::DiscreteDomain; + +using IDomainSpMX = ddc::DiscreteDomain; using IDomainSpVx = ddc::DiscreteDomain; +using IDomainSpX = ddc::DiscreteDomain; + using IDomainSpXVx = ddc::DiscreteDomain; +using IDomainXVx = ddc::DiscreteDomain; + template -using FieldX = device_t>; +using FieldSp = device_t>; template using FieldVx = device_t>; template -using FieldSp = device_t>; +using FieldX = device_t>; + template -using FieldSpX = device_t>; +using FieldSpM = device_t>; + +template +using FieldSpMX = device_t>; template using FieldSpVx = device_t>; +template +using FieldSpX = device_t>; + template using FieldSpXVx = device_t>; @@ -262,97 +293,116 @@ using FieldSpXVx = device_t>; template using DField = device_t>; +using DFieldSp = FieldSp; + +using DFieldVx = FieldVx; using DFieldX = FieldX; -using DFieldVx = FieldVx; -using DFieldSp = FieldSp; +using DFieldSpM = FieldSpM; -using DFieldSpX = FieldSpX; +using DFieldSpMX = FieldSpMX; using DFieldSpVx = FieldSpVx; +using DFieldSpX = FieldSpX; + using DFieldSpXVx = FieldSpXVx; -template -using SpanSp = device_t>; template -using SpanSpX = device_t>; +using BSSpanX = device_t>; template -using SpanX = device_t>; +using SpanSp = device_t>; template -using SpanSpX = device_t>; +using SpanX = device_t>; template using SpanVx = device_t>; template -using SpanSpXVx = device_t>; +using SpanSpMX = device_t>; template using SpanSpVx = device_t>; template -using BSSpanX = device_t>; +using SpanSpX = device_t>; +template +using SpanSpXVx = device_t>; template using DSpan = device_t>; +using DBSSpanX = BSSpanX; using DSpanSp = SpanSp; -using DSpanSpX = SpanSpX; +using DSpanVx = SpanVx; using DSpanX = SpanX; -using DSpanVx = SpanVx; +using DSpanSpMX = SpanSpMX; + +using DSpanSpVx = SpanSpVx; + +using DSpanSpX = SpanSpX; using DSpanSpXVx = SpanSpXVx; -using DSpanSpVx = SpanSpVx; -using DBSSpanX = BSSpanX; +template +using ViewSp = device_t>; + +template +using ViewVx = device_t>; template using ViewX = device_t>; + template -using ViewVx = device_t>; +using BSViewX = device_t>; template -using ViewSp = device_t>; +using ViewSpM = device_t>; template -using ViewSpX = device_t>; +using ViewSpMX = device_t>; template using ViewSpVx = device_t>; template -using ViewSpXVx = device_t>; +using ViewSpX = device_t>; template -using BSViewX = device_t>; +using ViewSpXVx = device_t>; template using DView = device_t>; +using DViewSp = ViewSp; + +using DViewVx = ViewVx; using DViewX = ViewX; -using DViewVx = ViewVx; -using DViewSp = ViewSp; +using DBSViewX = BSViewX; + +using DViewSpM = ViewSpM; + +using DViewSpMX = ViewSpMX; using DViewSpX = ViewSpX; @@ -360,7 +410,6 @@ using DViewSpVx = ViewSpVx; using DViewSpXVx = ViewSpXVx; -using DBSViewX = BSViewX; using RDimFx = ddc::Fourier; using CoordFx = ddc::Coordinate; diff --git a/src/geometryXVx/geometryMX/CMakeLists.txt b/src/geometryXVx/geometryMX/CMakeLists.txt new file mode 100644 index 000000000..56fecc006 --- /dev/null +++ b/src/geometryXVx/geometryMX/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: MIT + +add_subdirectory(fluidinitialization) +add_subdirectory(fluidsolver) \ No newline at end of file diff --git a/src/geometryXVx/geometryMX/README.md b/src/geometryXVx/geometryMX/README.md new file mode 100644 index 000000000..a52e088d2 --- /dev/null +++ b/src/geometryXVx/geometryMX/README.md @@ -0,0 +1,6 @@ +# Geometry (x) + +The `geometryMX` folder contains all the code describing methods which are specific to a geometry with 1 spatial dimension and one dimension describing fluid moments (ex: density, temperature, mean velocity). It is broken up into the following sub-folders: + +- [fluidinitialization](./fluidinitialization/README.md) : Initialization methods for fluid species. +- [fluidsolver](./fluidsolver/README.md) : Solver for fluid models. \ No newline at end of file diff --git a/src/geometryXVx/geometryMX/fluidinitialization/CMakeLists.txt b/src/geometryXVx/geometryMX/fluidinitialization/CMakeLists.txt new file mode 100644 index 000000000..d292aac12 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidinitialization/CMakeLists.txt @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: MIT + +foreach(GEOMETRY_VARIANT IN LISTS GEOMETRY_XVx_VARIANTS_LIST) + +add_library("fluidinitialization_${GEOMETRY_VARIANT}" STATIC + constantfluidinitialization.cpp +) + +target_compile_features("fluidinitialization_${GEOMETRY_VARIANT}" + PUBLIC + cxx_std_17 +) + +target_include_directories("fluidinitialization_${GEOMETRY_VARIANT}" + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries("fluidinitialization_${GEOMETRY_VARIANT}" + PUBLIC + DDC::DDC + gslx::geometry_${GEOMETRY_VARIANT} +) + +add_library("gslx::fluidinitialization_${GEOMETRY_VARIANT}" ALIAS "fluidinitialization_${GEOMETRY_VARIANT}") + +endforeach() diff --git a/src/geometryXVx/geometryMX/fluidinitialization/README.md b/src/geometryXVx/geometryMX/fluidinitialization/README.md new file mode 100644 index 000000000..63448e17e --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidinitialization/README.md @@ -0,0 +1,6 @@ +# Fluid Initialization methods + +The fluidinitialization folder contains any methods that define the value of a fluid species at the start of the simulation. The fluid species is described by its fluid moments. + +The implemented initialization methods are: +- ConstantFluidInitialization \ No newline at end of file diff --git a/src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.cpp b/src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.cpp new file mode 100644 index 000000000..a18e61e99 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.cpp @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +#include + +#include "constantfluidinitialization.hpp" + +ConstantFluidInitialization::ConstantFluidInitialization(host_t moments) + : m_moments_alloc(moments.domain()) +{ + ddc::parallel_deepcopy(m_moments_alloc, moments); +} + +DSpanSpMX ConstantFluidInitialization::operator()(DSpanSpMX const fluid_moments) const +{ + ddc::ChunkSpan moments(m_moments_alloc.span_view()); + ddc::parallel_for_each( + Kokkos::DefaultExecutionSpace(), + fluid_moments.domain(), + KOKKOS_LAMBDA(IndexSpMX const ispmx) { + IndexSpM ispm(ddc::select(ispmx)); + fluid_moments(ispmx) = moments(ispm); + }); + return fluid_moments; +} diff --git a/src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.hpp b/src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.hpp new file mode 100644 index 000000000..273c9c1c9 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidinitialization/constantfluidinitialization.hpp @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "ifluidinitialization.hpp" +/** + * @brief A class that initializes a fluid species with constant moments. + */ +class ConstantFluidInitialization : public IFluidInitialization +{ + DFieldSpM m_moments_alloc; + +public: + /** + * @brief Creates an instance of the ConstantFluidInitialization class. + * @param[in] moments The fluid moments the fluid species should be initialized with. + */ + ConstantFluidInitialization(host_t moments); + + ~ConstantFluidInitialization() override = default; + + /** + * @brief Initializes the fluid species with a constant moments. + * @param[inout] fluid_moments On input: a span referencing an uninitialized fluid species described through its moments. + * On output: a span referencing a the fluid species initialized with constant moments. + * @return A span referencing the initialized fluid species. + */ + DSpanSpMX operator()(DSpanSpMX const fluid_moments) const override; +}; \ No newline at end of file diff --git a/src/geometryXVx/geometryMX/fluidinitialization/ifluidinitialization.hpp b/src/geometryXVx/geometryMX/fluidinitialization/ifluidinitialization.hpp new file mode 100644 index 000000000..be58dff28 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidinitialization/ifluidinitialization.hpp @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +/** + * @brief An abstract class that allows for initializing a fluid species. + */ +class IFluidInitialization +{ +public: + virtual ~IFluidInitialization() = default; + + /** + * @brief Operator for initializing a neutral species. + * @param[in, out] fluid_moments On input: the uninitialized fluid species. + * On output: the initialized fluid species. + * @return A span referencing the initialized fluid species. + */ + virtual DSpanSpMX operator()(DSpanSpMX fluid_moments) const = 0; +}; diff --git a/src/geometryXVx/geometryMX/fluidsolver/CMakeLists.txt b/src/geometryXVx/geometryMX/fluidsolver/CMakeLists.txt new file mode 100644 index 000000000..2611cbb15 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidsolver/CMakeLists.txt @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: MIT + +foreach(GEOMETRY_VARIANT IN LISTS GEOMETRY_XVx_VARIANTS_LIST) + +add_library("fluidsolver_${GEOMETRY_VARIANT}" STATIC + nullfluidsolver.cpp +) + +target_compile_features("fluidsolver_${GEOMETRY_VARIANT}" + PUBLIC + cxx_std_17 +) + +target_include_directories("fluidsolver_${GEOMETRY_VARIANT}" + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries("fluidsolver_${GEOMETRY_VARIANT}" + PUBLIC + DDC::DDC + sll::SLL + gslx::advection + gslx::geometry_${GEOMETRY_VARIANT} + gslx::interpolation + gslx::quadrature + gslx::speciesinfo +) + +add_library("gslx::fluidsolver_${GEOMETRY_VARIANT}" ALIAS "fluidsolver_${GEOMETRY_VARIANT}") + +endforeach() diff --git a/src/geometryXVx/geometryMX/fluidsolver/README.md b/src/geometryXVx/geometryMX/fluidsolver/README.md new file mode 100644 index 000000000..c4750a771 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidsolver/README.md @@ -0,0 +1,6 @@ +# Fluid solvers (MX) + +The `fluidsolver` folder contains code that allows solving for models that describe a species considered as fluid. Such a fluid species is described by moments of the distribution function (density, particle flux, energy...) rather than by a complete distribution function. Equations describing the time evolution of such a fluid moments are called *fluid equations*. Such fluid equations describe the conservation of fluid moments: conservation of density, particle flux, energy, etc. + +The currently implemented solvers are : +- NullFluidSolver \ No newline at end of file diff --git a/src/geometryXVx/geometryMX/fluidsolver/ifluidsolver.hpp b/src/geometryXVx/geometryMX/fluidsolver/ifluidsolver.hpp new file mode 100644 index 000000000..18159e035 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidsolver/ifluidsolver.hpp @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +/** + * @brief An abstract class for solving a fluid model. + */ +class IFluidSolver +{ +public: + virtual ~IFluidSolver() = default; + + /** + * @brief Operator for solving the fluid model on one timestep. + * @param[in, out] fluid_moments On input : a span referencing the fluid species. + * On output : a span referencing the fluid species updated + * after solving the fluid model on one timestep. + * @param[in] allfdistribu A constant view referencing the distribution function. + * @param[in] efield A constant view referencing the electric field. + * @param[in] dt The timestep. + * @return a span referencing the fluid species after solving the fluid model on one timestep. + */ + virtual DSpanSpMX operator()( + DSpanSpMX fluid_moments, + DViewSpXVx allfdistribu, + DViewX efield, + double dt) const = 0; +}; diff --git a/src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.cpp b/src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.cpp new file mode 100644 index 000000000..8a96dd05c --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.cpp @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +#include "nullfluidsolver.hpp" + +NullFluidSolver::NullFluidSolver(IDomainSp const& dom_fluidsp) +{ + // charged fluid species is not allowed for now + for (IndexSp const isp : dom_fluidsp) { + assert(charge(isp) == 0); + } +} + +DSpanSpMX NullFluidSolver::operator()( + DSpanSpMX const fluid_moments, + DViewSpXVx const allfdistribu, + DViewX const efield, + double const dt) const +{ + return fluid_moments; +} diff --git a/src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.hpp b/src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.hpp new file mode 100644 index 000000000..5e3a13805 --- /dev/null +++ b/src/geometryXVx/geometryMX/fluidsolver/nullfluidsolver.hpp @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "ifluidsolver.hpp" + +/** + * @brief A dommy class that solves a fluid model. + * The fluid model leaves the moments of the fluid species unchanged. + */ +class NullFluidSolver : public IFluidSolver +{ +public: + /** + * @brief The constructor for the class. + * + * @param[in] dom_fluidsp The moments domain on which the fluid species is defined. + */ + NullFluidSolver(IDomainSp const& dom_fluidsp); + + ~NullFluidSolver() override = default; + + /** + * @brief Solves a dummy fluid model on a timestep dt. + * @param[in, out] fluid_moments On input : a span referencing the moments of the fluid species. + * On output : a span referencing the moments of the fluid species + * updated after solving the dummy fluid model. + * @param[in] allfdistribu A constant view referencing the distribution function. + * @param[in] efield A constant view referencing the electric field. + * @param[in] dt The timestep. + * @return a span referencing the fluid species after solving the dummy fluid model on one timestep. + */ + DSpanSpMX operator()(DSpanSpMX fluid_moments, DViewSpXVx allfdistribu, DViewX efield, double dt) + const override; +}; \ No newline at end of file diff --git a/src/geometryXVx/rhs/CMakeLists.txt b/src/geometryXVx/rhs/CMakeLists.txt index 8553aff7c..c2daa9321 100644 --- a/src/geometryXVx/rhs/CMakeLists.txt +++ b/src/geometryXVx/rhs/CMakeLists.txt @@ -29,7 +29,7 @@ target_link_libraries("rhs_${GEOMETRY_VARIANT}" gslx::quadrature gslx::speciesinfo gslx::initialization_${GEOMETRY_VARIANT} - gslx::timestepper + gslx::timestepper gslx::utils_${GEOMETRY_VARIANT} gslx::utils ) diff --git a/src/geometryXVx/rhs/README.md b/src/geometryXVx/rhs/README.md index 6b75f3bea..c50d14622 100644 --- a/src/geometryXVx/rhs/README.md +++ b/src/geometryXVx/rhs/README.md @@ -1,4 +1,4 @@ -# RHS +# RHS The `rhs` folder contains any operator that appears on the right-hand-side (rhs) of a Boltzmann equation. These operators are often referred to as `sources`, to differentiate them from the advective terms that appear on the left-hand-side of a Boltzmann equation. The term `sources` does not necessarily imply that the considered operator injects particles in the plasma. It can act as a source or a sink of particles, or as a collision term that conserves the number of particles for instance. diff --git a/src/geometryXVx/time_integration_hybrid/CMakeLists.txt b/src/geometryXVx/time_integration_hybrid/CMakeLists.txt new file mode 100644 index 000000000..46bfd509b --- /dev/null +++ b/src/geometryXVx/time_integration_hybrid/CMakeLists.txt @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: MIT + +foreach(GEOMETRY_VARIANT IN LISTS GEOMETRY_XVx_VARIANTS_LIST) + +add_library("time_integration_hybrid_${GEOMETRY_VARIANT}" STATIC + predcorr_hybrid.cpp +) + +target_compile_features("time_integration_hybrid_${GEOMETRY_VARIANT}" + PUBLIC + cxx_std_17 +) + +target_include_directories("time_integration_hybrid_${GEOMETRY_VARIANT}" + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries("time_integration_hybrid_${GEOMETRY_VARIANT}" + PUBLIC + DDC::DDC + DDC::PDI_Wrapper + gslx::boltzmann_${GEOMETRY_VARIANT} + gslx::initialization_${GEOMETRY_VARIANT} + gslx::fluidsolver_${GEOMETRY_VARIANT} + gslx::poisson_${GEOMETRY_VARIANT} + gslx::speciesinfo +) + +add_library("gslx::time_integration_hybrid_${GEOMETRY_VARIANT}" ALIAS "time_integration_hybrid_${GEOMETRY_VARIANT}") + +endforeach() diff --git a/src/geometryXVx/time_integration_hybrid/README.md b/src/geometryXVx/time_integration_hybrid/README.md new file mode 100644 index 000000000..1a1af7442 --- /dev/null +++ b/src/geometryXVx/time_integration_hybrid/README.md @@ -0,0 +1,15 @@ +# Time integration hybrid + +Code for time integrators that solves a Boltzmann-Poisson system for the electrostatic potential and the electron and ion distribution function, along with a fluid model to describe a fluid species. A predictor-corrector scheme is used to solve the Vlasov Poisson system coupled to the fluid equation on one timestep $\Delta t$ as +1. Find the electrostatic potential at time $t+\Delta t/2$ following: +- Solve Boltzmann equation for the distribution function at time $t+\Delta t/2$; +- Using this distribution function, solve Poisson equation for the electrostatic potential at time $t+\Delta t/2$. +2. With the potential computed at time $t+\Delta t/2$: +- Solve Boltzmann equation for the distribution function at time $t+\Delta t$; +- Using the distribution function at time $t+\Delta t$, solve Poisson equation for the electrostatic potential at time $t+\Delta t$; +- Solve the fluid model for the fluid species fluid moments at time $t+\Delta t$. + +For more information about the Boltzmann-Poisson time integrator, see [time\_integration](./../time_integration/README.md). + +The implemented time integrators that take into account fluid species are: +- PredCorrHybrid \ No newline at end of file diff --git a/src/geometryXVx/time_integration_hybrid/itimesolver_hybrid.hpp b/src/geometryXVx/time_integration_hybrid/itimesolver_hybrid.hpp new file mode 100644 index 000000000..63c7037dd --- /dev/null +++ b/src/geometryXVx/time_integration_hybrid/itimesolver_hybrid.hpp @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +/** + * @brief An abstract class for solving a Boltzmann-Poisson system of equations coupled to a fluid model. + */ +class ITimeSolverHybrid +{ +public: + virtual ~ITimeSolverHybrid() = default; + + /** + * @brief Operator for solving the Boltzmann-Poisson-fluid system. + * @param[in, out] allfdistribu On input : the initial value of the distribution function. + * On output : the value of the distribution function after solving + * the Boltzmann-Poisson-fluid system a given number of iterations. + * @param[in, out] fluid_moments On input : a span referencing the fluid species. + * On output : the fluid species after solving + * the Boltzmann-Poisson-fluid system a given number of iterations. + * @param[in] time_start The physical time at the start of the simulation. + * @param[in] dt The timestep. + * @param[in] steps The number of iterations to be performed by the solver. + * @return The distribution function after solving the system. + */ + virtual DSpanSpXVx operator()( + DSpanSpXVx allfdistribu, + DSpanSpMX fluid_moments, + double time_start, + double dt, + int steps = 1) const = 0; +}; diff --git a/src/geometryXVx/time_integration_hybrid/predcorr_hybrid.cpp b/src/geometryXVx/time_integration_hybrid/predcorr_hybrid.cpp new file mode 100644 index 000000000..e87d29c4f --- /dev/null +++ b/src/geometryXVx/time_integration_hybrid/predcorr_hybrid.cpp @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT + +#include +#include + +#include + +#include +#include +#include + +#include "predcorr_hybrid.hpp" + +PredCorrHybrid::PredCorrHybrid( + IBoltzmannSolver const& boltzmann_solver, + IFluidSolver const& fluid_solver, + IPoissonSolver const& poisson_solver) + : m_boltzmann_solver(boltzmann_solver) + , m_fluid_solver(fluid_solver) + , m_poisson_solver(poisson_solver) +{ +} + +DSpanSpXVx PredCorrHybrid::operator()( + DSpanSpXVx const allfdistribu, + DSpanSpMX fluid_moments, + double const time_start, + double const dt, + int const steps) const +{ + auto allfdistribu_alloc = ddc::create_mirror_view_and_copy(allfdistribu); + ddc::ChunkSpan allfdistribu_host = allfdistribu_alloc.span_view(); + + IDomainX const dom_x = ddc::get_domain(allfdistribu); + + // electrostatic potential and electric field (depending only on x) + host_t electrostatic_potential_host(dom_x); + DFieldX electrostatic_potential(dom_x); + + DFieldX electric_field(dom_x); + + host_t fluid_moments_host(fluid_moments.domain()); + + // a 2D chunk of the same size as fdistribu + host_t allfdistribu_half_t_host(allfdistribu.domain()); + DFieldSpXVx allfdistribu_half_t(allfdistribu.domain()); + + m_poisson_solver(electrostatic_potential, electric_field, allfdistribu); + + 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, electric_field, allfdistribu); + // copies necessary to PDI + ddc::parallel_deepcopy(allfdistribu_host, allfdistribu); + ddc::parallel_deepcopy(electrostatic_potential_host, electrostatic_potential); + ddc::parallel_deepcopy(fluid_moments_host, fluid_moments); + ddc::PdiEvent("iteration") + .with("iter", iter) + .and_with("time_saved", iter_time) + .and_with("fdistribu", allfdistribu_host) + .and_with("fluid_moments", fluid_moments_host) + .and_with("electrostatic_potential", electrostatic_potential_host); + + // copy fdistribu + ddc::parallel_deepcopy(allfdistribu_half_t, allfdistribu); + + // predictor + m_boltzmann_solver(allfdistribu_half_t, electric_field, dt / 2); + + // computation of the electrostatic potential at time tn+1/2 + // and the associated electric field + m_poisson_solver(electrostatic_potential, electric_field, allfdistribu_half_t); + // correction on a dt + m_boltzmann_solver(allfdistribu, electric_field, dt); + m_fluid_solver(fluid_moments, allfdistribu, electric_field, dt); + } + + double const final_time = time_start + iter * dt; + m_poisson_solver(electrostatic_potential, electric_field, allfdistribu); + + ddc::parallel_deepcopy(allfdistribu_host, allfdistribu); + ddc::parallel_deepcopy(electrostatic_potential_host, electrostatic_potential); + ddc::parallel_deepcopy(fluid_moments_host, fluid_moments); + ddc::PdiEvent("last_iteration") + .with("iter", iter) + .and_with("time_saved", final_time) + .and_with("fdistribu", allfdistribu_host) + .and_with("fluid_moments", fluid_moments_host) + .and_with("electrostatic_potential", electrostatic_potential_host); + + return allfdistribu; +} diff --git a/src/geometryXVx/time_integration_hybrid/predcorr_hybrid.hpp b/src/geometryXVx/time_integration_hybrid/predcorr_hybrid.hpp new file mode 100644 index 000000000..6bea1989d --- /dev/null +++ b/src/geometryXVx/time_integration_hybrid/predcorr_hybrid.hpp @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "itimesolver_hybrid.hpp" + +class IPoissonSolver; +class IBoltzmannSolver; +class IFluidSolver; + +/** + * @brief A class that solves a Boltzmann-Poisson system of equations coupled to a fluid particles model using a predictor-corrector scheme. + * + * A class that solves a Boltzmann-Poisson system with + * a predictor corrector scheme. This scheme consists in + * estimating the electric potential after a time interval + * of a half-timestep. This potential is then used to compute + * the value of the distribution function at time t+dt, and the + * value of the fluid moments for the fluid species. + * dt is the timestep of the simulation. + */ +class PredCorrHybrid : public ITimeSolverHybrid +{ +private: + IBoltzmannSolver const& m_boltzmann_solver; + + IFluidSolver const& m_fluid_solver; + + IPoissonSolver const& m_poisson_solver; + +public: + /** + * @brief Creates an instance of the predictor-corrector class. + * @param[in] boltzmann_solver A solver for a Boltzmann equation. + * @param[in] fluid_solver A solver for a fluid model. + * @param[in] poisson_solver A solver for a Poisson equation. + */ + PredCorrHybrid( + IBoltzmannSolver const& boltzmann_solver, + IFluidSolver const& fluid_solver, + IPoissonSolver const& poisson_solver); + + ~PredCorrHybrid() override = default; + + /** + * @brief Solves the Boltzmann-Poisson-fluid system. + * @param[in, out] allfdistribu On input: the initial value of the distribution function. + * On output: the value of the distribution function after solving + * the Boltzmann-Poisson-fluid system a given number of iterations. + ** @param[in, out] fluid_moments On input: a span referencing the fluid species. + * On output: the state of the fluid species after solving + * the Boltzmann-Poisson-fluid system a given number of iterations. + * @param[in] time_start The physical time at the start of the simulation. + * @param[in] dt The timestep. + * @param[in] steps The number of iterations to be performed by the predictor-corrector. + * @return The distribution function after solving the system. + */ + DSpanSpXVx operator()( + DSpanSpXVx allfdistribu, + DSpanSpMX fluid_moments, + double time_start, + double dt, + int steps = 1) const override; +}; diff --git a/src/speciesinfo/CMakeLists.txt b/src/speciesinfo/CMakeLists.txt index 4f09ab8c0..8f80feb32 100644 --- a/src/speciesinfo/CMakeLists.txt +++ b/src/speciesinfo/CMakeLists.txt @@ -12,3 +12,12 @@ target_link_libraries(speciesinfo INTERFACE sll::SLL ) add_library(gslx::speciesinfo ALIAS speciesinfo) + + +add_library(moments INTERFACE) +target_include_directories(moments + INTERFACE + "$") +target_link_libraries(moments INTERFACE + DDC::DDC) +add_library(gslx::moments ALIAS moments) \ No newline at end of file diff --git a/src/speciesinfo/README.md b/src/speciesinfo/README.md new file mode 100644 index 000000000..86f77cc63 --- /dev/null +++ b/src/speciesinfo/README.md @@ -0,0 +1,5 @@ +# SpeciesInfo (x, v\_x) + +The `speciesinfo` folder contains all the code describing the species described in the simulations. The currently implemented classes for describing plasma species are: + +- SpeciesInformation : species described by a kinetic or adiabatic model. diff --git a/src/speciesinfo/moments.hpp b/src/speciesinfo/moments.hpp new file mode 100644 index 000000000..420e7b645 --- /dev/null +++ b/src/speciesinfo/moments.hpp @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +#pragma once + +/// @brief Moments discrete dimension to access constant attributes related to fluid moments. +class Moments +{ +public: + /// alias of the discrete dimension + using discrete_dimension_type = Moments; + +public: + /// @brief Impl object storing attributes in `MemorySpace`. + template + class Impl + { + template + friend class Impl; + + public: + /// alias of the discrete dimension + using discrete_dimension_type = Moments; + + /** + * @brief Conversion constructor between different memory spaces. + * @param[in] impl object from `OMemorySpace` that will be used to initialize this object on `MemorySpace` + */ + template + explicit Impl(Impl const& impl) + { + } + + /** + * @brief Main constructor + */ + Impl() {} + }; +}; diff --git a/tests/geometryXVx/CMakeLists.txt b/tests/geometryXVx/CMakeLists.txt index b348b05d1..529edd2f7 100644 --- a/tests/geometryXVx/CMakeLists.txt +++ b/tests/geometryXVx/CMakeLists.txt @@ -28,9 +28,13 @@ target_link_libraries(unit_tests_${GEOMETRY_VARIANT} paraconf::paraconf gslx::advection gslx::boltzmann_${GEOMETRY_VARIANT} - gslx::initialization_${GEOMETRY_VARIANT} + gslx::fluidinitialization_${GEOMETRY_VARIANT} + gslx::fluidsolver_${GEOMETRY_VARIANT} + gslx::moments gslx::poisson_${GEOMETRY_VARIANT} gslx::quadrature + gslx::speciesinfo + gslx::time_integration_${GEOMETRY_VARIANT} gslx::utils_${GEOMETRY_VARIANT} ) @@ -63,11 +67,12 @@ target_sources(unit_tests_xperiod_vx fftpoissonsolver.cpp ) - target_sources(unit_tests_xnonperiod_vx PRIVATE femnonperiodicpoissonsolver.cpp) add_subdirectory(bump_on_tail) +add_subdirectory(geometryMX) + add_subdirectory(landau) add_subdirectory(sheath) diff --git a/tests/geometryXVx/geometryMX/CMakeLists.txt b/tests/geometryXVx/geometryMX/CMakeLists.txt new file mode 100644 index 000000000..a9861e9c5 --- /dev/null +++ b/tests/geometryXVx/geometryMX/CMakeLists.txt @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.15) + +include(GoogleTest) + +foreach(GEOMETRY_VARIANT IN LISTS GEOMETRY_XVx_VARIANTS_LIST) + +add_executable(unit_tests_geometryMX_${GEOMETRY_VARIANT} + ../../main.cpp + fluidspecies.cpp + moments.cpp + predcorr_hybrid.cpp +) + +target_compile_features(unit_tests_geometryMX_${GEOMETRY_VARIANT} PUBLIC cxx_std_17) +target_link_libraries(unit_tests_geometryMX_${GEOMETRY_VARIANT} + PUBLIC + GTest::gtest + GTest::gmock + gslx::advection + gslx::boltzmann_${GEOMETRY_VARIANT} + gslx::fluidinitialization_${GEOMETRY_VARIANT} + gslx::fluidsolver_${GEOMETRY_VARIANT} + gslx::moments + gslx::poisson_${GEOMETRY_VARIANT} + gslx::quadrature + gslx::speciesinfo + gslx::time_integration_${GEOMETRY_VARIANT} + gslx::time_integration_hybrid_${GEOMETRY_VARIANT} + gslx::utils_${GEOMETRY_VARIANT} +) + +gtest_discover_tests(unit_tests_geometryMX_${GEOMETRY_VARIANT} + TEST_SUFFIX "_${GEOMETRY_VARIANT}" + PROPERTIES TIMEOUT 10 +) + +endforeach() \ No newline at end of file diff --git a/tests/geometryXVx/geometryMX/fluidspecies.cpp b/tests/geometryXVx/geometryMX/fluidspecies.cpp new file mode 100644 index 000000000..3f9fe99f4 --- /dev/null +++ b/tests/geometryXVx/geometryMX/fluidspecies.cpp @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#include +#include + +#include + +#include "constantfluidinitialization.hpp" +#include "geometry.hpp" +#include "species_info.hpp" + +/** + * This test initializes a discrete space for kinetic species + * and fluid species, with corresponding masses and charges. + * The test checks if the masses() and charges() attributes + * of the discrete space correspond to the masses and charges + * attributes of the fluid and kinetic species. + */ +TEST(GeometryXM, KineticFluidSpecies) +{ + CoordX const x_min(0.0); + CoordX const x_max(1.0); + IVectX const x_size(50); + + // Creating mesh & supports + ddc::init_discrete_space(x_min, x_max, x_size); + ddc::init_discrete_space(SplineInterpPointsX::get_sampling()); + + IDomainX meshX(SplineInterpPointsX::get_domain()); + SplineXBuilder_1d const builder_x(meshX); + + // Kinetic species domain initialization + IVectSp const nb_kinspecies(2); + IDomainSp const dom_kinsp(IndexSp(0), nb_kinspecies); + + IndexSp const my_iion = dom_kinsp.front(); + IndexSp const my_ielec = dom_kinsp.back(); + + host_t> kinetic_charges(dom_kinsp); + kinetic_charges(my_ielec) = -1; + kinetic_charges(my_iion) = 1; + + host_t kinetic_masses(dom_kinsp); + double const mass_ion(400), mass_elec(1); + kinetic_masses(my_ielec) = mass_elec; + kinetic_masses(my_iion) = mass_ion; + + // Fluid species domain initialization + IVectSp const nb_fluidspecies(2); + IDomainSp const dom_fluidsp(IndexSp(dom_kinsp.back() + 1), nb_fluidspecies); + + host_t> fluid_charges(dom_fluidsp); + fluid_charges(dom_fluidsp.front()) = 1.; + fluid_charges(dom_fluidsp.back()) = -1.; + + host_t fluid_masses(dom_fluidsp); + fluid_masses(dom_fluidsp.front()) = 5.; + fluid_masses(dom_fluidsp.back()) = 8.; + + // Create the domain of kinetic species + fluid species + IDomainSp const dom_allsp(IndexSp(0), nb_kinspecies + nb_fluidspecies); + + // Create a Field that contains charges of all species + host_t> charges(dom_allsp); + + // fill the Field with charges of kinetic species + for (IndexSp isp : dom_kinsp) { + charges(isp) = kinetic_charges(isp); + } + + // fill the Field with charges of fluid species + for (IndexSp isp : dom_fluidsp) { + charges(isp) = fluid_charges(isp); + } + + // Create a Field that contains masses of kinetic and fluid species + host_t masses(dom_allsp); + + // fill the Field with masses of kinetic species + for (IndexSp isp : dom_kinsp) { + masses(isp) = kinetic_masses(isp); + } + + // fill the Field with masses of fluid species + for (IndexSp isp : dom_fluidsp) { + masses(isp) = fluid_masses(isp); + } + + ddc::init_discrete_space(std::move(charges), std::move(masses)); + + ddc::for_each(dom_allsp, [&](IndexSp const isp) { + if (isp.uid() < nb_kinspecies) { + EXPECT_EQ(ddc::discrete_space().charges()(isp), kinetic_charges(isp)); + EXPECT_EQ(ddc::discrete_space().masses()(isp), kinetic_masses(isp)); + + } else if (nb_kinspecies + 1 <= isp.uid() < nb_kinspecies + nb_fluidspecies) { + EXPECT_EQ(ddc::discrete_space().charges()(isp), fluid_charges(isp)); + EXPECT_EQ(ddc::discrete_space().masses()(isp), fluid_masses(isp)); + } + }); +} + +/** + * Same test as above with an adiabatic species + * on top of the fluid and kinetic species. + */ +TEST(GeometryXM, KineticFluidAdiabaticSpecies) +{ + CoordX const x_min(0.0); + CoordX const x_max(1.0); + IVectX const x_size(50); + + // Creating mesh & supports + ddc::init_discrete_space(x_min, x_max, x_size); + ddc::init_discrete_space(SplineInterpPointsX::get_sampling()); + + IDomainX meshX(SplineInterpPointsX::get_domain()); + SplineXBuilder_1d const builder_x(meshX); + + // Kinetic species domain initialization + IVectSp const nb_kinspecies(2); + IDomainSp const dom_kinsp(IndexSp(0), nb_kinspecies); + + IndexSp const my_iion = dom_kinsp.front(); + IndexSp const my_ielec = dom_kinsp.back(); + + host_t> kinetic_charges(dom_kinsp); + kinetic_charges(my_ielec) = -1; + kinetic_charges(my_iion) = 1; + + host_t kinetic_masses(dom_kinsp); + double const mass_ion(400), mass_elec(1); + kinetic_masses(my_ielec) = mass_elec; + kinetic_masses(my_iion) = mass_ion; + + // adiabatic species initialization + int nb_ion_adiabspecies = 1; + + // Fluid species domain initialization + IVectSp const nb_fluidspecies(2); + IDomainSp const dom_fluidsp(IndexSp(dom_kinsp.back() + 1), nb_fluidspecies); + + host_t> fluid_charges(dom_fluidsp); + fluid_charges(dom_fluidsp.front()) = 1.; + fluid_charges(dom_fluidsp.back()) = -1.; + + host_t fluid_masses(dom_fluidsp); + fluid_masses(dom_fluidsp.front()) = 5.; + fluid_masses(dom_fluidsp.back()) = 8.; + + // Create the domain of all species including kinetic species + fluid species + adiabatic species (if existing) + // adiabatic species are placed at the back of the domain + IDomainSp const dom_allsp(IndexSp(0), nb_kinspecies + nb_fluidspecies + nb_ion_adiabspecies); + + // Create a Field that contains charges of all species + host_t> charges(dom_allsp); + + // fill the Field with charges of kinetic species + for (IndexSp isp : dom_kinsp) { + charges(isp) = kinetic_charges(isp); + } + + // fill the Field with charges of fluid species + for (IndexSp isp : dom_fluidsp) { + charges(isp) = fluid_charges(isp); + } + + // fill the Field with charges of adiabatic species + double const charge_adiabspecies(3.); + charges(dom_allsp.back()) = nb_ion_adiabspecies * charge_adiabspecies; + + // Create the domain of kinetic and fluid species + IDomainSp const dom_kinfluidsp(IndexSp(0), nb_kinspecies + nb_fluidspecies); + + // Create a Field that contains masses of kinetic and fluid species (adiabatic species do not have a mass) + host_t masses(dom_kinfluidsp); + + // fill the Field with masses of kinetic species + for (IndexSp isp : dom_kinsp) { + masses(isp) = kinetic_masses(isp); + } + + // fill the Field with masses of fluid species + for (IndexSp isp : dom_fluidsp) { + masses(isp) = fluid_masses(isp); + } + ddc::init_discrete_space(std::move(charges), std::move(masses)); + + /** + * checks that the masses and charges of dom_allsp are well-ordered: + * kinetic species first, then fluid species, then adiabatic species. + */ + ddc::for_each(dom_allsp, [&](IndexSp const isp) { + if (isp.uid() < nb_kinspecies) { + EXPECT_EQ(ddc::discrete_space().charges()(isp), kinetic_charges(isp)); + EXPECT_EQ(ddc::discrete_space().masses()(isp), kinetic_masses(isp)); + + } else if (nb_kinspecies <= isp.uid() && isp.uid() < nb_kinspecies + nb_fluidspecies) { + EXPECT_EQ(ddc::discrete_space().charges()(isp), fluid_charges(isp)); + EXPECT_EQ(ddc::discrete_space().masses()(isp), fluid_masses(isp)); + + } else { + EXPECT_EQ(isp, dom_allsp.back()); + EXPECT_EQ(ddc::discrete_space().charges()(isp), charge_adiabspecies); + } + }); +} \ No newline at end of file diff --git a/tests/geometryXVx/geometryMX/moments.cpp b/tests/geometryXVx/geometryMX/moments.cpp new file mode 100644 index 000000000..bab8f8a7c --- /dev/null +++ b/tests/geometryXVx/geometryMX/moments.cpp @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: MIT + +#include + +#include + +#include +#include + +#include + +#include "constantfluidinitialization.hpp" +#include "geometry.hpp" +#include "species_info.hpp" + +/** + * This test initializes a discrete space for moments (density, + * particle_flux, stress) and initializes a neutral species + * defined on the moment space and a spatial dimension with constant values + * for the density, particle flux and stress. The test checks if the + * initialization works properly. + */ +TEST(GeometryXM, MomentsInitialization) +{ + CoordX const x_min(0.0); + CoordX const x_max(1.0); + IVectX const x_size(50); + + // Creating mesh & supports + ddc::init_discrete_space(x_min, x_max, x_size); + ddc::init_discrete_space(SplineInterpPointsX::get_sampling()); + + IDomainX meshX(SplineInterpPointsX::get_domain()); + SplineXBuilder_1d const builder_x(meshX); + + // Kinetic species domain initialization + IVectSp const nb_kinspecies(2); + IDomainSp const dom_kinsp(IndexSp(0), nb_kinspecies); + + IndexSp const iion = dom_kinsp.front(); + IndexSp const ielec = dom_kinsp.back(); + + host_t> kinetic_charges(dom_kinsp); + kinetic_charges(ielec) = -1; + kinetic_charges(iion) = 1; + + host_t kinetic_masses(dom_kinsp); + double const mass_ion(400), mass_elec(1); + kinetic_masses(ielec) = mass_elec; + kinetic_masses(iion) = mass_ion; + + // Neutral species domain initialization + IVectSp const nb_fluidspecies(1); + IDomainSp const dom_fluidsp(IndexSp(dom_kinsp.back() + 1), nb_fluidspecies); + IndexSp const ifluid = dom_fluidsp.front(); + + // neutrals charge is zero + host_t> fluid_charges(dom_fluidsp); + ddc::parallel_fill(fluid_charges, 0.); + + host_t fluid_masses(dom_fluidsp); + fluid_masses(ifluid) = kinetic_masses(iion); + + // Create the domain of kinetic species + fluid species + IDomainSp const dom_allsp(IndexSp(0), nb_kinspecies + nb_fluidspecies); + + // Create a Field that contains charges of all species + host_t> charges(dom_allsp); + + // fill the Field with charges of kinetic species + for (IndexSp isp : dom_kinsp) { + charges(isp) = kinetic_charges(isp); + } + + // fill the Field with charges of fluid species + for (IndexSp isp : dom_fluidsp) { + charges(isp) = fluid_charges(isp); + } + + // Create a Field that contains masses of kinetic and fluid species + host_t masses(dom_allsp); + + // fill the Field with masses of kinetic species + for (IndexSp isp : dom_kinsp) { + masses(isp) = kinetic_masses(isp); + } + + // fill the Field with masses of fluid species + for (IndexSp isp : dom_fluidsp) { + masses(isp) = fluid_masses(isp); + } + + ddc::init_discrete_space(std::move(charges), std::move(masses)); + + // Moments domain initialization + IVectM const nb_fluid_moments(3); + IDomainM const meshM(IndexM(0), nb_fluid_moments); + ddc::init_discrete_space(); + + IndexM idensity(0); + IndexM iparticle_flux(1); + IndexM istress(2); + + // Neutral species initialization + DFieldSpMX neutrals_alloc(IDomainSpMX(dom_fluidsp, meshM, meshX)); + auto neutrals = neutrals_alloc.span_view(); + + double const fluid_density_init(1.); + double const fluid_particle_flux_init(0.5); + double const fluid_stress_init(0.9); + + host_t moments_init(IDomainSpM(dom_fluidsp, meshM)); + moments_init(ifluid, idensity) = fluid_density_init; + moments_init(ifluid, iparticle_flux) = fluid_particle_flux_init; + moments_init(ifluid, istress) = fluid_stress_init; + + ConstantFluidInitialization fluid_init(moments_init); + fluid_init(neutrals); + + auto neutrals_host + = ddc::create_mirror_view_and_copy(Kokkos::DefaultHostExecutionSpace(), neutrals); + + double const tolerance(1.e-12); + ddc::for_each(ddc::get_domain(neutrals), [&](IndexSpX const ispx) { + IndexSp const isp(ddc::select(ispx)); + IndexX const ix(ddc::select(ispx)); + + // test for equality of density + IndexSpMX const idensity_loc(isp, idensity, ix); + EXPECT_LE(std::fabs(neutrals_host(idensity_loc) - fluid_density_init), tolerance); + + // test for equality of particle_flux + IndexSpMX const iparticle_flux_loc(isp, iparticle_flux, ix); + EXPECT_LE( + std::fabs(neutrals_host(iparticle_flux_loc) - fluid_particle_flux_init), + tolerance); + + // test for equality of stresses + IndexSpMX const istress_loc(isp, istress, ix); + EXPECT_LE(std::fabs(neutrals_host(istress_loc) - fluid_stress_init), tolerance); + }); +} \ No newline at end of file diff --git a/tests/geometryXVx/geometryMX/predcorr_hybrid.cpp b/tests/geometryXVx/geometryMX/predcorr_hybrid.cpp new file mode 100644 index 000000000..3b2811ebf --- /dev/null +++ b/tests/geometryXVx/geometryMX/predcorr_hybrid.cpp @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: MIT + +#include + +#include +#include + +#include +#include + +#include + +#include "bsl_advection_vx.hpp" +#include "bsl_advection_x.hpp" +#include "chargedensitycalculator.hpp" +#include "constantfluidinitialization.hpp" +#ifdef PERIODIC_RDIMX +#include "femperiodicpoissonsolver.hpp" +#else +#include "femnonperiodicpoissonsolver.hpp" +#endif +#include "Lagrange_interpolator.hpp" +#include "fftpoissonsolver.hpp" +#include "geometry.hpp" +#include "irighthandside.hpp" +#include "maxwellianequilibrium.hpp" +#include "neumann_spline_quadrature.hpp" +#include "nullfluidsolver.hpp" +#include "predcorr.hpp" +#include "predcorr_hybrid.hpp" +#include "quadrature.hpp" +#include "singlemodeperturbinitialization.hpp" +#include "species_info.hpp" +#include "spline_interpolator.hpp" +#include "splitrighthandsidesolver.hpp" +#include "splitvlasovsolver.hpp" + +/** + * This test creates one instance of the PredCorr class, and one instance of the + * PredCorrFluid class. With the NullFluidSolver class, + * this test verifies that the distribution function is the same after applying the + * predictor corrector scheme to it, with and without the fluid species. + */ +TEST(GeometryXM, PredCorrHybrid) +{ + CoordX const x_min(0.0); + CoordX const x_max(1.0); + IVectX const x_ncells(50); + + CoordVx const vx_min(-8); + CoordVx const vx_max(8); + IVectVx const vx_ncells(50); + + PC_tree_t conf_pdi = PC_parse_string(""); + PDI_init(conf_pdi); + + // Creating mesh & supports + ddc::init_discrete_space(x_min, x_max, x_ncells); + + ddc::init_discrete_space(vx_min, vx_max, vx_ncells); + + ddc::init_discrete_space(SplineInterpPointsX::get_sampling()); + ddc::init_discrete_space(SplineInterpPointsVx::get_sampling()); + + IDomainX meshX(SplineInterpPointsX::get_domain()); + IDomainVx meshVx(SplineInterpPointsVx::get_domain()); + IDomainXVx meshXVx(meshX, meshVx); + + SplineXBuilder const builder_x(meshXVx); +#ifndef PERIODIC_RDIMX + SplineXBuilder_1d const builder_x_poisson(meshX); +#endif + SplineVxBuilder const builder_vx(meshXVx); + SplineVxBuilder_1d const builder_vx_poisson(meshVx); + + // Kinetic species domain initialization + IVectSp const nb_kinspecies(2); + IDomainSp const dom_kinsp(IndexSp(0), nb_kinspecies); + + IndexSp const iion = dom_kinsp.front(); + IndexSp const ielec = dom_kinsp.back(); + + host_t> kinetic_charges(dom_kinsp); + kinetic_charges(ielec) = -1; + kinetic_charges(iion) = 1; + + host_t kinetic_masses(dom_kinsp); + double const mass_ion(400), mass_elec(1); + kinetic_masses(ielec) = mass_elec; + kinetic_masses(iion) = mass_ion; + + // Fluid species domain initialization + IVectSp const nb_fluidspecies(1); + IDomainSp const dom_fluidsp(IndexSp(dom_kinsp.back() + 1), nb_fluidspecies); + + // Fluid charges + host_t> fluid_charges(dom_fluidsp); + ddc::parallel_fill(fluid_charges, 0.); + + host_t fluid_masses(dom_fluidsp); + ddc::parallel_fill(fluid_masses, mass_ion); + + // Create the domain of kinetic species + fluid species + IDomainSp const dom_allsp(IndexSp(0), nb_kinspecies + nb_fluidspecies); + + // Create a Field that contains charges of all species + host_t> charges(dom_allsp); + + // fill the Field with charges of kinetic species + for (IndexSp isp : dom_kinsp) { + charges(isp) = kinetic_charges(isp); + } + + // fill the Field with charges of fluid species + for (IndexSp isp : dom_fluidsp) { + charges(isp) = fluid_charges(isp); + } + + // Create a Field that contains masses of kinetic and fluid species + host_t masses(dom_allsp); + + // fill the Field with masses of kinetic species + for (IndexSp isp : dom_kinsp) { + masses(isp) = kinetic_masses(isp); + } + + // fill the Field with masses of fluid species + for (IndexSp isp : dom_fluidsp) { + masses(isp) = fluid_masses(isp); + } + + ddc::init_discrete_space(std::move(charges), std::move(masses)); + + // Initialization of kinetic species distribution function + DFieldSpXVx allfdistribu_alloc(IDomainSpXVx(dom_kinsp, meshX, meshVx)); + auto allfdistribu = allfdistribu_alloc.span_view(); + + host_t kinsp_density_eq(dom_kinsp); + host_t kinsp_velocity_eq(dom_kinsp); + host_t kinsp_temperature_eq(dom_kinsp); + + ddc::parallel_fill(kinsp_density_eq, 1.); + ddc::parallel_fill(kinsp_velocity_eq, 0.); + ddc::parallel_fill(kinsp_temperature_eq, 1.); + + DFieldSpVx allfequilibrium_alloc(IDomainSpVx(dom_kinsp, meshVx)); + auto allfequilibrium = allfequilibrium_alloc.span_view(); + MaxwellianEquilibrium const init_fequilibrium( + std::move(kinsp_density_eq), + std::move(kinsp_temperature_eq), + std::move(kinsp_velocity_eq)); + init_fequilibrium(allfequilibrium); + + host_t> init_perturb_mode(dom_kinsp); + ddc::parallel_fill(init_perturb_mode, 2); + host_t init_perturb_amplitude(dom_kinsp); + ddc::parallel_fill(init_perturb_amplitude, 0.1); + + SingleModePerturbInitialization const + init(allfequilibrium, + init_perturb_mode.span_cview(), + init_perturb_amplitude.span_cview()); + init(allfdistribu); + + // Moments domain initialization + IVectM const nb_fluid_moments(3); + IDomainM const meshM(IndexM(0), nb_fluid_moments); + ddc::init_discrete_space(); + + IndexM idensity(0); + IndexM iflux(1); + IndexM istress(2); + + // Initialization of fluid species moments + DFieldSpMX fluid_moments_alloc(IDomainSpMX(dom_fluidsp, meshM, meshX)); + auto fluid_moments = fluid_moments_alloc.span_view(); + + host_t moments_init(IDomainSpM(dom_fluidsp, meshM)); + ddc::parallel_fill(moments_init[idensity], 1.); + ddc::parallel_fill(moments_init[iflux], 0.); + ddc::parallel_fill(moments_init[istress], 1.); + + ConstantFluidInitialization fluid_init(moments_init); + fluid_init(fluid_moments); + +#ifdef PERIODIC_RDIMX + ddc::PeriodicExtrapolationRule bv_x_min; + ddc::PeriodicExtrapolationRule bv_x_max; +#else + ddc::ConstantExtrapolationRule bv_x_min(x_min); + ddc::ConstantExtrapolationRule bv_x_max(x_max); +#endif + + // Creating operators + SplineXEvaluator const spline_x_evaluator(bv_x_min, bv_x_max); +#ifndef PERIODIC_RDIMX + SplineXEvaluator_1d const spline_x_evaluator_poisson(bv_x_min, bv_x_max); +#endif + PreallocatableSplineInterpolator const spline_x_interpolator(builder_x, spline_x_evaluator); + + IVectVx static constexpr gwvx {0}; + LagrangeInterpolator const + lagrange_vx_non_preallocatable_interpolator(3, gwvx); + PreallocatableLagrangeInterpolator< + IDimVx, + BCond::DIRICHLET, + BCond::DIRICHLET, + IDimX, + IDimVx> const lagrange_vx_interpolator(lagrange_vx_non_preallocatable_interpolator); + + BslAdvectionSpatial const advection_x(spline_x_interpolator); + BslAdvectionVelocity const advection_vx(lagrange_vx_interpolator); + + SplitVlasovSolver const vlasov(advection_x, advection_vx); + + host_t const quadrature_coeffs_host + = neumann_spline_quadrature_coefficients(meshVx, builder_vx_poisson); + + auto const quadrature_coeffs = ddc::create_mirror_view_and_copy( + Kokkos::DefaultExecutionSpace(), + quadrature_coeffs_host.span_view()); + ChargeDensityCalculator rhs(quadrature_coeffs); +#ifdef PERIODIC_RDIMX + IDomainSpXVx const meshSpXVx(dom_kinsp, meshXVx); + ddc::init_discrete_space(ddc::init_fourier_space(ddc::select(meshSpXVx))); + FftPoissonSolver const poisson(rhs); +#else + FemNonPeriodicPoissonSolver const poisson(builder_x_poisson, spline_x_evaluator_poisson, rhs); +#endif + + // construction of predcorr without fluid species + PredCorr const predcorr(vlasov, poisson); + + // distribution function to be evolved by predcorr without fluid species + DFieldSpXVx allfdistribu_predcorr_alloc(allfdistribu.domain()); + auto allfdistribu_predcorr = allfdistribu_predcorr_alloc.span_view(); + ddc::parallel_deepcopy(allfdistribu_predcorr, allfdistribu); + + double const time_start(0.); + int const nb_iter(10); + double const deltat(0.1); + predcorr(allfdistribu_predcorr, time_start, deltat, nb_iter); + + // construction of predcorr with fluid species + NullFluidSolver const fluidsolver(dom_fluidsp); + PredCorrHybrid const predcorr_hybrid(vlasov, fluidsolver, poisson); + predcorr_hybrid(allfdistribu, fluid_moments, time_start, deltat, nb_iter); + + auto allfdistribu_host + = ddc::create_mirror_view_and_copy(Kokkos::DefaultHostExecutionSpace(), allfdistribu); + + auto allfdistribu_predcorr_host = ddc:: + create_mirror_view_and_copy(Kokkos::DefaultHostExecutionSpace(), allfdistribu_predcorr); + + /** + * Since the fluid model uses NullFluidSolver, + * the distribution function evolved with PredCorrFluid and PredCorr + * should be equal + */ + double const tolerance(1.e-12); + ddc::for_each(allfdistribu.domain(), [&](IndexSpXVx const ispxvx) { + EXPECT_LE( + std::fabs(allfdistribu_host(ispxvx) - allfdistribu_predcorr_host(ispxvx)), + tolerance); + }); + + PC_tree_destroy(&conf_pdi); + PDI_finalize(); +}