Commit e0a0fd80 authored by ESTERIE Pierre's avatar ESTERIE Pierre
Browse files

New particle proxy

parent ddf375fa
// --------------------------------
// See LICENCE file at project root
// File : particle.hpp
// --------------------------------
#ifndef SCALFMM_CONTAINER_PARTICLE_IMPL_HPP
#define SCALFMM_CONTAINER_PARTICLE_IMPL_HPP
#include "scalfmm/meta/utils.hpp"
#include <bits/c++config.h>
#include <inria/integer_sequence.hpp>
#include <iterator>
#include <scalfmm/container/point.hpp>
#include <scalfmm/meta/type_pack.hpp>
#include <tuple>
#include <type_traits>
///**
// * \brief Multi-purpose particle implementation
// *
// * This template implementation of a particle allows simple reuse for several
// * use cases. The aim it to provide an interface that is compatible with the
// * rest of ScalFMM. It is mainly intended to be used as an interface for the
// * particle containers.
// *
// * The Types parameter pack can accept any type that is to be considered as a
// * particle attribute. You can also specify scalfmm::pack type to factorise
// * several types.
// *
// * In the following example, the two specialisations of the class will give the
// * same final structure.
// *
// * ```
// * using FReal = double;
// * static constexpr std::size_t dimension = 3;
// *
// * particle<FReal, dimension, int, float, float, float, float>;
// * particle<FReal, dimension, int, scalfmm::meta::pack<4, float> >;
// * ```
// *
// * The base of these two classes is
// * ```
// * std::tuple<double, double, double, int, float, float, float, float>;
// * ```
// *
// * \warning Although the classes will have the same final layout, C++ considers
// * these two classes to be different !
// *
// * ##### Example
// *
// * ```
// * // Define a 3D particle with an int attribute
// * using Particle = particle<double, 3, int>;
// *
// * Particle p;
// * p.get<>
// * ```
// *
// *
// * \tparam FReal Floating point type
// * \tparam dimension Space dimension count
// * \tparam Types Attributes type list
// *
// */
namespace scalfmm::container
{
/// @brief
///
/// @tparam PositionType
/// @tparam PositionDim
/// @tparam InputsType
/// @tparam NInputs
/// @tparam OutputsType
/// @tparam MOutputs
/// @tparam Variables
template<typename PositionType, std::size_t PositionDim, typename InputsType, std::size_t NInputs,
typename OutputsType, std::size_t MOutputs, typename... Variables>
struct particle_impl
{
public:
using position_value_type = PositionType;
static constexpr std::size_t dimension = PositionDim;
static constexpr std::size_t dimension_size = PositionDim;
using position_type = container::point<position_value_type, dimension_size>;
using position_tuple_type = meta::generate_tuple_t<position_value_type, dimension_size>;
using range_position_type = meta::make_range_sequence<0, dimension_size>;
using inputs_value_type = InputsType;
static constexpr std::size_t inputs_size = NInputs;
using inputs_type = std::array<inputs_value_type, inputs_size>;
using inputs_tuple_type = meta::generate_tuple_t<inputs_value_type, inputs_size>;
using range_inputs_type = meta::make_range_sequence<dimension_size, dimension_size + inputs_size>;
using outputs_value_type = OutputsType;
static constexpr std::size_t outputs_size = MOutputs;
using outputs_type = std::array<outputs_value_type, outputs_size>;
using outputs_tuple_type = meta::generate_tuple_t<outputs_value_type, outputs_size>;
using range_outputs_type =
meta::make_range_sequence<dimension_size + inputs_size, dimension_size + inputs_size + outputs_size>;
using variables_type = std::tuple<Variables...>;
static constexpr std::size_t variables_size = sizeof...(Variables);
using range_variables_type =
meta::make_range_sequence<dimension_size + inputs_size + outputs_size,
dimension_size + inputs_size + outputs_size + variables_size>;
using tuple_type =
typename meta::cat<typename meta::pack_expand_tuple<meta::pack<dimension_size, position_value_type>,
meta::pack<inputs_size, inputs_value_type>,
meta::pack<outputs_size, outputs_value_type>>,
variables_type>::type;
constexpr particle_impl() = default;
constexpr particle_impl(particle_impl const&) = default;
constexpr particle_impl(particle_impl&&) noexcept = default;
constexpr inline auto operator=(particle_impl const&) -> particle_impl& = default;
constexpr inline auto operator=(particle_impl&&) noexcept -> particle_impl& = default;
~particle_impl() = default;
/// @brief
///
/// @param p
/// @param i
/// @param o
/// @param vs
///
/// @return
constexpr particle_impl(position_type p, inputs_value_type i, outputs_value_type o, Variables... vs)
: m_position(p)
, m_variables(vs...)
{
std::fill(std::begin(m_inputs), std::end(m_inputs), i);
std::fill(std::begin(m_outputs), std::end(m_outputs), o);
}
/// @brief
///
/// @param p
/// @param i
/// @param o
/// @param vs
///
/// @return
constexpr particle_impl(position_type p, inputs_type i, outputs_type o, Variables... vs)
: m_position(p)
, m_inputs(i)
, m_outputs(o)
, m_variables(vs...)
{
}
/// @brief
///
/// @param t
particle_impl(tuple_type t)
: m_position(meta::to_array(meta::sub_tuple(t, range_position_type{})))
, m_inputs{meta::to_array(meta::sub_tuple(t, range_inputs_type{}))}
, m_outputs{meta::to_array(meta::sub_tuple(t, range_outputs_type{}))}
, m_variables(meta::sub_tuple(t, range_variables_type{}))
{
}
[[nodiscard]] constexpr inline auto as_tuple() const noexcept -> tuple_type
{
return std::tuple_cat(meta::to_tuple(m_position), meta::to_tuple(m_inputs), meta::to_tuple(m_outputs),
m_variables);
}
constexpr inline auto position(position_type p) noexcept -> void { m_position = p; }
[[nodiscard]] constexpr inline auto position() const noexcept -> position_type const& { return m_position; }
[[nodiscard]] constexpr inline auto position() noexcept -> position_type& { return m_position; }
[[nodiscard]] constexpr inline auto position(std::size_t i) const noexcept -> position_value_type
{
return m_position.at(i);
}
[[nodiscard]] constexpr inline auto position(std::size_t i) noexcept -> position_value_type&
{
return m_position.at(i);
}
constexpr inline auto inputs(inputs_type i) noexcept -> void { m_inputs = i; }
[[nodiscard]] constexpr inline auto inputs() const noexcept -> inputs_type const& { return m_inputs; }
[[nodiscard]] constexpr inline auto inputs() noexcept -> inputs_type& { return m_inputs; }
[[nodiscard]] constexpr inline auto inputs(std::size_t i) const noexcept -> inputs_value_type
{
return m_inputs.at(i);
}
[[nodiscard]] constexpr inline auto inputs(std::size_t i) noexcept -> inputs_value_type&
{
return m_inputs.at(i);
}
constexpr inline auto outputs(outputs_type i) noexcept -> void { m_outputs = i; }
[[nodiscard]] constexpr inline auto outputs() const noexcept -> outputs_type const& { return m_outputs; }
[[nodiscard]] constexpr inline auto outputs() noexcept -> outputs_type& { return m_outputs; }
[[nodiscard]] constexpr inline auto outputs(std::size_t i) const noexcept -> outputs_value_type
{
return m_outputs.at(i);
}
[[nodiscard]] constexpr inline auto outputs(std::size_t i) noexcept -> outputs_value_type&
{
return m_outputs.at(i);
}
[[nodiscard]] constexpr inline auto variables() const noexcept -> variables_type const& { return m_variables; }
[[nodiscard]] constexpr inline auto variables() noexcept -> variables_type& { return m_variables; }
template<typename T>
constexpr inline auto variables(T v) noexcept -> std::enable_if_t<std::is_same_v<T, variables_type>, void>
{
m_variables = v;
}
template<typename... Vs>
constexpr inline auto variables(Vs... vs) noexcept -> std::enable_if_t<(sizeof...(Vs) != 0), void>
{
m_variables = std::make_tuple(vs...);
}
private:
position_type m_position{};
inputs_type m_inputs{};
outputs_type m_outputs{};
variables_type m_variables{};
};
} // namespace scalfmm::container
#endif // SCALFMM_CONTAINER_PARTICLE_HPP
// --------------------------------
// See LICENCE file at project root
// File : particle_proxy.hpp
// --------------------------------
#ifndef SCALFMM_CONTAINER_PARTICLE_PROXY_HPP
#define SCALFMM_CONTAINER_PARTICLE_PROXY_HPP
#include "scalfmm/meta/utils.hpp"
#include <scalfmm/container/point.hpp>
#include <scalfmm/meta/type_pack.hpp>
#include <tuple>
#include <type_traits>
namespace scalfmm::container
{
/// Proxy for particle
template<typename PositionType, std::size_t PositionDim, typename InputsType, std::size_t NInputs,
typename OutputsType, std::size_t MOutputs, typename... Variables>
struct particle_proxy
{
public:
using position_value_type = PositionType;
static constexpr std::size_t dimension = PositionDim;
static constexpr std::size_t dimension_size = PositionDim;
// here we add a reference to instantiate a proxy of the point
using position_type = container::point<std::add_lvalue_reference_t<position_value_type>, dimension_size>;
using range_position_type = meta::make_range_sequence<0, dimension_size>;
using inputs_value_type = InputsType;
static constexpr std::size_t inputs_size = NInputs;
using inputs_type = std::array<std::reference_wrapper<inputs_value_type>, inputs_size>;
using range_inputs_type = meta::make_range_sequence<dimension_size, dimension_size + inputs_size>;
using outputs_value_type = OutputsType;
static constexpr std::size_t outputs_size = MOutputs;
using outputs_type = std::array<std::reference_wrapper<outputs_value_type>, outputs_size>;
using range_outputs_type =
meta::make_range_sequence<dimension_size + inputs_size, dimension_size + inputs_size + outputs_size>;
using variables_type = std::tuple<std::add_lvalue_reference_t<Variables>...>;
static constexpr std::size_t variables_size = sizeof...(Variables);
using range_variables_type =
meta::make_range_sequence<dimension_size + inputs_size + outputs_size,
dimension_size + inputs_size + outputs_size + variables_size>;
// tuple type from which we can construct the proxy.
using tuple_type =
typename meta::cat<typename meta::pack_expand_tuple<meta::pack<dimension_size, std::add_lvalue_reference_t<position_value_type>>,
meta::pack<inputs_size, std::add_lvalue_reference_t<inputs_value_type>>,
meta::pack<outputs_size, std::add_lvalue_reference_t<outputs_value_type>>>,
variables_type>::type;
constexpr particle_proxy() = delete;
constexpr particle_proxy(particle_proxy const&) = default;
constexpr particle_proxy(particle_proxy&&) noexcept = default;
constexpr inline auto operator=(particle_proxy const&) -> particle_proxy& = default;
constexpr inline auto operator=(particle_proxy&&) noexcept -> particle_proxy& = default;
~particle_proxy() = default;
particle_proxy(tuple_type& t)
: m_position(container::get_reference_sequence(meta::sub_tuple(t, range_position_type{})))
, m_inputs{container::get_reference_sequence(meta::sub_tuple(t, range_inputs_type{}))}
, m_outputs{container::get_reference_sequence(meta::sub_tuple(t, range_outputs_type{}))}
, m_variables(meta::sub_tuple(t, range_variables_type{}))
{
}
particle_proxy(tuple_type const& t)
: m_position(container::get_reference_sequence(meta::sub_tuple(t, range_position_type{})))
, m_inputs{container::get_reference_sequence(meta::sub_tuple(t, range_inputs_type{}))}
, m_outputs{container::get_reference_sequence(meta::sub_tuple(t, range_outputs_type{}))}
, m_variables(meta::sub_tuple(t, range_variables_type{}))
{
}
[[nodiscard]] constexpr inline auto as_tuple() const noexcept -> tuple_type
{
return std::tuple_cat(meta::to_tuple(m_position), meta::to_tuple(m_inputs), meta::to_tuple(m_outputs),
m_variables);
}
[[nodiscard]] constexpr inline auto position() const noexcept -> position_type const& { return m_position; }
[[nodiscard]] constexpr inline auto position() noexcept -> position_type& { return m_position; }
[[nodiscard]] constexpr inline auto position(std::size_t i) const noexcept -> position_value_type const&
{
return m_position.at(i);
}
[[nodiscard]] constexpr inline auto position(std::size_t i) noexcept -> position_value_type&
{
return m_position.at(i);
}
[[nodiscard]] constexpr inline auto inputs() const noexcept -> inputs_type const& { return m_inputs; }
[[nodiscard]] constexpr inline auto inputs() noexcept -> inputs_type& { return m_inputs; }
[[nodiscard]] constexpr inline auto inputs(std::size_t i) const noexcept -> inputs_value_type const&
{
return m_inputs.at(i).get();
}
[[nodiscard]] constexpr inline auto inputs(std::size_t i) noexcept -> inputs_value_type&
{
return m_inputs.at(i).get();
}
[[nodiscard]] constexpr inline auto outputs() const noexcept -> outputs_type const& { return m_outputs; }
[[nodiscard]] constexpr inline auto outputs() noexcept -> outputs_type& { return m_outputs; }
[[nodiscard]] constexpr inline auto outputs(std::size_t i) const noexcept -> outputs_value_type const&
{
return m_outputs.at(i).get();
}
[[nodiscard]] constexpr inline auto outputs(std::size_t i) noexcept -> outputs_value_type&
{
return m_outputs.at(i).get();
}
[[nodiscard]] constexpr inline auto variables() const noexcept -> variables_type const& { return m_variables; }
[[nodiscard]] constexpr inline auto variables() noexcept -> variables_type& { return m_variables; }
template<typename T>
constexpr inline auto variables(T v) noexcept -> std::enable_if_t<std::is_same_v<T, variables_type>, void>
{
m_variables = v;
}
template<typename... Vs>
constexpr inline auto variables(Vs... vs) noexcept -> std::enable_if_t<(sizeof...(Vs) != 0), void>
{
m_variables = std::make_tuple(vs...);
}
private:
position_type m_position;
inputs_type m_inputs;
outputs_type m_outputs;
variables_type m_variables;
};
} // namespace scalfmm::container
#endif // SCALFMM_CONTAINER_particle_proxy_PROXY_HPP
......@@ -102,6 +102,11 @@ namespace scalfmm::container
{
}
explicit point_proxy(std::array<reference_wrapper_type, dimension> const& a)
: base_type(a)
{
}
template<typename... Ts, std::enable_if_t<meta::all(std::is_same_v<value_type, Ts>...), int> = 0>
explicit point_proxy(std::tuple<Ts...>& a)
: base_type(get_reference_sequence(a))
......
......@@ -117,6 +117,7 @@ namespace scalfmm::container
using reference = tuple_of_ref;
using pointer = void;
using difference_type = std::size_t;
static constexpr bool is_const_qualified{IsConst};
private:
template<size_t... Is>
......
......@@ -739,6 +739,7 @@ namespace scalfmm::tools
const VALUE_T box_width)
{
// get the number of elements per particles in the container build with tuples.
// TODO : nb_elements via value_type stored in the container -> change value_type in particle container
constexpr int nb_elt_per_par = std::tuple_size<typename CONTAINER_T::value_type>::value;
// Not good output_values are put in input_values
constexpr int nb_input_per_par = CONTAINER_T::particle_type::inputs_size;
......
......@@ -347,6 +347,15 @@ namespace scalfmm::component
inline auto update_interaction_list() -> void
{
// leaf level update only P2P ???
// This method is in two passes
//
// The first one is the pass on the leaves
// It builds the symbolic interactions and the iterator list corresponding
// to the existing leaf.
// The second pass build the iterator list corresponding to the interaction list of the leaf
//
// First for each iterates on the group of leaves
// Second for each iterates on the leaves
component::for_each(std::get<0>(begin()), std::get<0>(end()), [this](auto& group) {
std::size_t index_in_group{0};
component::for_each(std::begin(*group), std::end(*group), [&group, &index_in_group, this](auto& leaf) {
......@@ -357,6 +366,7 @@ namespace scalfmm::component
});
});
// here we get the first level of cells
auto tree_height = std::distance(std::get<1>(begin()), std::get<1>(end()));
auto cell_level_it = std::get<1>(begin()) + (tree_height - 1);
......
......@@ -3,6 +3,7 @@
// --------------------
#include <bits/c++config.h>
#include <cmath>
#include <type_traits>
#define CATCH_CONFIG_RUNNER
#include <catch2/catch.hpp>
#include <string>
......@@ -11,12 +12,13 @@
//#include <scalfmm/utils/static_assert_as_exception.hpp>
// Followed by file where assertions must be tested
#include <tuple>
#include <array>
#include "scalfmm/meta/utils.hpp"
#include "scalfmm/container/particle.hpp"
#include "scalfmm/container/particle_container.hpp"
#include "scalfmm/meta/utils.hpp"
#include <array>
#include <tuple>
//TEST_CASE("Static test", "[static-assertion]")
// TEST_CASE("Static test", "[static-assertion]")
//{
// using namespace scalfmm;
//
......@@ -30,7 +32,8 @@
// catch(test::exceptionalized_static_assert const& esa)
// {
// throwed = true;
// std::cout << colors::on_green << colors::bold << colors::white << esa.what() << colors::reset << std::endl;
// std::cout << colors::on_green << colors::bold << colors::white << esa.what() << colors::reset <<
// std::endl;
// }
// REQUIRE(throwed);
// }
......@@ -39,21 +42,179 @@
//#undef SCALFMM_TEST_EXCEPTIONALIZE_STATIC_ASSERT
//#undef static_assert
TEST_CASE("Particle construction", "[particle-construction]")
TEST_CASE("particle-construction", "[particle-construction]")
{
using namespace scalfmm;
SECTION("Default construction", "[default]")
SECTION("default-construction", "[default-construction]")
{
container::particle<double, 3, double, 2, double, 2, std::size_t> p{};
}
SECTION("proxy-construction", "[proxy-construction]")
{
container::particle_container<container::particle<float, 3, float, 2, float, 2, std::size_t>> c(1);
auto it = std::begin(c);
*it = std::make_tuple(1., 2., 3., 4., 5., 6., 7., 150);
container::particle<float&, 3, float&, 2, float&, 2, std::size_t&> p(*it);
auto tuple_ref = p.as_tuple();
meta::get<0>(tuple_ref) = 0.25;
std::cout << meta::get<0>(*it) << '\n';
*it = std::make_tuple(1., 2., 3., 4., 5., 6., 7., 150);
auto itc = std::cbegin(c);
container::particle<const float&, 3, const float&, 2, const float&, 2, const std::size_t&> pc(*itc);
auto tuple_ref_c = pc.as_tuple();
// meta::get<0>(tuple_ref_c) = 0.25;
std::cout << meta::get<0>(tuple_ref_c) << '\n';
std::cout << pc << '\n';
}
}
TEST_CASE("particle-common", "[particle-common]")
{
using namespace scalfmm;
using particle_type = container::particle<float, 3, float, 2, float, 2, std::size_t, std::size_t>;
using proxy_type = container::particle<float&, 3, float&, 2, float&, 2, std::size_t&, std::size_t&>;
SECTION("particle-common", "[particle-common]")
{
container::particle_container<container::particle<float, 3, float, 2, float, 2, std::size_t, std::size_t>> c(1);
auto it = std::begin(c);
*it = std::make_tuple(1., 1., 1., 2., 2., 3., 3., 4, 4);
particle_type ref(*it);
proxy_type proxy(*it);
REQUIRE(ref.sizeof_dimension() == 3);
REQUIRE(ref.sizeof_inputs() == 2);
REQUIRE(ref.sizeof_outputs() == 2);
REQUIRE(ref.sizeof_variables() == 2);
REQUIRE(proxy.sizeof_dimension() == 3);
REQUIRE(proxy.sizeof_inputs() == 2);
REQUIRE(proxy.sizeof_outputs() == 2);
REQUIRE(proxy.sizeof_variables() == 2);
std::size_t i{0};
meta::repeat(
[&i, &ref, &proxy](auto const& e) {
REQUIRE(ref.position(i) == e);
REQUIRE(proxy.position(i) == e);
++i;
},
meta::sub_tuple(*it, typename particle_type::range_position_type{}));
i = 0;
meta::repeat(
[&i, &ref, &proxy](auto const& e) {
REQUIRE(ref.inputs(i) == e);
REQUIRE(proxy.inputs(i) == e);
++i;
},
meta::sub_tuple(*it, typename particle_type::range_inputs_type{}));
i = 0;
meta::repeat(
[&i, &ref, &proxy](auto const& e) {
REQUIRE(ref.outputs(i) == e);
REQUIRE(proxy.outputs(i) == e);
++i;
},
meta::sub_tuple(*it, typename particle_type::range_outputs_type{}));
meta::repeat(
[](auto const& e1, auto const& e2, auto const& e3) {
REQUIRE(e1 == e2);
REQUIRE(e1 == e3);
},
meta::sub_tuple(*it, typename particle_type::range_variables_type{}), ref.variables(), proxy.variables());
}
}
// Quick fold expression
template<typename... Args>
bool all(Args... args)
TEST_CASE("particle-proxy", "[particle-proxy]")
{
return (... && args);
using namespace scalfmm;
using proxy_type = container::particle<float&, 3, float&, 2, float&, 2, std::size_t&, std::size_t&>;
SECTION("particle-proxy", "[particle-proxy]")
{
container::particle_container<container::particle<float, 3, float, 2, float, 2, std::size_t, std::size_t>> c(1);
auto it = std::begin(c);
*it = std::make_tuple(1., 1., 1., 2., 2., 3., 3., 4, 4);
proxy_type proxy(*it);
std::size_t i{0};
meta::repeat(
[&i, &proxy](auto const& e) {
proxy.position(i) = 11.0;
REQUIRE(11.0 == e);
++i;