Commit c3250587 authored by ESTERIE Pierre's avatar ESTERIE Pierre

Some more work on basic components

parent 94e18098
......@@ -149,6 +149,15 @@ if(MORSE_DISTRIB_DIR OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/morse_cmake"
$<INSTALL_INTERFACE:include>
)
#
# Module rangev3
# ------------
target_include_directories(${CMAKE_PROJECT_NAME} INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/modules/rangev3>
$<INSTALL_INTERFACE:include>
)
#
# Specific Debug flags
# --------------------
......@@ -464,7 +473,7 @@ if(MORSE_DISTRIB_DIR OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modules/morse_cmake"
if(SCALFMM_USE_STATIC_ANALYSIS AND SCALFMM_USE_CLANGTIDY)
find_program(CLANGTIDY "clang-tidy")
if (CLANGTIDY)
if(CLANGTIDY)
set(CMAKE_CXX_CLANG_TIDY "${CLANGTIDY};-checks=-*,boost-*,cppcoreguidelines-*,clang-analyser-cplusplus*,modernize-*,mpi-*,performance-*,portability-*,readability-*")
message(STATUS "Clang Tidy analysis is ON.")
endif()
......
//---------------------
// Experimental example
//---------------------
#include <iosfwd>
#include <string>
#include <vector>
#include <iostream>
#include <tuple>
#include <random>
#include <inria/tcli/help_descriptor.hpp>
#include <inria/tcli/tcli.hpp>
#include <range/v3/core.hpp>
#include <range/v3/algorithm/generate.hpp>
#include <range/v3/algorithm/for_each.hpp>
#include <range/v3/algorithm/sort.hpp>
#include <range/v3/view/generate.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/algorithm/result_types.hpp>
#include <range/v3/functional/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <scalfmm/container/particle_container.hpp>
#include <scalfmm/container/point.hpp>
#include <scalfmm/container/particle.hpp>
#include <scalfmm/tree/tree.hpp>
#include <Files/FFmaGenericLoader.hpp>
#include <scalfmm/tree/box.hpp>
#include <scalfmm/functional/utils.hpp>
#include <scalfmm/tools/colorized.hpp>
namespace args
{
struct nb_particle : inria::tcli::required_tag
{
inria::tcli::str_vec flags = {"--n-particles", "-nbp"};
const char* description = "Number of particles to generate.";
using type = std::size_t;
};
struct tree_height : inria::tcli::required_tag
{
inria::tcli::str_vec flags = {"--height", "-H"};
inria::tcli::str_vec flags = {"--tree-height", "-th"};
const char* description = "Tree height (or initial height in case of an adaptive tree).";
using type = int;
using type = std::size_t;
};
struct thread_count : inria::tcli::required_tag
{
inria::tcli::str_vec flags = {"--threads", "-t"};
const char* description = "Maximum thread count to be used.";
using type = int;
using type = std::size_t;
type def{1};
};
......@@ -42,13 +63,14 @@ namespace args
struct chunk_size
{
inria::tcli::str_vec flags = {"--group-size"};
inria::tcli::str_vec flags = {"--group-size", "-gs"};
const char* description = "Group tree chunk size.";
using type = int;
using type = std::size_t;
type def{250};
};
auto cli = inria::tcli::make_parser(
nb_particle{},
tree_height{}, thread_count{},
file{}, inria::tcli::help{},
chunk_size{}
......@@ -59,39 +81,90 @@ namespace args
* \brief Store the PerfTest program parameters.
*/
struct params {
int _tree_height{}; ///< Tree height.
int _nb_threads{}; ///< Maximum thread count (when used).
std::string _filename{}; ///< Particles file.
int _group_size{}; ///< Group tree group size
std::size_t m_nb_particle{}; ///< Tree height.
std::size_t m_tree_height{}; ///< Tree height.
std::size_t m_nb_threads{}; ///< Maximum thread count (when used).
std::string m_filename{}; ///< Particles file.
std::size_t m_group_size{}; ///< Group tree group size
params() = default;
params(const decltype(args::cli)& cli)
{
_tree_height = cli.get<args::tree_height>();
_nb_threads = cli.get<args::thread_count>();
_filename = cli.get<args::file>();
_group_size = cli.get<args::chunk_size>();
m_nb_particle = cli.get<args::nb_particle>();
m_tree_height = cli.get<args::tree_height>();
m_nb_threads = cli.get<args::thread_count>();
m_filename = cli.get<args::file>();
m_group_size = cli.get<args::chunk_size>();
}
};
using namespace scalfmm;
struct curve {};
//CPP_template(class Iter, class Sent, class Fun)
// (requires /* ranges::Invocable<Fun&> && ranges::OutputIterator<Iter,ranges::invoke_result_t<Fun&>> && ranges::Sentinel<Sent, Iter>*/
// ranges::Writable<Iter,ranges::invoke_result_t<Fun&>> )
//void my_algorithm(Iter first, Sent last, Fun f)
//{
// // ...
//}
// Quick type displayer
template<typename T>
class TD;
int main(int argc, char** argv)
{
args::cli.parse(argc,argv);
params parameters(args::cli);
using source_t = container::particle<double,3,float>;
using target_t = container::point<double,3>;
using container_source_t = container::particle_container<source_t, curve>;
using container_target_t = container::particle_container<target_t, curve>;
const std::size_t tree_height{parameters.m_tree_height};
using source_t = container::particle<double,3,double,std::size_t>;
using position_t = container::point<double,3>;
using container_source_t = container::particle_container<source_t>;
const std::size_t nb_of_part{parameters.m_nb_particle};
//FFmaGenericLoader<particle_value_t> loader(parameters._filename);
container_source_t cs{nb_of_part};
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(-1.0, 1.0);
auto random_r = [&dis, &gen](){ return dis(gen); };
auto make_particle = [&tree_height, &random_r]()
{
position_t pos = {random_r(), random_r(), random_r()};
source_t part( pos
, random_r()
, index::get_morton_index(pos, component::box<position_t>{2.0, {0.0,0.0,0.0}}, tree_height)
);
return part.as_tuple();
};
auto print_particle = [](source_t p)
{
std::cout << colors::yellow << "=================" << colors::reset << '\n';
std::cout << "x = " << std::get<0>(p) << '\n';
std::cout << "y = " << std::get<1>(p) << '\n';
std::cout << "z = " << std::get<2>(p) << '\n';
std::cout << "p = " << std::get<3>(p) << '\n';
std::cout << "x.p = " << p.position()[0] << '\n';
std::cout << "norm2 = " << utils::norm2(p.position()) << '\n';
std::cout << "morton = " << std::get<4>(p) << '\n';
};
auto pred = [](auto a, auto b)
{
return std::get<4>(a) < std::get<4>(b);
};
ranges::generate(cs.begin(), cs.end(), make_particle);
ranges::sort(cs.begin(), cs.end(), pred);
ranges::for_each(cs.begin(), cs.end(), print_particle);
return 0;
}
......
......@@ -27,10 +27,10 @@
*
* ```
* using FReal = double;
* static constexpr std::size_t Dim = 3;
* static constexpr std::size_t dimension = 3;
*
* particle<FReal, Dim, int, float, float, float, float>;
* particle<FReal, Dim, int, scalfmm::pack<4, float> >;
* particle<FReal, dimension, int, float, float, float, float>;
* particle<FReal, dimension, int, scalfmm::pack<4, float> >;
* ```
*
* The base of these two classes is
......@@ -53,20 +53,20 @@
*
*
* \tparam FReal Floating point type
* \tparam Dim Space dimension count
* \tparam dimension Space dimension count
* \tparam Types Attributes type list
*
*/
namespace scalfmm::container
{
template<typename ValueType, std::size_t _Dim = 3, typename... Types>
class particle : public scalfmm::meta::pack_expand_tuple< scalfmm::meta::pack<_Dim, ValueType>, Types... >
template<typename ValueType, std::size_t Dim = 3, typename... Types>
class particle : public scalfmm::meta::pack_expand_tuple< scalfmm::meta::pack<Dim, ValueType>, Types... >
{
public:
/// Storage class : std::tuple<FReal,...(Dim times), Types...>
/// Storage class : std::tuple<FReal,...(dimension times), Types...>
using tuple_data_t = scalfmm::meta::
pack_expand_tuple< scalfmm::meta::pack<_Dim, ValueType>, Types... >;
pack_expand_tuple< scalfmm::meta::pack<Dim, ValueType>, Types... >;
/// Expand Types list
using types_tuple_t = scalfmm::meta::
......@@ -86,18 +86,18 @@ namespace scalfmm::container
template<typename... Ts>
constexpr static bool correct_attribute_list_size()
{
return std::tuple_size<tuple_data_t>::value >= sizeof...(Ts) + Dim;
return std::tuple_size<tuple_data_t>::value >= sizeof...(Ts) + dimension;
}
/// Space dimensions
constexpr static std::size_t Dim = _Dim;
constexpr static std::size_t dimension = Dim;
/// Size of #tuple_data_t tuple
constexpr static std::size_t NbAttributes = std::tuple_size<tuple_data_t>::value - Dim;
constexpr static std::size_t NbAttributes = std::tuple_size<tuple_data_t>::value - dimension;
/// Floating point type
using value_type = ValueType;
/// Position type, required by the FVariadicParticleContainer
using position_t = point<value_type, Dim>;
using position_t = point<value_type, dimension>;
/// Default constructor
particle() = default;
......@@ -124,8 +124,8 @@ namespace scalfmm::container
*/
template<typename... Ts, sfinae_check<correct_attribute_list_size<Ts...>()> = 0>
particle(const position_t& pos, Ts&&... ts)
: particle(inria::make_index_sequence<Dim>(),
inria::make_index_sequence<std::tuple_size<tuple_data_t>::value-sizeof...(ts)-Dim>(),
: particle(inria::make_index_sequence<dimension>(),
inria::make_index_sequence<std::tuple_size<tuple_data_t>::value-sizeof...(ts)-dimension>(),
pos,
std::forward<Ts>(ts)...
)
......@@ -147,7 +147,7 @@ namespace scalfmm::container
*/
position_t position() const
{
return position_impl(inria::make_index_sequence<Dim>());
return position_impl(inria::make_index_sequence<dimension>());
}
/**
......@@ -157,7 +157,7 @@ namespace scalfmm::container
*/
void set_position(const position_t& pos)
{
return set_position_impl(pos, inria::make_index_sequence<Dim>());
return set_position_impl(pos, inria::make_index_sequence<dimension>());
}
/**
......@@ -166,9 +166,9 @@ namespace scalfmm::container
* \tparam I Index of the attribute to get
*/
template<std::size_t I>
auto attribute() -> decltype(std::get<Dim+I>(*this))
auto attribute() -> decltype(std::get<dimension+I>(*this))
{
return std::get<Dim+I>(*this);
return std::get<dimension+I>(*this);
}
/**
......@@ -177,9 +177,9 @@ namespace scalfmm::container
* \tparam I Index of the attribute to get
*/
template<std::size_t I>
auto attribute() const -> decltype(std::get<Dim+I>(*this))
auto attribute() const -> decltype(std::get<dimension+I>(*this))
{
return std::get<Dim+I>(*this);
return std::get<dimension+I>(*this);
}
/**
......@@ -218,7 +218,7 @@ namespace scalfmm::container
particle(inria::index_sequence<Is...>, inria::index_sequence<Js...>,
const position_t& pos, Ts&&... ts)
: tuple_data_t(pos[Is]..., std::forward<Ts>(ts)...,
typename std::tuple_element<Dim+Js+sizeof...(ts), tuple_data_t>::type(0)...)
typename std::tuple_element<dimension+Js+sizeof...(ts), tuple_data_t>::type(0)...)
{
//static_assert(sizeof...(Ts) == NbAttributes, "Parameter count is incorrect");
}
......@@ -262,7 +262,7 @@ namespace scalfmm::container
template<std::size_t... Is>
types_tuple_t attributes_impl(inria::index_sequence<Is...>) const
{
return types_tuple_t(std::get<Is+Dim>(*this)...);
return types_tuple_t(std::get<Is+dimension>(*this)...);
}
};
......
......@@ -16,34 +16,34 @@
namespace scalfmm::container
{
template<typename Particle, typename SpaceCurve>
template<typename Particle>
class particle_container
: public variadic_container< memory::aligned_allocator<XSIMD_DEFAULT_ALIGNMENT
, typename meta::tuple_cat< typename Particle::tuple_data_t
, std::tuple<std::size_t>>::type
>
>
: public variadic_container
< memory::aligned_allocator< XSIMD_DEFAULT_ALIGNMENT
, typename Particle::tuple_data_t
>
, typename Particle::tuple_data_t
>
{
public:
//using tuple_t = decltype(std::tuple_cat(Particle{}.as_tuple(),std::make_tuple(std::size_t{})));
using particle_t = Particle;
using space_curve_t = SpaceCurve;
//using allocator_t = Allocator;
particle_container() = default;
particle_container(const particle_container& other) = default;
particle_container(particle_container&& other) = default;
particle_container& operator=(const particle_container& other) = default;
particle_container& operator=(particle_container&& other) = default;
//explicit particle_container()
//{
//}
private:
space_curve_t m_curve{};
//variadic_container<allocator_t, tuple_t> m_inner_container{};
// base type : concatenating the particle tuple with the indexes needed
// in order to allocate the vector
using value_type = typename Particle::tuple_data_t;
using allocator_type = typename memory::aligned_allocator< XSIMD_DEFAULT_ALIGNMENT, value_type>;
using base_type = variadic_container< allocator_type, value_type>;
using size_type = typename base_type::size_type;
using difference_type = typename base_type::difference_type;
using reference = typename base_type::reference_tuple;
using const_reference = typename base_type::const_reference_tuple;
using pointer = typename base_type::pointer_tuple;
using const_pointer = typename base_type::const_pointer_tuple;
using iterator = typename base_type::iterator;
using const_iterator = typename base_type::const_iterator;
using particle_type = Particle;
//Forwardind constructors
using base_type::base_type;
};
}
......
......@@ -211,6 +211,8 @@ namespace scalfmm::container
// No initializer list constructor
variadic_container_impl(std::initializer_list<value_type>) = delete;
protected:
~variadic_container_impl() {
this->clear();
if(nullptr != std::get<0>(this->data())) {
......@@ -218,6 +220,7 @@ namespace scalfmm::container
}
}
public:
/** \brief Assignment operator
*
* \param other Container to copy
......@@ -1295,10 +1298,6 @@ namespace scalfmm::container
};
template<typename... Types, std::size_t... Indices>
class variadic_container_iterator<std::tuple<Types...>, inria::index_sequence<Indices...> >
: public std::tuple<Types*...> {
......@@ -1316,7 +1315,6 @@ class variadic_container_iterator<std::tuple<Types...>, inria::index_sequence<In
using base_seq = inria::index_sequence<Indices...> ;
using pointer_tuple = std::tuple<Types*...>;
#ifdef __INTEL_COMPILER
using std::tuple<Types*...>::tuple;
#else
......@@ -1459,7 +1457,7 @@ class variadic_container_iterator<std::tuple<Types...>, inria::index_sequence<In
*
* \return A tuple of references to the values of the pointer element
*/
reference operator*() {
auto operator*() {
return reference(*std::get<Indices>(*this)...);
}
......
// See LICENCE file at project root
//
#ifndef SCALFMM_FUNCTIONAL_UTILS_HPP
#define SCALFMM_FUNCTIONAL_UTILC_HPP
#include <cmath>
#include <scalfmm/meta/traits.hpp>
namespace scalfmm::utils
{
// Norm2 on a range
template<typename T>
inline auto norm2(const T& range)
-> std::enable_if_t< meta::has_value_type<T>::value
&& meta::has_range_interface<T>::value
, typename T::value_type>
{
typename T::value_type square_sum{0};
for (auto a : range)
{
square_sum += a*a;
}
return square_sum;
}
//Norm
template<typename T>
inline auto norm(const T& range)
-> std::enable_if_t< meta::has_value_type<T>::value
&& meta::has_range_interface<T>::value
, typename T::value_type>
{ return std::sqrt(norm2(range)); }
}
#endif // SCALFMM_FUNCTIONAL_UTILC_HPP
......@@ -51,6 +51,13 @@ namespace scalfmm::meta
struct tuple_cat
{ using type = decltype(std::tuple_cat(T{},U{})); };
template<typename, typename = std::void_t<>>
struct has_value_type : std::false_type{};
template<typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type{};
} // namespace scalfmm::meta
#endif
// == file : progress_bar.hpp
// == author : Pierre Esterie
#ifndef TIMIT_UTILS_PROGRESS_BAR_HPP
#define TIMIT_UTILS_PROGRESS_BAR_HPP
#ifndef SCALFMM_TOOLS_PROGRESS_BAR_HPP
#define SCALFMM_TOOLS_PROGRESS_BAR_HPP
#include <sstream>
#include <memory>
#include <thread>
#include <iostream>
#include <scalfmm/tools/colorized.hpp>
namespace timit { namespace utils
namespace scalfmm::tools
{
template<typename Object>
int progress(Object& obj);
......@@ -26,10 +25,10 @@ namespace timit { namespace utils
sstr.str("");
sstr.clear();
sstr.precision(4);
int p = timit::utils::progress(obj);
int p = progress(obj);
std::cout << p << std::endl;
sstr << "[";
for(int i = 0; i < 100; ++i)
for(int i = 0; i < 100; ++i)
{
sstr << (i < p ? "\u2038" : " ");
}
......@@ -45,6 +44,6 @@ namespace timit { namespace utils
this->t.join();
}
};
}}
}
#endif
// See LICENCE file at project root
// File : box.hpp
// --------------------------------
#ifndef SCALFMM_TREE_BOX_HPP
#define SCALFMM_TREE_BOX_HPP
#include <ostream>
#include <cmath>
#include <scalfmm/tree/morton_curve.hpp>
/* Implements a N dimensions box
*
* \author Quentin Khan <quentin.khan@inria.fr>
*
* The box is described by two opposite corners : the maximum and
* the minimum one. All the class transformations maintain this
* predicate.
*
* \tparam value_type Floating number representation.
* \tparam dimension Space dimension count.
* \tparam SpaceFillingCurve A templatize implementation of a space filling curve
*
*/
namespace scalfmm::component
{
template<class Position, template<std::size_t> class SpaceFillingCurve = z_curve>
class box {
public:
/// Position type
using position_type = Position;
/// Floating number representation
using value_type = typename position_type::value_type;
/// Space dimension
constexpr static const std::size_t dimension = position_type::dimension;
/// Space filling curve type
using space_filling_curve_t = SpaceFillingCurve<dimension>;
private:
position_type _c1; ///< Minimum corner
position_type _c2; ///< Maximum corner
position_type _center; ///< Center
/** Rearranges the corners to ensure the maximum-minimum predicate */
void rearrange_corners () {
for(std::size_t i = 0; i < dimension; ++i){
if(_c1[i] > _c2[i]) {
std::swap(_c1[i], _c2[i]);
}
}
_center = (_c1 + _c2) / 2;
}
public:
/// Accessor for the minimum corner
const position_type& c1() const noexcept {
return _c1;
}
/// Accessor for the maximum corner
const position_type& c2() const noexcept {
return _c2;
}
/** Builds an empty box at the origin */
box() = default;
/** Copies an existing box */
box(const box&) = default;
/** Copies an other box */
box& operator=(const box& other) = default;
/** Builds a cube from the lower corner and its side length
*
* \param min_corner The lowest corner
* \param side_length The cube's side length
**/
[[gnu::deprecated]] box(const position_type& min_corner, value_type side_length) :
_c1(min_corner),
_c2(min_corner)
{
if(side_length < 0) {
side_length = - side_length;
}
for(auto&& d : _c2) {
d += side_length;
}
_center = (_c1 + _c2) / 2;
}
/** Builds a cube using its center and width
*
* \param width Cube width
* \param box_center Cube center
* \param unused Disambiguisation param from lower corner constructor
*/
box(value_type width, const position_type& box_center)
: _c1(box_center),
_c2(box_center),
_center(box_center)
{
if(width < 0) {
width = - width;
}
value_type radius = width / 2;
for(auto&& d : _c1) {
d -= radius;
}
for(auto&& d : _c2) {
d += radius;
}
}
/** Builds a box from two corners
*
* The maximum and minimum corners are deduced from the given corners.
*
* \param corner_1 The first corner.
* \param corner_2 The second corner.
*/
box(const position_type& corner_1, const position_type& corner_2) : _c1(corner_1), _c2(corner_2) {
rearrange_corners();
}
/** Changes the box corners
*
* The maximum and minimum corners are deduced from the given corners.
*
* \param corner_1 The first corner.
* \param corner_2 The second corner.
*/
void set(const position_type& corner_1, const position_type& corner_2) {
_c1 = corner_1;
_c2 = corner_2;
rearrange_corners();
}
/** Checks whether a position is within the box bounds
*
* \param p The position to check.
*/
bool contains(const position_type& p) const {
for(std::size_t i = 0; i < dimension; i++) {
if(p[i] < _c1[i] || p[i] > _c2[i]) {
return false;
}
}
return true;
}
/** Checks whether an object's position is within the box bounds
*
* The object must implement a `position_type position() const;` method.
*
* \tparam T The object type.
* \param obj The object which position to check.
*/
template<class T>
bool contains(const T& obj) const {
return contains(obj.position());
}
/** Accessor for the box center */
const position_type& center() const {
return _center;
}
/** Accessor for the box corners
*
* The corners are numbered using a space filling curve.
*