Commit 69c8d416 authored by COULAUD Olivier's avatar COULAUD Olivier

Src/Files/FGenerateDistribution.hpptry to fix a conflict

parents 73160667 3e5b1bed
......@@ -145,10 +145,9 @@ typedef void (*Callback_free_cell)(void*);
/**
* @brief Callback used to know the size of userData.
* @param level current level of current cell
* @param userData Datas that will be serialize
* @param morton_index of the current cell
*/
typedef FSize (*Callback_get_cell_size)(int level, void * userDatas, long long morton_index);
typedef FSize (*Callback_get_cell_size)(int level, long long morton_index);
/**
* @brief Callback used to serialize userdata inside an array of size
......@@ -159,6 +158,39 @@ typedef FSize (*Callback_get_cell_size)(int level, void * userDatas, long long m
*/
typedef void (*Callback_copy_cell)(void * userDatas, FSize size, void * memoryAllocated);
/**
* @brief Callback used by scalfmm to know the size needed by the user
* to store its local datas linked to a leaf.
*
* @param nbParts : number of point inside current Leaf
* @return Size (in bytes) needed to serialize the user datas
*/
typedef FSize (*Callback_get_leaf_size)(FSize nbParts);
/**
* @brief Callback used by scalfmm to serialize the leaf user data.
*
* @param Morton MortonIndex of current Leaf
* @param nbParts : number of point inside current Leaf
* @param userdata : leaf User data
* @param memAllocated : Ptr to an array of size =
* Callback_get_leaf_size(...), to be filled by the user.
*/
typedef void (*Callback_copy_leaf)(FSize nbParts, void * userDatas, void * memAllocated);
/**
* @brief Callback used by scalfmm to retreive leaf data from an array
* (previously filled by the user through Callback_copy_leaf)
*
* @param Morton MortonIndex of current Leaf
* @param nbParts : number of point inside current Leaf
* @param memAllocated : Ptr to an array of size =
* Callback_get_leaf_size(...), to be read by the user in order to
* re-build its leaf.
* @return new userdata local to the leaf
*/
typedef void * (*Callback_restore_leaf)(FSize nbParts, void * memAllocated);
/**
* @brief Callback called if scalfmm_finalize_cell is called.
......@@ -214,10 +246,18 @@ typedef struct User_Scalfmm_Cell_Descriptor{
Callback_get_cell_size user_get_size;
Callback_copy_cell user_copy_cell;
Callback_restore_cell user_restore_cell;
Callback_init_leaf user_init_leaf;
Callback_free_leaf user_free_leaf;
}Scalfmm_Cell_Descriptor;
/**
* @brief This struct contains all the callback affecting leaves
*/
typedef struct User_Scalfmm_Leaf_Descriptor{
Callback_init_leaf user_init_leaf;
Callback_free_leaf user_free_leaf;
Callback_get_leaf_size user_get_size;
Callback_copy_leaf user_copy_leaf;
Callback_restore_leaf user_restore_leaf;
}Scalfmm_Leaf_Descriptor;
/**
* @brief This function build the tree. If scalfmm_init has been
......@@ -228,7 +268,10 @@ typedef struct User_Scalfmm_Cell_Descriptor{
* @param BoxWidth Width of the entire simulation box.
* @param BoxCenter Coordinate of the center of the box (ie array)
*/
void scalfmm_build_tree(scalfmm_handle handle,int TreeHeight,double BoxWidth,double* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor);
void scalfmm_build_tree(scalfmm_handle handle,int TreeHeight,double BoxWidth,
double* BoxCenter,
Scalfmm_Cell_Descriptor user_cell_descriptor,
Scalfmm_Leaf_Descriptor user_leaf_descriptor);
/**
......@@ -617,6 +660,29 @@ typedef void (*Callback_P2PInner)(void * targetLeaf,FSize nbParticles, const FSi
typedef void (*Callback_P2PSym)(void * targetLeaf, FSize nbParticles, const FSize* particleIndexes,
void * sourceLeaf, FSize nbSourceParticles, const FSize* sourceParticleIndexes, void* userData);
/**
* @brief Function to be filled by user's P2P Remote, the sources will
* be erased after the call, so no need to modify them
* @param targetLeaf ptr to user target leaf
* @param nbParticles number of particle in current leaf
* @param particleIndexes indexes of particles currently computed
* @praram sourceLeaves array of user source target
* @param sourceParticleIndexes array of indexes for each source
* @param sourceNbPart : array containing the number of part for each source
* @param size Number of direct neighbors
* @param userData datas specific to the user's kernel
* @attention This function will be called in distributed scalfmm
* only, between leaves belonging to diffenrent MPI processus. On ly
* the target leaf should be modified, since we don't send back the
* sources.
*/
typedef void (*Callback_P2PRemote)(void * targetLeaf,FSize nbParticles, const FSize* particleIndexes,
void ** sourceLeaves,
const FSize ** sourceParticleIndexes,FSize * sourceNbPart,
const int * sourcePosition, const int size, void* userData);
/**
* @brief Function to be filled by user's method to reset a user's cell
* @param level level of the cell.
......@@ -647,6 +713,7 @@ typedef struct User_Scalfmm_Kernel_Descriptor {
Callback_P2PFull p2p_full;
Callback_P2PInner p2pinner;
Callback_P2PSym p2p_sym;
Callback_P2PRemote p2p_remote;
}Scalfmm_Kernel_Descriptor;
......@@ -682,6 +749,14 @@ void scalfmm_user_kernel_config(scalfmm_handle Handle, Scalfmm_Kernel_Descriptor
*/
void scalfmm_execute_fmm(scalfmm_handle Handle);
/**
* @brief This function launch the fmm on the parameters given, but
* only the far field will be evaluated
* @param Handle scalfmm_handle provided by scalfmm_init
*/
void scalfmm_execute_fmm_far_field(scalfmm_handle Handle);
/**
* @brief This function apply the call back on each leaf. Should be
* called after insert_parts.
......@@ -778,8 +853,7 @@ scalfmm_handle scalfmm_init_distributed( scalfmm_kernel_type KernelType,scalfmm_
* once the partitionning done. Can be inserted with no changes.
* @param indexesFilled Array that store the global index of each part
* in the localArrayFilled.
* @param stride stride between two attributes inside attr.
* @param attr array of attribute to be distributed alongside the positions.
* @param outputNbPoint number of points dedicated to this proc
*/
void scalfmm_create_local_partition(scalfmm_handle handle, int nbPoints, double * particleXYZ, double ** localArrayFilled,
FSize ** indexesFilled, FSize * outputNbPoint);
......
......@@ -83,7 +83,8 @@ public:
FScalFMMEngine<FReal>::Algorithm = algo;
}
void build_tree(int TreeHeight, FReal BoxWidth , FReal * BoxCenter,User_Scalfmm_Cell_Descriptor notUsedHere){
virtual void build_tree(int TreeHeight, FReal BoxWidth , FReal * BoxCenter,
User_Scalfmm_Cell_Descriptor notUsedHere, Scalfmm_Leaf_Descriptor notUsedHereToo){
octree = new OctreeClass(TreeHeight,FMath::Min(3,TreeHeight-1),BoxWidth,FPoint<FReal>(BoxCenter));
this->matrix = new MatrixKernelClass();
this->kernel = new InterKernel(TreeHeight,BoxWidth,FPoint<FReal>(BoxCenter),matrix);
......@@ -738,6 +739,47 @@ public:
// }
// }
void execute_fmm_far_field(){
switch(FScalFMMEngine<FReal>::Algorithm){
case 0:
{
typedef FFmmAlgorithm<OctreeClass,InterCell,ContainerClass,InterKernel,LeafClass> AlgoClassSeq;
AlgoClassSeq* algoSeq = new AlgoClassSeq(octree,kernel);
algoSeq->execute(FFmmP2M | FFmmM2M | FFmmM2L | FFmmL2L | FFmmL2P);
FScalFMMEngine<FReal>::algoTimer = algoSeq;
FScalFMMEngine<FReal>::abstrct = algoSeq;
break;
}
case 1:
{
typedef FFmmAlgorithmThread<OctreeClass,InterCell,ContainerClass,InterKernel,LeafClass> AlgoClassThread;
AlgoClassThread* algoThread = new AlgoClassThread(octree,kernel);
algoThread->execute(FFmmP2M | FFmmM2M | FFmmM2L | FFmmL2L | FFmmL2P);
FScalFMMEngine<FReal>::algoTimer = algoThread;
FScalFMMEngine<FReal>::abstrct = algoThread;
break;
}
case 2:
{
typedef FFmmAlgorithmPeriodic<FReal,OctreeClass,InterCell,ContainerClass,InterKernel,LeafClass> AlgoClassPeriodic;
AlgoClassPeriodic algoPeriod(octree,2);
algoPeriod.setKernel(kernel);
algoPeriod.execute(FFmmP2M | FFmmM2M | FFmmM2L | FFmmL2L | FFmmL2P);
break;
}
case 3:
{
typedef FFmmAlgorithmThreadTsm<OctreeClass,InterCell,ContainerClass,InterKernel,LeafClass> AlgoClassTargetSource;
AlgoClassTargetSource* algoTS = new AlgoClassTargetSource(octree,kernel);
algoTS->execute(FFmmP2M | FFmmM2M | FFmmM2L | FFmmL2L | FFmmL2P);
FScalFMMEngine<FReal>::algoTimer = algoTS;
FScalFMMEngine<FReal>::abstrct = algoTS;
break;
}
default :
std::cout<< "No algorithm found (probably for strange reasons) : "<< FScalFMMEngine<FReal>::Algorithm <<" exiting" << std::endl;
}
}
void execute_fmm(){
switch(FScalFMMEngine<FReal>::Algorithm){
......
......@@ -95,7 +95,9 @@ public:
//by specific Engine
//Function about the tree
virtual void build_tree(int TreeHeight,FReal BoxWidth,FReal* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor){
virtual void build_tree(int TreeHeight,FReal BoxWidth,FReal* BoxCenter,
Scalfmm_Cell_Descriptor user_cell_descriptor,
Scalfmm_Leaf_Descriptor user_leaf_descriptor){
FAssertLF(0,"Nothing has been done yet, exiting");
}
......@@ -775,6 +777,9 @@ public:
virtual void execute_fmm(){
FAssertLF(0,"No kernel set, cannot execute anything, exiting ...\n");
}
virtual void execute_fmm_far_field(){
FAssertLF(0,"No kernel set, cannot execute anything, exiting ...\n");
}
virtual void intern_dealloc_handle(Callback_free_cell userDeallocator){
FAssertLF(0,"No kernel set, cannot execute anything, exiting ...\n");
......@@ -833,8 +838,11 @@ struct ScalFmmCoreHandle {
extern "C" void scalfmm_build_tree(scalfmm_handle Handle,int TreeHeight,double BoxWidth,double* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor){
((ScalFmmCoreHandle<double> *) Handle)->engine->build_tree(TreeHeight,BoxWidth, BoxCenter, user_cell_descriptor);
extern "C" void scalfmm_build_tree(scalfmm_handle Handle,int TreeHeight,double BoxWidth,
double* BoxCenter,
Scalfmm_Cell_Descriptor user_cell_descriptor,
Scalfmm_Leaf_Descriptor user_leaf_descriptor){
((ScalFmmCoreHandle<double> *) Handle)->engine->build_tree(TreeHeight,BoxWidth, BoxCenter, user_cell_descriptor, user_leaf_descriptor);
}
extern "C" void scalfmm_tree_insert_particles(scalfmm_handle Handle, int NbPositions, double * arrayX, double * arrayY, double * arrayZ,
......@@ -989,6 +997,12 @@ extern "C" void scalfmm_execute_fmm(scalfmm_handle Handle){
((ScalFmmCoreHandle<double> * ) Handle)->engine->execute_fmm();
}
//Executing FMM
extern "C" void scalfmm_execute_fmm_far_field(scalfmm_handle Handle){
((ScalFmmCoreHandle<double> * ) Handle)->engine->execute_fmm_far_field();
}
extern "C" void scalfmm_user_kernel_config(scalfmm_handle Handle, Scalfmm_Kernel_Descriptor userKernel, void * userDatas){
((ScalFmmCoreHandle<double> * ) Handle)->engine->user_kernel_config(userKernel,userDatas);
}
......
......@@ -6,6 +6,15 @@ extern "C" {
#include "FInterEngine.hpp"
#include "FUserKernelEngine.hpp"
/**
* Define here static member
*/
Scalfmm_Cell_Descriptor CoreCell::user_cell_descriptor;
template<class FReal>
Scalfmm_Leaf_Descriptor FUserLeafContainer<FReal>::user_leaf_descriptor;
extern "C" scalfmm_handle scalfmm_init(/*int TreeHeight,double BoxWidth,
double* BoxCenter, */
scalfmm_kernel_type KernelType,
......@@ -154,6 +163,55 @@ typedef struct FChebCell_struct{
FChebCell<double,7> * cell;
}ChebCellStruct;
typedef struct FChebLeaf_struct{
//Store a P2PParticleContainer
FP2PParticleContainerIndexed<double>* container;
}ChebLeafStruct;
//Initialize leaves
extern "C" ChebLeafStruct * ChebLeafStruct_create(FSize nbPart){
FP2PParticleContainerIndexed<double>* newCont = new FP2PParticleContainerIndexed<double>();
newCont->reserve(nbPart);
ChebLeafStruct * newLeaf = new ChebLeafStruct();
newLeaf->container = newCont;
return newLeaf;
}
//Delete leaves
extern "C" void ChebLeafStruct_free(void * leafData){
ChebLeafStruct * leaf = reinterpret_cast<ChebLeafStruct *>(leafData);
delete leaf->container;
delete leaf;
}
//Fill leaves once partitionning is done
extern "C" void ChebLeafStruct_fill(FSize nbPart, const FSize * idxPart,
long long morton_index, void * leafData,
void * userData){
UserData * userDataKernel = reinterpret_cast<UserData *>(userData);
ChebLeafStruct * leaf = reinterpret_cast<ChebLeafStruct *>(leafData);
FP2PParticleContainerIndexed<double>* container = leaf->container;
for(int i=0 ; i<nbPart; ++i){
FPoint<double> pos{userDataKernel->insertedPositions[idxPart[i]*3 + 0],
userDataKernel->insertedPositions[idxPart[i]*3 + 1],
userDataKernel->insertedPositions[idxPart[i]*3 + 2]};
double phi = userDataKernel->myPhyValues[idxPart[i]];
container->push(pos,idxPart[i],phi);
}
}
extern "C" void ChebLeafStruct_get_back_results(void * leafData,
double ** forceXptr, double ** forceYptr, double ** forceZptr,
double ** potentialsptr){
ChebLeafStruct * leaf = reinterpret_cast<ChebLeafStruct *>(leafData);
*forceXptr = leaf->container->getForcesX();
*forceYptr = leaf->container->getForcesY();
*forceZptr = leaf->container->getForcesZ();
*potentialsptr = leaf->container->getPotentials();
}
//How to create/destroy cells
extern "C" ChebCellStruct * ChebCellStruct_create(long long int inIndex,int * position){
......@@ -179,6 +237,8 @@ typedef struct FChebKernel_struct{
FInterpMatrixKernelR<double> * matrix;
} ChebKernelStruct;
//Kernel functions
extern "C" ChebKernelStruct * ChebKernelStruct_create(int inTreeHeight,
double inBoxWidth,
......@@ -210,8 +270,30 @@ extern "C" void ChebKernelStruct_free(void *inKernel){
delete reinterpret_cast<ChebKernelStruct *>(inKernel);
}
/**
* New one, intended to work with internal FP2PParticleContainer instead of filling a new one
*/
extern "C" void ChebKernel_P2M(void * leafCell, void * leafData, FSize nbParticles,
const FSize *particleIndexes, void * inKernel){
//get the real leaf
ChebLeafStruct * leaf = reinterpret_cast<ChebLeafStruct *>(leafData);
extern "C" void ChebKernel_P2M(void * leafCell, FSize nbParticles, const FSize *particleIndexes, void * inKernel){
//get the real cell struct
ChebCellStruct * realCellStruct = reinterpret_cast<ChebCellStruct *>(leafCell);
FChebCell<double,7> * realCell = realCellStruct->cell;
//Identify thread number
int id_thread = omp_get_thread_num();
//get the real chebyshev struct
UserData * userDataKernel = reinterpret_cast<UserData *>(inKernel);
ChebKernelStruct * realKernel = userDataKernel->kernelStruct;
realKernel->kernel[id_thread]->P2M(realCell, leaf->container);
}
extern "C" void ChebKernel_P2M_old(void * leafCell, void * leafData, FSize nbParticles,
const FSize *particleIndexes, void * inKernel){
//make temporary array of parts
FP2PParticleContainerIndexed<double>* tempContainer = new FP2PParticleContainerIndexed<double>();
tempContainer->reserve(nbParticles);
......@@ -239,6 +321,7 @@ extern "C" void ChebKernel_P2M(void * leafCell, FSize nbParticles, const FSize *
delete tempContainer;
}
extern "C" void ChebKernel_M2M(int level, void* parentCell, int childPosition, void *childCell, void *inKernel){
//Get our structures
ChebCellStruct * parentCellStruct = reinterpret_cast<ChebCellStruct *>(parentCell);
......@@ -297,7 +380,28 @@ extern "C" void ChebKernel_L2L(int level, void* parentCell, int childPosition, v
childChebCell->getLocal(0));
}
extern "C" void ChebKernel_L2P(void* leafCell, FSize nbParticles, const FSize* particleIndexes, void* inKernel){
extern "C" void ChebKernel_L2P(void* leafCell, void * leafData, FSize nbParticles,
const FSize* particleIndexes, void* inKernel){
//get the real leaf
ChebLeafStruct * leaf = reinterpret_cast<ChebLeafStruct *>(leafData);
//get the real cell struct
ChebCellStruct * realCellStruct = reinterpret_cast<ChebCellStruct *>(leafCell);
FChebCell<double,7> * realCell = realCellStruct->cell;
//Identify thread number
int id_thread = omp_get_thread_num();
//get the real chebyshev struct
UserData * userDataKernel = reinterpret_cast<UserData *>(inKernel);
ChebKernelStruct * realKernel = userDataKernel->kernelStruct;
realKernel->kernel[id_thread]->L2P(realCell,leaf->container);
}
extern "C" void ChebKernel_L2P_old(void* leafCell, void * leafData,FSize nbParticles,
const FSize* particleIndexes, void* inKernel){
//Create temporary FSimpleLeaf
FP2PParticleContainerIndexed<double>* tempContainer = new FP2PParticleContainerIndexed<double>();
tempContainer->reserve(nbParticles);
......@@ -338,9 +442,43 @@ extern "C" void ChebKernel_L2P(void* leafCell, FSize nbParticles, const FSize* p
tempContainer=nullptr;
}
void ChebKernel_P2P(FSize nbParticles, const FSize* particleIndexes, const FSize ** sourceParticleIndexes,FSize* sourceNbPart,
void ChebKernel_P2P(void * targetleaf, FSize nbParticles, const FSize* particleIndexes, void ** sourceLeaves,
const FSize ** sourceParticleIndexes, FSize* sourceNbPart,
const int * sourcePosition,const int size, void* inKernel){
//First step, convert the target leaf in a P2P Particle container
ChebLeafStruct * tgtLeaf = reinterpret_cast<ChebLeafStruct *>(targetleaf);
//Same with the sources leaves
std::vector<FP2PParticleContainerIndexed<double> *> arraySrcLeaves;
arraySrcLeaves.reserve(size);
for(int i=0 ; i<size ; ++i){
if(sourceNbPart[i] != 0){
arraySrcLeaves.push_back(reinterpret_cast<ChebLeafStruct *>(sourceLeaves[i])->container);
}else{
arraySrcLeaves.push_back(nullptr);
}
}
//Then call P2P ?
//Identify thread number
int id_thread = omp_get_thread_num();
//Get the kernel
ChebKernelStruct * inKernelStruct = reinterpret_cast<UserData*>(inKernel)->kernelStruct;
//Empty tree coordinate
int coord[3] = {0,0,0};
inKernelStruct->kernel[id_thread]->P2P(FTreeCoordinate(coord),tgtLeaf->container,tgtLeaf->container,
arraySrcLeaves.data(),sourcePosition,size);
}
void ChebKernel_P2P_old(void * targetLeaf, FSize nbParticles, const FSize* particleIndexes,
void ** sourceLeaves,
const FSize ** sourceParticleIndexes,FSize* sourceNbPart,
const int * sourcePosition,const int size, void* inKernel){
//Create temporary FSimpleLeaf for target
FP2PParticleContainerIndexed<double>* tempContTarget = new FP2PParticleContainerIndexed<double>();
......@@ -421,13 +559,48 @@ void ChebKernel_P2P(FSize nbParticles, const FSize* particleIndexes, const FSize
delete [] tempContSources;
}
void ChebKernel_P2PRemote(void * targetLeaf,FSize nbParticles, const FSize* particleIndexes,
void ** sourceLeaves,
const FSize ** sourceParticleIndexes,FSize * sourceNbPart,
const int * sourcePosition, const int size, void* inKernel){
//First step, convert the target leaf in a P2P Particle container
ChebLeafStruct * tgtLeaf = reinterpret_cast<ChebLeafStruct *>(targetLeaf);
//Same with the sources leaves
std::vector<FP2PParticleContainerIndexed<double> *> arraySrcLeaves;
arraySrcLeaves.reserve(size);
for(int i=0 ; i<size ; ++i){
if(sourceNbPart[i] != 0){
arraySrcLeaves.push_back(reinterpret_cast<ChebLeafStruct *>(sourceLeaves[i])->container);
}else{
arraySrcLeaves.push_back(nullptr);
}
}
//Then call P2P ?
//Identify thread number
int id_thread = omp_get_thread_num();
//Get the kernel
ChebKernelStruct * inKernelStruct = reinterpret_cast<UserData*>(inKernel)->kernelStruct;
//Empty tree coordinate
int coord[3] = {0,0,0};
inKernelStruct->kernel[id_thread]->P2PRemote(FTreeCoordinate(coord),tgtLeaf->container,tgtLeaf->container,
arraySrcLeaves.data(),sourcePosition,size);
}
void ChebCell_reset(int level, long long morton_index, int* tree_position, double* spatial_position, void * userCell,void * inKernel){
ChebCellStruct * cellStruct = reinterpret_cast<ChebCellStruct *>(userCell);
FChebCell<double,7>* chebCell = cellStruct->cell;
chebCell->resetToInitialState();
}
FSize ChebCell_getSize(int level,void * userData, long long morton_index){
FSize ChebCell_getSize(int level, long long morton_index){
//Create fake one and ask for its size
FChebCell<double,7>* chebCell = new FChebCell<double,7>();
//then return what size is needed to store a cell
......@@ -501,4 +674,94 @@ void* ChebCell_restore(int level, void * arrayTobeRead){
return cellStruct;
}
/**
* @brief Those fucntion implements the copy,restore and get_size
* functions for leaves
*/
FSize ChebLeaf_getSize(FSize nbPart){
//Test where we do not use leafData
FP2PParticleContainerIndexed<double>* newCont = new FP2PParticleContainerIndexed<double>();
newCont->reserve(nbPart);
//fake push empty parts
for(int i=0 ; i<nbPart ; ++i){
FPoint<double> pos{0,0,0};
newCont->push(pos,0,0,0,0,0);
}
FSize res = newCont->getSavedSize();
delete newCont;
return res;
}
/**
* Copy Order : Positions XYZ, then attributes
*/
void ChebLeaf_copy(FSize nbPart,void * userLeaf, void * memAllocated){
ChebLeafStruct * tgtLeaf = reinterpret_cast<ChebLeafStruct *>(userLeaf);
FP2PParticleContainerIndexed<double>* container = tgtLeaf->container;
char * toWrite = reinterpret_cast<char*>(memAllocated);
FSize cursor = 0;
//Loop over dimensions
for(int i=0 ; i<3 ; ++i){
memcpy(&toWrite[cursor],container->getPositions()[i],nbPart*sizeof(double));
cursor += nbPart*sizeof(double);
}
//Then store attributes
//First physical values
memcpy(&toWrite[cursor],container->getPhysicalValuesArray(),sizeof(double)*nbPart);
cursor += sizeof(double)*nbPart;
//Then fx
memcpy(&toWrite[cursor],container->getForcesXArray(),sizeof(double)*nbPart);
cursor += sizeof(double)*nbPart;
//Then fy
memcpy(&toWrite[cursor],container->getForcesYArray(),sizeof(double)*nbPart);
cursor += sizeof(double)*nbPart;
//Then fz
memcpy(&toWrite[cursor],container->getForcesZArray(),sizeof(double)*nbPart);
cursor += sizeof(double)*nbPart;
//Finally potentials
memcpy(&toWrite[cursor],container->getPotentialsArray(),sizeof(double)*nbPart);
cursor += sizeof(double)*nbPart;
}
void * ChebLeaf_restore(FSize nbPart,void * memToRead){
ChebLeafStruct * tgtLeaf = ChebLeafStruct_create(nbPart);
FP2PParticleContainerIndexed<double>* container = tgtLeaf->container;
char * toRead = reinterpret_cast<char*>(memToRead);
FSize cursor = 0;
//Loop over dimensions
for(int i=0 ; i<3 ; ++i){
memcpy(container->getWPositions()[i],&toRead[cursor],nbPart*sizeof(double));
cursor += nbPart*sizeof(double);
}
//Then store attributes
//First physical values
memcpy(container->getPhysicalValuesArray(),&toRead[cursor],sizeof(double)*nbPart);
cursor += sizeof(double)*nbPart;
//Then fx