Commit 38de838e authored by COULAUD Olivier's avatar COULAUD Olivier

Mv files in ScalFMM-Tools project

parent 8067ae8b
This diff is collapsed.
// ==== CMAKE =====
// @FUSE_BLAS
// ================
// Keep in private GIT
// @FUSE_MPI
#include "../../Src/Utils/FGlobal.hpp"
// include algo for linear tree
#include "inria/algorithm/distributed/mpi.hpp"
#include "inria/linear_tree/balance_tree.hpp"
// tree class
#include "../../Src/GroupTree/Core/FGroupTree.hpp"
// symbolic data
#include "../../Src/Components/FSymbolicData.hpp"
// cell class
#include "../../Src/Kernels/Chebyshev/FChebCell.hpp"
// parameter
#include "../../Src/Utils/FParameters.hpp"
#include "../../Src/Utils/FParameterNames.hpp"
// GroupParticleContianer
#include "../../Src/GroupTree/Core/FP2PGroupParticleContainer.hpp"
// file loader
#include "../../Src/Files/FMpiFmaGenericLoader.hpp"
// FBox
#include "Adaptive/FBox.hpp"
// Group linear tree
#include "../../Src/GroupTree/Core/FGroupLinearTree.hpp"
// Function for GroupLinearTree
#include "../../Src/GroupTree/Core/FDistributedGroupTreeBuilder.hpp"
#include <memory>
static const int ORDER = 6;
using FReal = double;
using GroupCellClass = FChebCell<FReal, ORDER>;
using GroupCellUpClass = typename GroupCellClass::multipole_t;
using GroupCellDownClass = typename GroupCellClass::local_expansion_t;
using GroupCellSymbClass = FSymbolicData;
using GroupContainerClass = FP2PGroupParticleContainer<FReal>;
using GroupOctreeClass = FGroupTree<FReal,
GroupCellSymbClass,
GroupCellUpClass,
GroupCellDownClass, GroupContainerClass, 1, 4, FReal>;
// Structure for 1 particle
struct particle_t {
using position_t = FPoint<FReal>;
position_t pos;
FReal phi;
MortonIndex morton_index;
const auto& position() const {
return pos;
}
const FPoint<FReal>& getPosition(){
return pos;
}
const auto& physicalValue() const{
return phi;
}
const auto& getPositions() const {
return pos;
}
int weight() const { return 1;}
friend constexpr auto morton_index(const particle_t& p) {
return p.morton_index;
}
};
int main(int argc, char *argv[]) {
// Parameter definition
const FParameterNames LocalOptionBlocSize { {"-bs"}, "The size of the block of the blocked tree"};
// Parameter help
FHelpDescribeAndExit(argc, argv,
"Test the blocked tree created with linear tree." ,FParameterDefinitions::OctreeHeight,
FParameterDefinitions::InputFile,
LocalOptionBlocSize);
// Get parameters
// Get the groupSize
const int groupSize =
FParameters::getValue(argc,argv,LocalOptionBlocSize.options, 250);
// Get the file input
const char* const filename =
FParameters::getStr(argc,argv,FParameterDefinitions::InputFile.options, "../Data/test20k.fma");
// Get the treeHeight
const unsigned int TreeHeight =
FParameters::getValue(argc, argv, FParameterDefinitions::OctreeHeight.options, 5);
// The level is the level of the leaf
int level = TreeHeight-1;
// Init MPI communicator
// Initialisation MPI Berenger
FMpi FMpiComm(argc,argv);
// Initialisation MPI Quentin
inria::mpi::communicator mpi_comm(FMpiComm.global().getComm());
// Show job information
std::cout << "JOB INFORMATION " << std::endl;
std::cout << "File name : " << filename << std::endl;
std::cout << "TreeHeight : " << TreeHeight << std::endl;
std::cout << "Block size : " << groupSize << std::endl;
std::cout << "------------------------------------------" << std::endl;
std::cout << "Opening : " << filename << " ...";
FMpiFmaGenericLoader<FReal> loader(filename, FMpiComm.global());
std::cout << " done." << std::endl;
// vector to stock all particles
std::vector<particle_t> myParticles(loader.getMyNumberOfParticles());
// define the max level to sort particle
const std::size_t max_level = sizeof(particle_t::morton_index) * 8 / 3;
// define a box, used in the sort
const FBox<FPoint<FReal>> box{loader.getBoxWidth(),loader.getCenterOfBox()};
// iterate on all of my particles
for(FSize idxPart = 0; idxPart <loader.getMyNumberOfParticles();++idxPart){
particle_t tmp;
// get the current particles
loader.fillParticle(&tmp.pos,&tmp.phi);
// set the morton index of the current particle at the max_level
tmp.morton_index = inria::linear_tree::get_morton_index(
tmp.pos, box, max_level);
// set the weight of the particle
tmp.phi = 0.1;
// add the particle to my vector of particle
myParticles.at(idxPart) = tmp;
}
// Now i have all of my particles in a vector, they all have a morton index
// now we will sort them
std::cout << "Sorting particles ...";
inria::sort(mpi_comm,myParticles,
[](const auto& p1, const auto& p2) {
return p1.morton_index < p2.morton_index;
});
std::cout << " Done" << std::endl;
std::cout << " I have " << loader.getMyNumberOfParticles() << " particles ..." << std::endl;
std::cout << "For a total of " << loader.getNumberOfParticles() << " particles ..." << std::endl;
// Now i want to create the the linear tree
// a linear tree is a tree, with only the leaf
std::cout << "Create linear tree at level " << level << " ...";
auto linear_tree =
inria::linear_tree::create_balanced_linear_tree_at_level(mpi_comm,
level,
box,
myParticles);
std::cout << " done." << std::endl;
// Now i need to create a blocked linear tree, it's just a linear tree with
// more information
std::cout << "Creating blocked linear tree ...";
// declaration of the group linear tree
FGroupLinearTree<decltype(linear_tree)::value_type>group_linear_tree{mpi_comm};
// now i will fill it
// i can apply 2 methods
// - create_local_group_linear_tree
// - create_global_group_linear_tree
// the first function balance the linear tree according to particle (so he
// don't touch to the distribution )
// the second function balance the linear tree according to the number of
// block, he try to have group full on the left
//
// with a groupSize at 128, 890 leaf and 3 proc the distribution will be
// ___________________________________
// | Proc 0 | Proc 1 | Proc 2 |
// | | | |
// | 128 128 | 128 128 | 128 128 122 |
// |___________|_________|_____________|
group_linear_tree.create_local_group_linear_tree(
&linear_tree,
groupSize
);
std::cout << " Done" << std::endl;
// now i will to redistribute the particle according to the linear tree
std::cout << "Redistribute ...";
// Redistribution of particles
inria::linear_tree::redistribute_particles(mpi_comm,
linear_tree,
myParticles);
std::cout << " Done" << std::endl;
// Now we need to modify the morton index of of all particle to
// have the morton index at le treeHeight-1
MortonIndex minMidx=1,maxMidx=0;
for (int i =0 ; i< level ; ++i){
minMidx= minMidx <<3 ;
}
for(unsigned i = 0 ; i < myParticles.size(); ++i){
myParticles.at(i).morton_index = inria::linear_tree::get_morton_index(
myParticles.at(i).pos, box, level);
maxMidx =std::max(maxMidx, myParticles.at(i).morton_index);
minMidx =std::min(minMidx, myParticles.at(i).morton_index);
}
std::cout << " MinIndex: " << minMidx << " MaxIndex: " << maxMidx<<std::endl;
// Now we need to share the particle distribution to build the GroupTree
std::cout << "Share my particle distribution ...";
group_linear_tree.set_index_particle_distribution(myParticles);
std::cout << " done"<< std::endl;
// Now i can declare my groupTree
// it's a empty instance of the FGroupTree
GroupOctreeClass localGroupTree = GroupOctreeClass::template get_block_tree_instance<GroupCellSymbClass, GroupCellUpClass, GroupCellDownClass, GroupContainerClass>(TreeHeight,
groupSize,
loader.getCenterOfBox(),
loader.getBoxWidth());
// Now i can fill the localGroupTree
std::cout << "Creating tree ..." ;
localGroupTree.create_tree(group_linear_tree,myParticles);
std::cout << " done." << std::endl;
// now we can show the groupTree
localGroupTree.printInfoBlocks();
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef SCALFMM_ADAPTIVE_DUMMY_TREE_
#define SCALFMM_ADAPTIVE_DUMMY_TREE_
#include "Adaptive/FNode.hpp"
namespace scalfmm {
namespace tests {
template<typename _FReal, std::size_t _Dim>
struct DummyTree {
constexpr static const std::size_t Dim = _Dim;
using FReal = _FReal;
using particle_t = MockParticle<FReal, Dim>;
using node_t = FNode<DummyTree, std::vector<particle_t >, NodeEmptyData >;
using leaf_list_t = std::unordered_set<node_t*>;
using position_t = typename node_t::position_t;
using box_t = typename node_t::box_t;
box_t _box;
node_t* _root;
leaf_list_t _leaves;
std::size_t _leaf_max_particle_count = 10;
std::size_t _height = 0;
DummyTree(FReal side_length) {
_box.set(_box.c1, position_t()+side_length);
_root = new node_t(this);
}
~DummyTree() {
delete _root;
}
box_t box() const {return _box;}
node_t* root() const {return _root;}
leaf_list_t& leaves() {return _leaves;}
std::size_t height() const {return _height;}
void set_height(std::size_t new_height) {_height = new_height;}
std::size_t max_height() const {return 20;}
std::size_t leaf_max_particle_count() const {return _leaf_max_particle_count;}
friend bool operator==(const DummyTree& t1, const DummyTree& t2) {
return &t1 == &t2;
}
};
}
}
#endif
This diff is collapsed.
#ifndef _SCALFMM_TEST_MOCKPARTICLE_HPP_
#define _SCALFMM_TEST_MOCKPARTICLE_HPP_
#include <tuple>
#include "Utils/FPoint.hpp"
#include "Components/FBasicParticle.hpp"
namespace scalfmm {
namespace tests {
/** \brief Mock particle used for testing purposes
*
* This particle class implements the basic struture required by a
* particle. It uses some c++ template metaprogramming to allow its use
* in any dimensions.
*
* The class indexes its instances through the public #index attibute.
*
* \tparam FReal The type used for floating point representation
* \tparal Dim The space dimension count
*/
template<typename FReal, std::size_t Dim = 3>
struct MockParticle : FBasicParticle<FReal, Dim, std::size_t> {
using FBase = FBasicParticle<FReal, Dim, std::size_t>;
static std::size_t idx;
using FBase::FBase;
/** \brief Set a new value for the class counter
*
* \param new_index The new index to count from
*/
static void reset_index(std::size_t new_index) {
idx = new_index;
}
MockParticle() : FBase() {
std::get<Dim>(this->as_tuple()) = ++idx;
}
MockParticle(const typename FBase::position_t& pos, std::size_t i)
: FBase(pos, i)
{
std::get<Dim>(this->as_tuple()) = ++idx;
}
/// Constructor from position and types
MockParticle(const typename FBase::position_t& pos)
: FBase(pos, ++idx)
{}
};
// Definition of MockParticle class variable idx
template<typename FReal, std::size_t Dim>
std::size_t MockParticle<FReal, Dim>::idx = 0;
}
}
#endif
#ifndef SCALFMM_TEST_ABSTRACT_HPP_
#define SCALFMM_TEST_ABSTRACT_HPP_
#include <type_traits>
#include <iostream>
#define RUN(test_function_name) \
std::cout << #test_function_name << std::endl; \
run_test(& std::remove_reference<decltype((*this))>::type :: test_function_name);
template<class T>
struct test_Abstract {
virtual void set_up() {}
virtual void tear_down() {}
virtual void run_all() = 0;
virtual void run_test(void (T::*test_function)()) {
this->set_up();
(dynamic_cast<T*>(this)->*test_function)();
this->tear_down();
}
};
#endif
/**
* \file
*
* \author Quentin Khan
*
* \brief Test for the sequential adaptive FMM algorithm.
*
* This fills an adaptive tree with mock particles. Those are made of a position
* and a count attribute initialised to 0.
*
* A test kernel is then run to count the particles that interact. At the end of
* the run, every particle must hold the total particle count in its count
* attribute.
*
*/
#include <iostream>
#include <string>
#include "Files/FFmaGenericLoader.hpp"
#include "Components/FBasicParticle.hpp"
#include "Adaptive/FAdaptiveSequential.hpp"
#include "Adaptive/FTree.hpp"
#include "Adaptive/FVariadicParticleContainer.hpp"
#include "FCountKernel.hpp"
/**
* \brief Expected P2P count for a node
*
* Computes the maximum P2P interaction count for given node.
*
* \warning For an adaptive tree, this count is not the exact interaction
* count. Some nodes that are counted here may not exist in the actual tree.
*/
template<typename node_t>
std::size_t expected_P2P(node_t* node) {
std::size_t index = node->getIndex();
std::size_t depth = node->getLevel();
int min = 0;
int max = (int)std::pow(2,depth);
FTreeCoordinate coord(index);
std::size_t count = 0;
for(int i = std::max(min, coord[0]-1); i < std::min(max, coord[0]+2); ++i)
for(int j = std::max(min, coord[1]-1); j < std::min(max, coord[1]+2); ++j)
for(int k = std::max(min, coord[2]-1); k < std::min(max, coord[2]+2); ++k)
++count;
return count;
}
template<typename node_t>
std::size_t expected_P2M(node_t* node) {
if(node->is_leaf() && node->getParticleContainer()->size() != 0)
return 1;
else
return 0;
}
template<typename node_t>
std::size_t expected_M2M(node_t* node) {
if(! node->is_leaf()) {
return 8;
} else {
return 0;
}
}
/**
* \brief Expected M2L count for a node
*
* Computes the maximum M2L interaction count that given node can have.
*
* \warning For an adaptive tree, this count is not the exact interaction
* count. Some nodes that are counted here may not exist in the actual tree.
*/
template<typename node_t>
std::size_t expected_M2L(node_t* node) {
std::size_t index = node->getIndex();
std::size_t depth = node->getLevel();
int min = 0;
int max = 1 << depth;
FTreeCoordinate coord(index);
std::size_t count = 0;
for(int i = std::max(min, coord[0]-2-(coord[0]%2)) ;
i < std::min(max, coord[0]+3+(1-coord[0]%2)) ;
++i) {
for(int j = std::max(min, coord[1]-2-(coord[1]%2)) ;
j < std::min(max, coord[1]+3+(1-coord[1]%2)) ;
++j) {
for(int k = std::max(min, coord[2]-2-(coord[2]%2)) ;
k < std::min(max, coord[2]+3+(1-coord[2]%2)) ;
++k) {
if((i < coord[0] - 1 || i > coord[0] + 1) ||
(j < coord[1] - 1 || j > coord[1] + 1) ||
(k < coord[2] - 1 || k > coord[2] + 1)) {
++count;
}
}
}
}
return count;
}
template<typename node_t>
std::size_t expected_L2L(node_t* node) {
if(! node->is_leaf()) {
return 8;
} else {
return 0;
}
}
template<typename node_t>
std::size_t expected_L2P(node_t* node) {
if(node->is_leaf() && node->getParticleContainer()->size() != 0) {
return 1;
} else {
return 0;
}
}
template<typename tree_t, typename kernel_t>
void test_P2P(tree_t& tree, kernel_t& kernel) {
for(auto&& leaf : tree.leaves()) {
if(kernel.call_count["P2P"] != expected_P2P(leaf)) {
std::cout << "error-P2P-count "
<< leaf->getIndex() << " "
<< FTreeCoordinate(leaf->getIndex()) << " "
<< kernel.call_count["P2P"] << " "
<< expected_P2P(leaf)
<< std::endl;
}
}
}
template<typename tree_t, typename position_vector_t>
void test_particle_count(tree_t& tree, const position_vector_t& position_vector) {
for(auto&& leaf : tree.leaves()) {
for(auto particle : *(leaf->getParticleContainer())) {
if(std::get<tree_t::particle_t::COUNT>(particle) != position_vector.size())
std::cout << "error-particle-count "
<< leaf->getIndex() << " "
<< FTreeCoordinate(leaf->getIndex()) << " "
<< std::get<tree_t::particle_t::COUNT>(particle) << " "
<< position_vector.size()
<< std::endl;
}
}
}
template<typename tree_t, typename kernel_t>
void test_P2M(tree_t& tree, kernel_t&) {
// Assert that all particles have the right count attribute
for(auto&& node : tree.post_order_walk()) {
auto* leaf = &node;
if(leaf->getData()->getMultipoleData().P2M_count != expected_P2M(leaf)) {
std::cout << "error-P2M "
<< &(leaf->getData()->getMultipoleData()) << " "
<< leaf->getIndex() << " "
<< FTreeCoordinate(leaf->getIndex()) << " "
<< leaf->getData()->getMultipoleData().P2M_count << " "
<< expected_P2M(leaf)
<< std::endl;
}
}
}
template<typename tree_t, typename kernel_t>
void test_M2M(tree_t& tree, kernel_t& kernel) {
// Assert that all particles have the right count attribute
for(auto&& node : tree.post_order_walk()) {
auto n = &node;
if(n->getData()->getMultipoleData().M2M_count != expected_M2M(n)) {
std::cout << "error-M2M "
<< n->getIndex() << " "
<< kernel.call_count["M2M"] << " "
<< expected_M2M(n)
<< std::endl;
}
}
}
template<typename tree_t, typename kernel_t>
void test_M2L(tree_t& tree, kernel_t& kernel) {
// Assert that all particles have the right count attribute
for(auto&& node : tree.post_order_walk()) {
auto leaf = &node;
if(kernel.call_count["M2L"] != expected_M2L(leaf)) {
std::cout << "error-M2L "
<< leaf->getIndex() << " "
<< kernel.call_count["M2L"] << " "
<< expected_M2L(leaf,true)
<< std::endl;
}
}
}
template<typename tree_t, typename kernel_t>
void test_L2L(tree_t& tree, kernel_t& kernel) {
// Assert that all particles have the right count attribute
for(auto&& node : tree.in_order_walk()) {
auto n = &node;
if(n->getData()->getLocalExpansionData().L2L_count != expected_L2L(n)) {
std::cout << "error-L2L "
<< n->getIndex() << " "
<< kernel.call_count["L2L"] << " "
<< expected_L2L(n)
<< std::endl;
}
}
}
template<typename tree_t, typename kernel_t>
void test_L2P(tree_t& tree, kernel_t& kernel) {
// Assert that all particles have the right count attribute
for(auto&& node : tree.in_order_walk()) {
auto leaf = &node;
if(leaf->getData()->getLocalExpansionData().L2P_count != expected_L2P(leaf)) {
std::cout << "error-L2P "
<< leaf->getIndex() << " "
<< kernel.call_count["L2P"] << " "
<< expected_L2P(leaf)
<< std::endl;
}
}
}
int main() {
/// Floating point representation
using FReal = double;
/// Space dimension
constexpr std::size_t Dim = 3;
/// Particle type
using particle_t = TestCountParticle<FReal, Dim>;
/// Particle container type
using particle_container_t = FVariadicParticleContainer<particle_t>;
/// Node data type
using node_data_t = TestCountNodeData;
/// Adaptive tree type
using tree_t = FTree<particle_container_t, node_data_t>;
/// Kernel type
using kernel_t = FCountKernel<node_data_t, particle_container_t>;
/// FMM algorithm type
using fmm_algo_t = FAdaptiveSequential<tree_t, kernel_t>;
// Load the test particle distribution
FFmaGenericLoader<FReal> loader("test.fma");
// Tree setup
tree_t tree({loader.getBoxWidth(), loader.getCenterOfBox()});
tree.leaf_max_particle_count(1);
std::vector<particle_t::position_t> position_vect;
// Load the particles into the list and the tree
for(int i = 0; i < loader.getNumberOfParticles(); ++i) {
FReal tmp_val;
typename particle_t::position_t tmp_pos;
loader.fillParticle(&tmp_pos, &tmp_val);
position_vect.push_back(tmp_pos);
tree.insert(tmp_pos, 0);
}
// Create kernel and FMM object
kernel_t kernel;
fmm_algo_t fmm_algo(&tree, &kernel);
// Run algorithm
fmm_algo.run();
// test_P2P(tree, kernel); // TODO error, kernel count total P2P, function tests for node P2P
test_P2M(tree, kernel);
test_M2M(tree, kernel);
// test_M2L(tree, kernel);
test_L2L(tree, kernel);
test_L2P(tree, kernel);
test_particle_count(tree, position_vect);
}
/**
* \file
*
* \author Quentin Khan
*
* \brief Test program for the task adaptive FMM implementation
*
* Tests:
* - test 1, counts the particles that interact with each particle
* - TODO test computation of an actual kernel against sequential result
*
* ##### Test 1
*
* Fills an adaptive tree with mock particles. Those are made of a position and
* a count attribute set to 0.
*
* The algorithm is run with a kernel that counts the particles that interact.
*
* ###### Expected result
*
* At the end of the run, every particle must hold the total particle count in
* its count attribute.
*
*/
// @FUSE_OMP4