...
 
Commits (46)
......@@ -95,4 +95,4 @@ sonar:
- source ./Utils/scripts/analysis.sh
- sonar-scanner |tee sonar.log;
only:
- master@solverstack/ScalFMM
- develop@solverstack/ScalFMM
......@@ -4,3 +4,9 @@
[submodule "inastemp"]
path = inastemp
url = https://gitlab.inria.fr/coulaud/inastemp.git
[submodule "experimental/modules/morse_cmake"]
path = experimental/modules/morse_cmake
url = https://gitlab.inria.fr/solverstack/morse_cmake.git
[submodule "experimental/modules/xsimd"]
path = experimental/modules/xsimd
url = https://github.com/QuantStack/xsimd.git
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: Never
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 3
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 2
UseTab: Never
This diff is collapsed.
set(CPACK_PACKAGE_VERSION_PATCH 0)
execute_process(
COMMAND git rev-list HEAD --count
OUTPUT_VARIABLE CPACK_PACKAGE_VERSION_PATCH
RESULT_VARIABLE RET
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
)
#string_TRIM(PATCH1 PATCH)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY "ON")
#
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENCE")
set(CPACK_PACKAGE_VERSION_MAJOR "${${CMAKE_PROJECT_NAME}_MAJOR_VERSION}")
set(CPACK_PACKAGE_VERSION_MINOR "${${CMAKE_PROJECT_NAME}_MINOR_VERSION}")
#
set(PACK_PACKAGE_VERSION "${${CMAKE_PROJECT_NAME}_VERSION}.${${CMAKE_PROJECT_NAME}_MINOR_VERSION}-${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "SCALFMM-${${CMAKE_PROJECT_NAME}_MAJOR_VERSION}.${${CMAKE_PROJECT_NAME}_MINOR_VERSION}-${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_SOURCE_IGNORE_FILES "\\\\.git;.DS_Store;.*~;/*.aux;/*.idx;/*.log;/*.out;/*.toc;/*.ilg;CMakeLists.txt.user;/.settings/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/Utils/;/Build*;/Obsolete/")
#
## This file should be placed in the root directory of your project.
## Then modify the CMakeLists.txt file in the root directory of your
## project to incorporate the testing dashboard.
## # The following are required to uses Dart and the Cdash dashboard
## ENABLE_TESTING()
## INCLUDE(CTest)
set(CTEST_PROJECT_NAME "ScalFMM")
set(CTEST_NIGHTLY_START_TIME "00:00:00 GMT")
set(CTEST_SUBMIT_URL "http://cdash.inria.fr/CDash/submit.php?project=scalfmm")
#--------------------------------------------------------------------
# BUILDNAME variable construction
# This variable will be used to set the build name which will appear
# on the Chameleon dashboard http://cdash.inria.fr/CDash/
#--------------------------------------------------------------------
# Start with the short system name, e.g. "Linux", "FreeBSD" or "Windows"
if(NOT BUILDNAME)
set(BUILDNAME "${CMAKE_SYSTEM_NAME}")
# Add i386 or amd64
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BUILDNAME "${BUILDNAME}-amd64")
else()
set(BUILDNAME "${BUILDNAME}-i386")
endif()
# Add compiler name
get_filename_component(CMAKE_CXX_COMPILER_NAME ${CMAKE_CXX_COMPILER} NAME)
set(BUILDNAME "${BUILDNAME}-${CMAKE_CXX_COMPILER_NAME}")
# Add the build type, e.g. "Debug, Release..."
if(CMAKE_BUILD_TYPE)
set(BUILDNAME "${BUILDNAME}-${CMAKE_BUILD_TYPE}")
endif(CMAKE_BUILD_TYPE)
# Specific options of Scalfmm
if(SCALFMM_USE_SSE)
set(BUILDNAME "${BUILDNAME}-sse")
endif()
if(SCALFMM_USE_BLAS)
set(BUILDNAME "${BUILDNAME}-blas")
endif()
if(SCALFMM_USE_MPI)
set(BUILDNAME "${BUILDNAME}-mpi")
endif()
endif()
# Examples
#---------
# List of source files
set(source_tests_files
sandbox.cpp
test_tensorial_interpolator.cpp
test-blas.cpp
test-xtensor.cpp
)
# Add execs - 1 cpp = 1 exec
foreach(exec ${source_tests_files})
set(compile_exec TRUE)
get_filename_component( execname ${exec} NAME_WE )
foreach(fuse_key ${FUSE_DEP_AVAILABLE})
file(STRINGS "${exec}" lines_fuse REGEX "@FUSE_${fuse_key}")
if(lines_fuse AND NOT ${fuse_key} IN_LIST FUSE_LIST)
message( STATUS "This needs ${fuse_key} = ${exec}" )
set(compile_exec FALSE)
endif()
endforeach()
# Dependency are OK
if( compile_exec )
add_executable( ${execname} ${exec})
list(APPEND SCALFMM_EXAMPLES_TARGETS ${execname})
list(APPEND SCALFMM_TESTS_TARGETS ${execname})
set_target_properties(${execname}
PROPERTIES ENABLE_EXPORTS TRUE
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE}
)
target_compile_definitions(${execname} PUBLIC -DXTENSOR_USE_XSIMD)
target_link_libraries( ${execname} ${CMAKE_PROJECT_NAME})
# TODO: Remove these include derectories, ust temporary to reuse old components
target_include_directories( ${execname} PRIVATE ${CMAKE_SOURCE_DIR}/../include/)
target_include_directories( ${execname} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions( ${execname} PRIVATE BYPASS_CONFIG)
install(TARGETS ${execname} RUNTIME DESTINATION bin)
endif()
endforeach(exec)
add_custom_target(scalfmm_examples ALL DEPENDS ${SCALFMM_EXAMPLES_TARGETS})
#ifndef TRAP_SCALFMM_CONFIG_HPP
#define TRAP_SCALFMM_CONFIG_HPP
#include <scalfmm/config/scalfmm-config.hpp>
#endif
//---------------------
// Experimental example
//---------------------
#include <algorithm>
#include <iostream>
#include <random>
#include <tuple>
#include <vector>
#include <inria/tcli/help_descriptor.hpp>
#include <inria/tcli/tcli.hpp>
#include <range/v3/algorithm/for_each.hpp>
#include <range/v3/algorithm/generate.hpp>
#include <range/v3/algorithm/result_types.hpp>
#include <range/v3/algorithm/sort.hpp>
#include <range/v3/core.hpp>
#include <range/v3/functional/concepts.hpp>
#include <range/v3/iterator/concepts.hpp>
#include <range/v3/range/concepts.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/view/generate.hpp>
#include <xsimd/xsimd.hpp>
#include <xtensor/xtensor.hpp>
#include <scalfmm/container/particle.hpp>
#include <scalfmm/container/particle_container.hpp>
#include <scalfmm/container/point.hpp>
#include <scalfmm/functional/utils.hpp>
#include <scalfmm/interpolation/uniform.hpp>
#include <scalfmm/tools/colorized.hpp>
#include <scalfmm/tree/box.hpp>
#include <scalfmm/tree/tree.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 = {"--tree-height", "-th"};
const char *description =
"Tree height (or initial height in case of an adaptive tree).";
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 = std::size_t;
type def{1};
};
struct order : inria::tcli::required_tag {
inria::tcli::str_vec flags = {"--order", "-o"};
const char *description = "Precision order.";
using type = std::size_t;
};
struct file : inria::tcli::required_tag {
inria::tcli::str_vec flags = {"--input-file", "-fin"};
const char *description = "Input filename (.fma or .bfma).";
using type = std::string;
};
struct chunk_size {
inria::tcli::str_vec flags = {"--group-size", "-gs"};
const char *description = "Group tree chunk size.";
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{}, order{});
} // namespace args
/**
* \brief Store the PerfTest program parameters.
*/
struct params {
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
std::size_t m_order{}; ///< Group tree group size
params() = default;
params(const decltype(args::cli) &cli) {
m_order = cli.get<args::order>();
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;
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);
interpolation::uniform_interpolator<double, 3> unif_interpolator(
parameters.m_order, parameters.m_tree_height);
// variad<int,float> ot{{8,9},{1.3,2.6}};
// variad<int, float> copy{ot};
// std::cout << colors::blue << std::get<0>(copy)[0] << " " << colors::green
// << std::get<1>(copy)[0] << colors::reset << '\n';
// variad<int, float, double> v_{{1,2}, {3.3,4.4}, {5.5,6.6}};
// variad<int, float, double> v_(10);
// v_.push_back(std::make_tuple(2,1.1,2.2));
// std::cout << std::get<0>(v_).size() << '\n';
// std::cout << colors::blue << std::get<0>(v_)[0] << " " << colors::green <<
// std::get<1>(v_)[0] << " " << colors::yellow << std::get<2>(v_)[0] <<
// colors::reset << '\n';
// 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};
// 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);
//};
// std::vector<std::tuple<int,float>> v = {{8,3.0},{9,2.1},{10,9.6}};
// my_algorithm(cs.begin(), cs.end(), make_particle);
// std::generate(cs.begin(), cs.end(), make_particle);
// std::sort(cs.begin(), cs.end(), pred);
// std::for_each(cs.begin(), cs.end(), print_particle);
// component::tree t{};
return 0;
}
#include <algorithm>
#include <array>
#include <chrono>
#include <functional>
#include <iostream>
#include <random>
#include <tuple>
#include <utility>
#include <scalfmm/container/particle.hpp>
#include <scalfmm/container/particle_container.hpp>
#include <scalfmm/core/operators.hpp>
#include <scalfmm/interpolation/uniform.hpp>
#include <scalfmm/tools/colorized.hpp>
#include <scalfmm/tree/leaf.hpp>
int main()
{
using size_type = std::size_t;
namespace colors = scalfmm::colors;
constexpr size_type particle_dim{3};
// constexpr size_type potential_dim{3};
constexpr size_type order{6};
using particle_type = scalfmm::container::particle<double, particle_dim, double, double, double>;
// using tuple_type = std::tuple<double,double,double>;
using point_type = scalfmm::container::point<double, particle_dim>;
using container_type = scalfmm::container::particle_container<particle_type>;
using multipole_type = scalfmm::container::variadic_container<double, double, double>;
using leaf_type = scalfmm::component::leaf<particle_type, point_type>;
using interpolator_type = scalfmm::interpolation::uniform_interpolator<double, particle_dim>;
const size_type nb_particles{10000};
const size_type tree_height{5};
const double width{3.723};
container_type particles_source{nb_particles};
container_type particles_target{nb_particles};
std::mt19937 gen(33);
std::uniform_real_distribution<double> dis(-1.0, 1.0);
auto random_r = [&dis, &gen]() { return dis(gen); };
point_type center = {2. * width, 0., 0.};
auto make_particle = [&center, &width, &random_r]() {
point_type position = {random_r() * width, random_r() * width, random_r() * width};
position += center;
particle_type p(position, random_r(), random_r(), random_r());
return p.as_tuple();
};
std::generate(particles_source.begin(), particles_source.end(), make_particle);
auto start = std::chrono::high_resolution_clock::now();
interpolator_type s(order, tree_height);
auto end = std::chrono::high_resolution_clock::now();
std::cout << colors::green << "Interpolator construction time : "
<< std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us\n"
<< colors::reset;
// Construct leaf
leaf_type l(std::move(particles_source), center, width);
multipole_type multipoles(scalfmm::meta::pow(order, particle_dim), std::make_tuple(0., 0., 0.));
std::vector<std::chrono::microseconds> t;
for(std::size_t exp = 0; exp < 200; ++exp)
{
start = std::chrono::high_resolution_clock::now();
scalfmm::operators::apply_p2m(s, order, l, multipoles);
end = std::chrono::high_resolution_clock::now();
t.push_back(std::chrono::duration_cast<std::chrono::microseconds>(end - start));
if(exp == 0)
{
std::ofstream file("dump.txt");
auto it = std::begin(multipoles);
for(int i = 0; i < multipoles.size(); ++i)
{
file << std::fixed << std::setprecision(13) << std::get<0>(*it) << '\n';
it++;
}
it = std::begin(multipoles);
for(int i = 0; i < multipoles.size(); ++i)
{
file << std::fixed << std::setprecision(13) << std::get<1>(*it) << '\n';
it++;
}
it = std::begin(multipoles);
for(int i = 0; i < multipoles.size(); ++i)
{
file << std::fixed << std::setprecision(13) << std::get<2>(*it) << '\n';
it++;
}
file.close();
}
}
std::sort(t.begin(), t.end());
std::cout << colors::yellow << "p2m took... : " << t[t.size() / 2].count() << "us\n" << colors::reset;
return 0;
}
// --------------------------------
// See LICENCE file at project root
// File : concepts/library.hpp
// --------------------------------
#ifndef SCALFMM_CONCEPTS_LIBRARY_HPP
#define SCALFMM_CONCEPTS_LIBRARY_HPP
#include <type_traits>
namespace scalfmm::concepts
{
//template<typename R, typename Enabler>
//struct require_impl;
//template<typename R>
//struct require_impl<R, void>
//{
// using type = R;
//};
//template<typename Return, typename... Ts>
//struct require_check : require_impl<Return, std::void_t<Ts...>>
//{
//};
//template<typename From, typename To>
//using Convertible = std::enable_if_t<std::is_convertible_v<From, To>>;
//template<typename T>
//using Arithmetic = std::enable_if_t<std::is_arithmetic_v<T>>;
//template<typename T>
//using Integral = std::enable_if_t<std::is_integral_v<T>>;
//template<bool Condition>
//using If = std::enable_if_t<Condition>;
} // end namespace scalfmm::concepts
//// Pseudo require macro
//#define requires(...)->typename ::concept ::require_check < __VA_ARGS__> ::type
#endif // SCALFMM_CONCEPTS_LIBRARY_HPP
// See LICENCE file at project root
///
/// File generated by cmake
// Do not remove any line
///////////////////////////////////////////////////////
#ifndef SCALFMM_CONFIG_SCALFMM_CONFIG_HPP
#define SCALFMM_CONFIG_SCALFMM_CONFIG_HPP
// Uncomment the next line to use debug mode
#cmakedefine SCALFMM_USE_LOG
///////////////////////////////////////////////////////
// Blas
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_USE_BLAS
#cmakedefine SCALFMM_USE_MKL_AS_BLAS
// Fortran Mangling
#cmakedefine SCALFMM_BLAS_ADD_
#cmakedefine SCALFMM_BLAS_UPCASE
#cmakedefine SCALFMM_BLAS_NOCHANGE
////////////////////////////////////////////////////////
// FFT
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_USE_FFT
#cmakedefine SCALFMM_USE_MKL_AS_FFTW
#cmakedefine SCALFMM_USE_ESSL_AS_FFTW
//////////////////////////////////////////////////////
// MPI
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_USE_MPI
///////////////////////////////////////////////////////
// Memory trace
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_USE_MEM_STATS
///////////////////////////////////////////////////////
// CUDA
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_USE_CUDA
///////////////////////////////////////////////////////
// OPENCL
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_USE_OPENCL
///////////////////////////////////////////////////////
// STARPU
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_USE_STARPU
#cmakedefine SCALFMM_DISABLE_NATIVE_OMP4
///////////////////////////////////////////////////////
// To control starpu config
///////////////////////////////////////////////////////
#cmakedefine SCALFMM_STARPU_USE_COMMUTE
#cmakedefine SCALFMM_STARPU_USE_REDUX
#cmakedefine SCALFMM_STARPU_USE_PRIO
#cmakedefine SCALFMM_STARPU_FORCE_NO_SCHEDULER
#cmakedefine SCALFMM_USE_STARPU_EXTRACT
#endif // CONFIG_H
#ifndef SCALFMM_SPACE_CURVE_HPP_
#define SCALFMM_SPACE_CURVE_HPP_
#include "Utils/FPoint.hpp"
/** Provides the corner traversal order of an N dimension hypercube
*
* The positions returned are array of booleans. Each boolean tells where
* to place the element in the binary grid.
*
* For instance, in 2D:
*
*
* __0__ __1__
* | | |
* 0| | X | pos(X) = [true, false]
* |_____|_____|
* | | |
* 1| | Y | pos(Y) = [true, true ]
* |_____|_____|
*
*
* \tparam Dim The hypercube dimension.
*/
template<std::size_t _Dim>
class FZCurve {
public:
/// Space dimension count
constexpr static const std::size_t Dim = _Dim;
/// Position type used
using position_t = FPoint<bool, Dim>;
/// Position count in the grid
constexpr static std::size_t pos_count = Fpow(2,Dim);
private:
/// Array of positions type
using position_array_t = std::array<position_t, pos_count>;
/// Array to cache the positions corresponding to indexes
static const position_array_t _positions;
/** Creates an array of positions to initialize #_positions */
static position_array_t create_array() noexcept {
position_array_t positions;
for(std::size_t i = 0; i < pos_count; ++i) {
for(std::size_t j = Dim-1, k = i; k != 0; --j, k >>=1) {
positions[i][j] = k % 2;
}
}
return positions;
}
public:
/** The position corresponding to an index
*
* \param idx The index of the point in the space filling curve
* \return The position corresponding to the space filling curve index
*/
static position_t position(std::size_t idx) noexcept {
return _positions[idx];
}
/** Index in the space filling curve of a boolean position
*
* \param p The position
* \return The space filling curve index corresponding to the position
*/
static std::size_t index(const position_t& p) noexcept {
std::size_t idx = 0;
for(auto i : p) {
idx <<= 1;
idx += i;
}
return idx;
}
/** Index in the space filling curve of a real position relative to the center of the hypercube
*
* \param p The position
* \param center The center of the hypercube
* \return The space filling curve index corresponding to the position
*/
template<typename FReal>
static std::size_t index(const FPoint<FReal, Dim>& p, const FPoint<FReal, Dim>& center) noexcept {
std::size_t idx = 0;
for(std::size_t i = 0; i < Dim; ++i) {
idx <<= 1;
idx += p[i] > center[i];
}
return idx;
}
};
// Initialization of static variable
template<std::size_t _Dim>
const typename FZCurve<_Dim>::position_array_t FZCurve<_Dim>::_positions(FZCurve<_Dim>::create_array());
#endif
// --------------------------------
// See LICENCE file at project root
// File : particle.hpp
// --------------------------------
#ifndef SCALFMM_CONTAINER_PARTICLE_HPP
#define SCALFMM_CONTAINER_PARTICLE_HPP
#include <inria/integer_sequence.hpp>
#include <scalfmm/container/point.hpp>
#include <scalfmm/meta/type_pack.hpp>
/**
* \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::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
{
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,...(dimension times), Types...>
using tuple_data_t = scalfmm::meta::pack_expand_tuple<scalfmm::meta::pack<Dim, ValueType>, Types...>;
/// Expand Types list
using types_tuple_t = scalfmm::meta::pack_expand_tuple<Types...>;
/// Expand std::enable_if if possible
template<bool value>
using sfinae_check = typename std::enable_if<value, bool>::type;
/**
* \brief Check parameter pack size vs. attribute + dimension count at
* compile time
*
* \return true if the parameter pack is shorter than the attribute list
* size + the dimension
*/
template<typename... Ts>
constexpr static bool correct_attribute_list_size()
{
return std::tuple_size<tuple_data_t>::value >= sizeof...(Ts) + dimension;
}
/// Space dimensions
constexpr static std::size_t dimension = Dim;
/// Size of #tuple_data_t tuple
constexpr static std::size_t attributes_size = std::tuple_size<tuple_data_t>::value - dimension;
/// Floating point type
using value_type = ValueType;
/// Position type, required by the FVariadicParticleContainer
using position_type = point<value_type, dimension>;
/// Default constructor
particle() = default;
/// Default copy constructor
particle(const particle&) = default;
/// Default copy operator
particle& operator=(const particle&) = default;
/// Default move constructor
particle(particle&&) noexcept = default;
/// Default move operator
particle& operator=(particle&&) noexcept = default;
/**
* \brief Constructor from position and types
*
* \tparam Ts Attributes parameter pack; if Ts is too long, this will not
* compile.
*
* \param pos Particle position
* \param ts Attributes
*
* \warning There may be less attributes than defined by the particle, in
* that case the missing ones are zero constructed.
*/
template<typename... Ts, sfinae_check<correct_attribute_list_size<Ts...>()> = 0>
particle(const position_type& pos, Ts&&... ts)
: 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)...)
{
}
/// Constructor from tuple equivalent to #tuple_data_t
template<typename... Ts>
particle(const std::tuple<Ts...>& ts)
: tuple_data_t(ts)
{
}
/**
* \brief Position getter
*
* The position is stored in the #_data tuple, to extract it we need to
* recreate a position_type object. This is done by the position_impl() method.
*
* \return A new position_type object
*/
[[nodiscard]] position_type position() const { return position_impl(inria::make_index_sequence<dimension>()); }
/**
* \brief Position setter
*
* \parma pos The new position
*/
void set_position(const position_type& pos)
{
return set_position_impl(pos, inria::make_index_sequence<dimension>());
}
/**
* \brief Get a reference to the Ith attribute
*
* \tparam I Index of the attribute to get
*/
template<std::size_t I>
[[nodiscard]] auto attribute() -> decltype(std::get<dimension + I>(*this))
{
return std::get<dimension + I>(*this);
}
/**
* \brief Get a const reference to the Ith attribute
*
* \tparam I Index of the attribute to get
*/
template<std::size_t I>
[[nodiscard]] auto attribute() const -> decltype(std::get<dimension + I>(*this))
{
return std::get<dimension + I>(*this);
}
/**
* \brief Get a tuple filled with copies of the attributes
*/
[[nodiscard]] types_tuple_t attributes() const
{
return attributes_impl(inria::make_index_sequence<std::tuple_size<types_tuple_t>::value>());
}
/**
* \brief Convert particle to a tuple
*/
[[nodiscard]] tuple_data_t& as_tuple() { return *this; }
/**
* \brief Convert particle to a tuple
*/
[[nodiscard]] const tuple_data_t& as_tuple() const { return *this; }
~particle() = default;
private:
/**
* \brief Contructor implementation
*
* Builds the particle, zero constructing missing arguuments.
*/
template<typename... Ts, std::size_t... Is, std::size_t... Js>
particle(inria::index_sequence<Is...> is, inria::index_sequence<Js...> js, const position_type& pos, Ts&&... ts)
: tuple_data_t(pos[Is]..., std::forward<Ts>(ts)...,
typename std::tuple_element<dimension + Js + sizeof...(ts), tuple_data_t>::type(0)...)
{
// static_assert(sizeof...(Ts) == NbAttributes, "Parameter count is incorrect");
}
/**
* \brief #position method implementation
*
* \tparam Is Index sequence of the position elements in the tuple, deduced
* using arguments
*/
template<std::size_t... Is>
position_type position_impl(inria::index_sequence<Is...> is) const
{
return position_type(std::get<Is>(this->as_tuple())...);
}
/**
* \brief #setPosition method implementation
*
* \tparam Is Index sequence of the position elements in the tuple, deduced
* using arguments
*
* \param pos new position
*/
template<std::size_t... Is>
void set_position_impl(const position_type& pos, inria::index_sequence<Is...> is)
{
auto l = {std::get<Is>(this->as_tuple()) = pos[Is]...};
(void)l;
}
/**
* \brief #attributes method implementation
*
* \tparam Is Index sequence of the attributes in the tuple, deduced using
* arguments
*
* \param pos new position
*/
template<std::size_t... Is>
types_tuple_t attributes_impl(inria::index_sequence<Is...> is) const
{
return types_tuple_t(std::get<Is + dimension>(*this)...);
}
};
} // namespace scalfmm::container
#endif // SCALFMM_CONTAINER_PARTICLE_HPP
// --------------------------------
// See LICENCE file at project root
// File : container/particle_container.hpp
// --------------------------------
#ifndef SCALFMM_CONTAINER_PARTICLE_CONTAINER_HPP
#define SCALFMM_CONTAINER_PARTICLE_CONTAINER_HPP
#include <tuple>
#include <vector>
#include <xsimd/config/xsimd_align.hpp>
#include <scalfmm/container/variadic_container.hpp>
#include <scalfmm/memory/aligned_allocator.hpp>
#include <scalfmm/meta/traits.hpp>
namespace scalfmm::container
{
template<typename Particle>
class particle_container
: public variadic_container<typename Particle::tuple_data_t>
{
public:
// 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<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;
};
} // namespace scalfmm::container
#endif // SCALFMM_CONTAINER_PARTICLE_CONTAINER_HPP
This diff is collapsed.
// --------------------------------
// See LICENCE file at project root
// File : simple_variadic.cpp
// --------------------------------
#ifndef SCALFMM_CONTAINER_SIMPLE_VARIADIC_CONTAINER_HPP
#define SCALFMM_CONTAINER_SIMPLE_VARIADIC_CONTAINER_HPP
#include <vector>
#include <tuple>
#include <type_traits>
#include <utility>
#include <xsimd/config/xsimd_config.hpp>
namespace scalfmm::container
{
template<typename Types, typename Indices>
class variad_impl;
//template<typename Allocator = memory::aligned_allocator<XSIMD_DEFAULT_ALIGNMENT, Ts>>
template<typename... Ts, std::size_t... Indices>
class variad_impl<std::tuple<Ts...>, std::integer_sequence<std::size_t, Indices...>> : public std::tuple<std::vector<Ts, XSIMD_DEFAULT_ALLOCATOR(Ts)>...>
{
private:
//Discard fold expression results
struct noop_t
{
template<typename... Types>
noop_t(const Types&... ts) {}
};
public:
using base_type = std::tuple< std::vector<Ts, XSIMD_DEFAULT_ALLOCATOR(Ts)>... >;
using value_type = std::tuple< Ts... >;
using allocator_type = std::tuple<XSIMD_DEFAULT_ALLOCATOR(Ts)...>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = std::tuple<Ts&...>&;
using const_reference = const std::tuple<const Ts&...>&;
using pointer = std::tuple<Ts*...>;
using const_pointer = const std::tuple<const Ts*...>;
private:
allocator_type m_allocator{};
public:
variad_impl() = default;
variad_impl(const variad_impl&) = default;
variad_impl(variad_impl&&) noexcept = default;
variad_impl& operator=(const variad_impl&) = default;
variad_impl& operator=(variad_impl&&) noexcept = default;
~variad_impl() = default;
// TODO
//explicit variad( const allocator_type& alloc){}
explicit variad_impl( size_type count
, const value_type& value
, const allocator_type& alloc = allocator_type() )
: m_allocator(alloc)
{
reserve(count);
for(std::size_t i=0; i<count; ++i)
{
push_back(value);
}
}
explicit variad_impl(size_type count)
{
reserve(count);
for(std::size_t i=0; i<count; ++i)
{
push_back(value_type{});
}
}
inline void reserve(size_type size)
{
noop_t{(std::get<Indices>(*this).reserve(size),0) ...};
}
inline void push_back(const value_type& value)
{
noop_t{(std::get<Indices>(*this).push_back(std::get<Indices>(value)),0) ...};
}
};
template<typename... Ts>
struct variad : public variad_impl<std::tuple<Ts...>, std::make_index_sequence<sizeof...(Ts)>>
{
using base_type = variad_impl<std::tuple<Ts...>, std::make_index_sequence<sizeof...(Ts)>>;
using base_type::base_type;
};
}
#endif // SCALFMM_CONTAINER_SIMPLE_VARIADIC_CONTAINER_HPP
This diff is collapsed.
// --------------------------------
// See LICENCE file at project root
// File : core/operators.hpp
// --------------------------------
#ifndef SCALFMM_CORE_OPERATORS_HPP
#define SCALFMM_CORE_OPERATORS_HPP
#include <algorithm>
#include <fstream>
#include <string>
#include <tuple>
#include <utility>
#include <xsimd/xsimd.hpp>
#include <xtensor/xarray.hpp>
#include <scalfmm/container/point.hpp>
#include <scalfmm/interpolation/mapping.hpp>
#include <scalfmm/meta/utils.hpp>
#include <scalfmm/tools/colorized.hpp>
namespace scalfmm::simd
{
namespace impl
{
struct noop_f
{
template<typename... F>
noop_f(F... fs)
{
}
};
template<typename Position, typename TuplePtr, std::size_t... Is>
constexpr inline auto load_position(TuplePtr const& particle_ptrs, std::index_sequence<Is...> s)
{
return Position{xsimd::load_aligned(std::get<Is>(particle_ptrs))...};
}
template<typename Position, typename TuplePtr, std::size_t... Is>
constexpr inline void store_position(TuplePtr const& particle_ptrs, Position const& src,
std::index_sequence<Is...> s)
{
noop_f{(xsimd::store_aligned(std::get<Is>(particle_ptrs), std::get<Is>(src)), 0)...};
}
template<typename Particle, typename TuplePtr, std::size_t... Is>
constexpr inline auto load_attributes(TuplePtr const& particle_ptrs, std::index_sequence<Is...> s)
{
return std::make_tuple(xsimd::load_aligned(std::get<Particle::dimension + Is>(particle_ptrs))...);
}
template<typename TupleAttributes, typename TuplePtr, std::size_t... Is>
constexpr inline void store_attributes(TuplePtr const& attributes_ptrs, TupleAttributes const& src,
std::index_sequence<Is...> s)
{
noop_f{(xsimd::store_aligned(std::get<Is>(attributes_ptrs), std::get<Is>(src)), 0)...};
}
template<typename F, typename Container, typename... Types, std::size_t... Is>
constexpr inline auto apply_f(std::index_sequence<Is...> s, F&& f, Container&& input, Types&&... ts)
{
using return_type = typename std::remove_reference<Container>::type;
return return_type{{f(std::get<Is>(std::forward<Container>(input)), std::forward<Types>(ts)...)...}};
}
} // namespace impl
template<typename Position, typename TuplePtr>
constexpr inline auto load_position(TuplePtr const& particle_ptrs)
{
return impl::load_position<Position>(particle_ptrs, std::make_index_sequence<Position::dimension>{});
}
template<typename Particle, typename TuplePtr>
constexpr inline auto load_attributes(TuplePtr const& particle_ptrs)
{
return impl::load_attributes<Particle>(particle_ptrs, std::make_index_sequence<Particle::attributes_size>{});
}
template<typename Position, typename TuplePtr>
constexpr inline void store_position(TuplePtr& particle_ptrs, Position const& src)
{
impl::store_position(particle_ptrs, src, std::make_index_sequence<Position::dimension>{});
}
template<typename TupleAttributes, typename TuplePtr>
constexpr inline void store_attributes(TuplePtr& attributes_ptrs, TupleAttributes const& src)
{
impl::store_attributes(attributes_ptrs, src,
std::make_index_sequence<std::tuple_size<TupleAttributes>::value>{});
}
template<std::size_t Size, typename F, typename Container, typename... Types>
constexpr inline auto apply_f(F&& f, Container&& input, Types&&... ts)
{
return impl::apply_f(std::make_index_sequence<Size>{}, std::forward<F>(f), std::forward<Container>(input),
std::forward<Types>(ts)...);
}
} // namespace scalfmm::simd
namespace scalfmm::utils
{
namespace impl
{
template<typename Container, std::size_t... ISs>
constexpr inline auto generate_s(std::index_sequence<ISs...> s, Container const& cont,
std::array<std::size_t, sizeof...(ISs)> const& index)
{
return meta::multiply(std::get<ISs>(cont[index[ISs]])...);
}
template<typename T, typename U, std::size_t... Is>
inline constexpr auto tuple_update(T&& lhs, U&& rhs, std::index_sequence<Is...> s)
{
simd::impl::noop_f{((std::get<Is>(std::forward<T>(lhs)) += std::get<Is>(std::forward<U>(rhs))), 0)...};
}
} // namespace impl
template<std::size_t N, typename Container>
constexpr inline auto generate_s(Container const& cont, std::array<std::size_t, N> const& index)
{
return impl::generate_s(std::make_index_sequence<N>{}, cont, index);
}
template<typename T, typename U>
inline constexpr void tuple_update(T&& lhs, U&& rhs)
{
return impl::tuple_update(std::forward<T>(lhs), std::forward<U>(rhs),
std::make_index_sequence<std::tuple_size<T>::value>{});
}
} // namespace scalfmm::utils
namespace scalfmm::operators
{
template<typename Interpolator, typename Leaf, typename Multipoles>
inline void apply_p2m(Interpolator const& interp, std::size_t order, Leaf const& leaf, Multipoles& expansion)
{
using leaf_type = Leaf;
using particle_type = typename leaf_type::particle_type;
using position_type = typename leaf_type::position_type;
using value_type = typename Leaf::value_type;
using simd_type = xsimd::simd_type<value_type>;
using simd_position_type = container::point<simd_type>;
using simd_potentials_type = container::point<simd_type>;
using polynomials_f_type = typename Interpolator::template polynomials_f_type<simd_type>;
const std::size_t inc = simd_type::size;
const std::size_t leaf_size = leaf.size();
// Vectorizable particles
const std::size_t vec_size = leaf_size - leaf_size % inc;
const interpolation::map_glob_loc<simd_position_type> mapping_part_position(
leaf.center(), simd_position_type(simd_type(leaf.width())));
auto particle_iterator = leaf.begin();
constexpr std::size_t potential_size{particle_type::attributes_size};
std::size_t nnodes = meta::pow(order, position_type::dimension);
std::vector<simd_position_type> poly_of_part(order);
std::vector<value_type, XSIMD_DEFAULT_ALLOCATOR(value_type)> S(nnodes * inc);
for(std::size_t part = 0; part < vec_size; part += inc)
{
simd_position_type part_position(simd::load_position<simd_position_type>(particle_iterator));
simd_position_type local_position{};
mapping_part_position(part_position, local_position);
for(std::size_t o = 0; o < order; ++o)
{
polynomials_f_type polynomials{};
poly_of_part[o] = simd::apply_f<simd_position_type::dimension>(polynomials, local_position, order, o);
}
// Assembling S
std::size_t idx = 0;
auto construct_s = [&part, &S, &poly_of_part, &idx, inc](auto&... current_indices) {
auto s_simd = utils::generate_s<position_type::dimension>(poly_of_part, {{current_indices...}});
xsimd::store_aligned(&S[idx], s_simd);
idx += inc;
};
std::array<std::size_t, position_type::dimension> stops;
stops.fill(order);
meta::looper<position_type::dimension>()(construct_s, stops);
std::size_t vec_idx = 0;
auto simd_potentials = simd::load_attributes<particle_type>(particle_iterator);
auto multipoles_iterator = expansion.begin();
for(std::size_t m = 0; m < expansion.size(); ++m)
{
auto s_to_apply = xsimd::load_aligned(&S[vec_idx]);
auto update_potential = [&s_to_apply](auto... pot) { return std::make_tuple(s_to_apply * pot...); };