Commit 648e2966 authored by BRAMAS Berenger's avatar BRAMAS Berenger
Browse files

Add dynanimc block tree and a test

parent b37776ec
// @SCALFMM_PRIVATE
#ifndef FGROUPATTACHEDLEAFDYN_HPP
#define FGROUPATTACHEDLEAFDYN_HPP
#include "../../Utils/FGlobal.hpp"
#include "../../Utils/FAssert.hpp"
#include "../../Utils/FPoint.hpp"
template <class FReal>
struct UnknownDescriptor{
FPoint<FReal> pos;
FSize originalIndex;
MortonIndex mindex;
};
template <class FReal>
class FGroupAttachedLeafDyn {
protected:
unsigned char* symbPart;
unsigned char* downPart;
public:
/** Empty constructor to point to nothing */
FGroupAttachedLeafDyn() : symbPart(nullptr), downPart(nullptr) {
}
FGroupAttachedLeafDyn(unsigned char* inSymbPart, unsigned char* inDownPart)
: symbPart(inSymbPart), downPart(inDownPart){
}
const unsigned char* getSymbPart() const {
return symbPart;
}
unsigned char* getSymbPart() {
return symbPart;
}
const unsigned char* getDownPart() const {
return downPart;
}
unsigned char* getDownPart() {
return downPart;
}
/** Return true if it has been attached to a memoy block */
bool isAttachedToSomething() const {
return symbPart != nullptr;
}
/** Allocate a new leaf by calling its constructor */
template<class ParticleClassContainer>
void copyFromContainer(const MortonIndex /*inMindex*/, const ParticleClassContainer* /*particles*/){
static_assert(sizeof(ParticleClassContainer) == 0, "copyFromContainer should be implemented by the subclass");
}
virtual void init(const MortonIndex inIndex, const UnknownDescriptor<FReal> inParticles[],
const FSize inNbParticles, const size_t inSymbSize, const size_t inDownSize) = 0;
};
#endif // FGROUPATTACHEDLEAFDYN_HPP
// @SCALFMM_PRIVATE
#ifndef FGROUPOFCELLSDYN_HPP
#define FGROUPOFCELLSDYN_HPP
#include "../../Utils/FAssert.hpp"
#include "../../Utils/FAlignedMemory.hpp"
#include "../../Containers/FTreeCoordinate.hpp"
#include "../StarPUUtils/FStarPUDefaultAlign.hpp"
#include <list>
#include <functional>
/**
* @brief The FGroupOfCellsDyn class manages the cells in block allocation.
*/
template <class CompositeCellClass>
class FGroupOfCellsDyn {
/** One header is allocated at the beginning of each block */
struct alignas(FStarPUDefaultAlign::StructAlign) BlockHeader{
MortonIndex startingIndex;
MortonIndex endingIndex;
int numberOfCellsInBlock;
int blockIndexesTableSize;
};
struct alignas(FStarPUDefaultAlign::StructAlign) CellClassSizes{
size_t symbCellClassSize;
size_t poleCellClassSize;
size_t localCellClassSize;
};
protected:
//< This value is for not used cells
static const MortonIndex CellIsEmptyFlag = -1;
//< The size of the memoryBuffer
size_t allocatedMemoryInByte;
//< Pointer to a block memory
unsigned char* memoryBuffer;
//< Pointer to the header inside the block memory
BlockHeader* blockHeader;
CellClassSizes* cellSizes;
//< Pointer to the indexes table inside the block memory
int* blockIndexesTable;
//< Pointer to the cells inside the block memory
unsigned char* blockCells;
//< The multipole data
unsigned char* cellMultipoles;
//< The local data size
unsigned char* cellLocals;
//< To kown if the object has to delete the memory
bool deleteBuffer;
public:
typedef CompositeCellClass CompleteCellClass;
FGroupOfCellsDyn()
: allocatedMemoryInByte(0), memoryBuffer(nullptr),
blockHeader(nullptr), cellSizes(nullptr), blockIndexesTable(nullptr), blockCells(nullptr),
cellMultipoles(nullptr), cellLocals(nullptr), deleteBuffer(false){
}
void reset(unsigned char* inBuffer, const size_t inAllocatedMemoryInByte,
unsigned char* inCellMultipoles, unsigned char* inCellLocals){
if(deleteBuffer){
for(int idxCellPtr = 0 ; idxCellPtr < blockHeader->blockIndexesTableSize ; ++idxCellPtr){
if(blockIndexesTable[idxCellPtr] != CellIsEmptyFlag){
const int cellPos = blockIndexesTable[idxCellPtr];
CompositeCellClass cell(&blockCells[cellPos*cellSizes->symbCellClassSize],
&cellMultipoles[cellPos*cellSizes->poleCellClassSize],
&cellLocals[cellPos*cellSizes->localCellClassSize]);
cell.release();
}
}
FAlignedMemory::DeallocBytes(memoryBuffer);
FAlignedMemory::DeallocBytes(cellMultipoles);
FAlignedMemory::DeallocBytes(cellLocals);
}
// Move the pointers to the correct position
allocatedMemoryInByte = (inAllocatedMemoryInByte);
memoryBuffer = (inBuffer);
blockHeader = reinterpret_cast<BlockHeader*>(inBuffer);
inBuffer += sizeof(BlockHeader);
cellSizes = reinterpret_cast<CellClassSizes*>(inBuffer);
inBuffer += sizeof(CellClassSizes);
blockIndexesTable = reinterpret_cast<int*>(inBuffer);
inBuffer += (blockHeader->blockIndexesTableSize*sizeof(int));
blockCells = reinterpret_cast<unsigned char*>(inBuffer);
inBuffer += (cellSizes->symbCellClassSize*blockHeader->numberOfCellsInBlock);
FAssertLF(size_t(inBuffer -memoryBuffer) == allocatedMemoryInByte);
cellMultipoles = inCellMultipoles;
cellLocals = inCellLocals;
deleteBuffer = (false);
}
/**
* Init from a given buffer
* @param inBuffer
* @param inAllocatedMemoryInByte
*/
FGroupOfCellsDyn(unsigned char* inBuffer, const size_t inAllocatedMemoryInByte,
unsigned char* inCellMultipoles, unsigned char* inCellLocals)
: allocatedMemoryInByte(inAllocatedMemoryInByte), memoryBuffer(inBuffer),
blockHeader(nullptr), cellSizes(nullptr), blockIndexesTable(nullptr), blockCells(nullptr),
cellMultipoles(nullptr), cellLocals(nullptr), deleteBuffer(false){
// Move the pointers to the correct position
allocatedMemoryInByte = (inAllocatedMemoryInByte);
memoryBuffer = (inBuffer);
blockHeader = reinterpret_cast<BlockHeader*>(inBuffer);
inBuffer += sizeof(BlockHeader);
cellSizes = reinterpret_cast<CellClassSizes*>(inBuffer);
inBuffer += sizeof(CellClassSizes);
blockIndexesTable = reinterpret_cast<int*>(inBuffer);
inBuffer += (blockHeader->blockIndexesTableSize*sizeof(int));
blockCells = reinterpret_cast<unsigned char*>(inBuffer);
inBuffer += (cellSizes->symbCellClassSize*blockHeader->numberOfCellsInBlock);
FAssertLF(size_t(inBuffer -memoryBuffer) == allocatedMemoryInByte);
cellMultipoles = inCellMultipoles;
cellLocals = inCellLocals;
}
/**
* @brief FGroupOfCellsDyn
* @param inStartingIndex first cell morton index
* @param inEndingIndex last cell morton index + 1
* @param inNumberOfCells total number of cells in the interval (should be <= inEndingIndex-inEndingIndex)
*/
FGroupOfCellsDyn(const MortonIndex inStartingIndex, const MortonIndex inEndingIndex, const int inNumberOfCells,
const size_t inSymbCellClassSize, const size_t inPoleCellClassSize, const size_t inLocalCellClassSize)
: allocatedMemoryInByte(0), memoryBuffer(nullptr), blockHeader(nullptr), cellSizes(nullptr),
blockIndexesTable(nullptr), blockCells(nullptr),
cellMultipoles(nullptr), cellLocals(nullptr), deleteBuffer(true){
// Find the number of cell to allocate in the blocks
const int blockIndexesTableSize = int(inEndingIndex-inStartingIndex);
FAssertLF(inNumberOfCells <= blockIndexesTableSize);
// Total number of bytes in the block
const size_t memoryToAlloc = sizeof(BlockHeader) + sizeof(CellClassSizes)
+ (blockIndexesTableSize*sizeof(int))
+ (inNumberOfCells*inSymbCellClassSize);
// Allocate
FAssertLF(0 <= int(memoryToAlloc) && int(memoryToAlloc) < std::numeric_limits<int>::max());
allocatedMemoryInByte = memoryToAlloc;
memoryBuffer = (unsigned char*)FAlignedMemory::AllocateBytes<32>(memoryToAlloc);
FAssertLF(memoryBuffer);
memset(memoryBuffer, 0, memoryToAlloc);
// Move the pointers to the correct position
unsigned char* bufferPtr = memoryBuffer;
blockHeader = reinterpret_cast<BlockHeader*>(bufferPtr);
bufferPtr += sizeof(BlockHeader);
cellSizes = reinterpret_cast<CellClassSizes*>(bufferPtr);
bufferPtr += sizeof(CellClassSizes);
blockIndexesTable = reinterpret_cast<int*>(bufferPtr);
bufferPtr += (blockIndexesTableSize*sizeof(int));
blockCells = reinterpret_cast<unsigned char*>(bufferPtr);
bufferPtr += (inNumberOfCells*inSymbCellClassSize);
FAssertLF(size_t(bufferPtr - memoryBuffer) == allocatedMemoryInByte);
// Init header
blockHeader->startingIndex = inStartingIndex;
blockHeader->endingIndex = inEndingIndex;
blockHeader->numberOfCellsInBlock = inNumberOfCells;
blockHeader->blockIndexesTableSize = blockIndexesTableSize;
cellSizes->symbCellClassSize = inSymbCellClassSize;
cellSizes->poleCellClassSize = inPoleCellClassSize;
cellSizes->localCellClassSize = inLocalCellClassSize;
cellMultipoles = (unsigned char*)FAlignedMemory::AllocateBytes<32>(inNumberOfCells*cellSizes->poleCellClassSize);
memset(cellMultipoles, 0, inNumberOfCells*cellSizes->poleCellClassSize);
cellLocals = (unsigned char*)FAlignedMemory::AllocateBytes<32>(inNumberOfCells*cellSizes->poleCellClassSize);
memset(cellLocals, 0, inNumberOfCells*cellSizes->poleCellClassSize);
// Set all index to not used
for(int idxCellPtr = 0 ; idxCellPtr < blockIndexesTableSize ; ++idxCellPtr){
blockIndexesTable[idxCellPtr] = CellIsEmptyFlag;
}
}
/** Call the destructor of cells and dealloc block memory */
~FGroupOfCellsDyn(){
if(deleteBuffer){
for(int idxCellPtr = 0 ; idxCellPtr < blockHeader->blockIndexesTableSize ; ++idxCellPtr){
if(blockIndexesTable[idxCellPtr] != CellIsEmptyFlag){
const int cellPos = blockIndexesTable[idxCellPtr];
CompositeCellClass cell(&blockCells[cellPos*cellSizes->symbCellClassSize],
&cellMultipoles[cellPos*cellSizes->poleCellClassSize],
&cellLocals[cellPos*cellSizes->localCellClassSize]);
cell.release();
}
}
FAlignedMemory::DeallocBytes(memoryBuffer);
FAlignedMemory::DeallocBytes(cellMultipoles);
FAlignedMemory::DeallocBytes(cellLocals);
}
}
/** Give access to the buffer to send the data */
const unsigned char* getRawBuffer() const{
return memoryBuffer;
}
/** The the size of the allocated buffer */
size_t getBufferSizeInByte() const {
return allocatedMemoryInByte;
}
/** Give access to the buffer to send the data */
const unsigned char* getRawMultipoleBuffer() const{
return cellMultipoles;
}
/** Give access to the buffer to send the data */
unsigned char* getRawMultipoleBuffer() {
return cellMultipoles;
}
/** The the size of the allocated buffer */
size_t getMultipoleBufferSizeInByte() const {
return cellSizes->poleCellClassSize*blockHeader->numberOfCellsInBlock;
}
/** Give access to the buffer to send the data */
unsigned char* getRawLocalBuffer(){
return cellLocals;
}
/** Give access to the buffer to send the data */
const unsigned char* getRawLocalBuffer() const{
return cellLocals;
}
/** The the size of the allocated buffer */
size_t getLocalBufferSizeInByte() const {
return cellSizes->localCellClassSize*blockHeader->numberOfCellsInBlock;
}
/** To know if the object will delete the memory block */
bool getDeleteMemory() const{
return deleteBuffer;
}
/** The index of the fist cell (set from the constructor) */
MortonIndex getStartingIndex() const {
return blockHeader->startingIndex;
}
/** The index of the last cell + 1 (set from the constructor) */
MortonIndex getEndingIndex() const {
return blockHeader->endingIndex;
}
/** The number of cell (set from the constructor) */
int getNumberOfCellsInBlock() const {
return blockHeader->numberOfCellsInBlock;
}
/** The size of the interval endingIndex-startingIndex (set from the constructor) */
int getSizeOfInterval() const {
return blockHeader->blockIndexesTableSize;
}
/** Return true if inIndex should be located in the current block */
bool isInside(const MortonIndex inIndex) const{
return blockHeader->startingIndex <= inIndex && inIndex < blockHeader->endingIndex;
}
/** Return true if inIndex is located in the current block and is not empty */
bool exists(const MortonIndex inIndex) const {
return isInside(inIndex) && (blockIndexesTable[inIndex-blockHeader->startingIndex] != CellIsEmptyFlag);
}
/** Return the address of the cell if it exists (or NULL) */
CompositeCellClass getCompleteCell(const MortonIndex inIndex){
FAssertLF(cellMultipoles && cellLocals);
if( exists(inIndex) ){
const int cellPos = blockIndexesTable[inIndex-blockHeader->startingIndex];
return CompositeCellClass(&blockCells[cellPos*cellSizes->symbCellClassSize],
&cellMultipoles[cellPos*cellSizes->poleCellClassSize],
&cellLocals[cellPos*cellSizes->localCellClassSize]);
}
else return CompositeCellClass();
}
/** Return the address of the cell if it exists (or NULL) */
CompositeCellClass getUpCell(const MortonIndex inIndex){
FAssertLF(cellMultipoles);
if( exists(inIndex) ){
const int cellPos = blockIndexesTable[inIndex-blockHeader->startingIndex];
return CompositeCellClass(&blockCells[cellPos*cellSizes->symbCellClassSize],
&cellMultipoles[cellPos*cellSizes->poleCellClassSize], nullptr);
}
else return CompositeCellClass();
}
/** Return the address of the cell if it exists (or NULL) */
CompositeCellClass getDownCell(const MortonIndex inIndex){
FAssertLF(cellLocals);
if( exists(inIndex) ){
const int cellPos = blockIndexesTable[inIndex-blockHeader->startingIndex];
return CompositeCellClass(&blockCells[cellPos*cellSizes->symbCellClassSize],
nullptr, &cellLocals[cellPos*cellSizes->localCellClassSize]);
}
else return CompositeCellClass();
}
/** Allocate a new cell by calling its constructor */
template<typename... CellConstructorParams>
void newCell(const MortonIndex inIndex, const int id, CellConstructorParams... args){
FAssertLF(isInside(inIndex));
FAssertLF(!exists(inIndex));
FAssertLF(id < blockHeader->blockIndexesTableSize);
CompositeCellClass cell(&blockCells[id*cellSizes->symbCellClassSize],
&cellMultipoles[id*cellSizes->poleCellClassSize],
&cellLocals[id*cellSizes->localCellClassSize]);
cell.init(args...);
blockIndexesTable[inIndex-blockHeader->startingIndex] = id;
}
/** Iterate on each allocated cells */
template<typename... FunctionParams>
void forEachCell(std::function<void(CompositeCellClass, FunctionParams...)> function, FunctionParams... args){
for(int idxCellPtr = 0 ; idxCellPtr < blockHeader->blockIndexesTableSize ; ++idxCellPtr){
if(blockIndexesTable[idxCellPtr] != CellIsEmptyFlag){
const int cellPos = blockIndexesTable[idxCellPtr];
function(CompositeCellClass(&blockCells[cellPos*cellSizes->symbCellClassSize],
&cellMultipoles[cellPos*cellSizes->poleCellClassSize],
&cellLocals[cellPos*cellSizes->localCellClassSize]), args...);
}
}
}
void forEachCell(std::function<void(CompositeCellClass)> function){
for(int idxCellPtr = 0 ; idxCellPtr < blockHeader->blockIndexesTableSize ; ++idxCellPtr){
if(blockIndexesTable[idxCellPtr] != CellIsEmptyFlag){
const int cellPos = blockIndexesTable[idxCellPtr];
function(CompositeCellClass(&blockCells[cellPos*cellSizes->symbCellClassSize],
&cellMultipoles[cellPos*cellSizes->poleCellClassSize],
&cellLocals[cellPos*cellSizes->localCellClassSize]));
}
}
}
};
#endif // FGROUPOFCELLSDYN_HPP
// @SCALFMM_PRIVATE
#ifndef FGROUPOFPARTICLESDYN_HPP
#define FGROUPOFPARTICLESDYN_HPP
#include "../../Utils/FGlobal.hpp"
#include "../../Utils/FAssert.hpp"
#include "../../Containers/FTreeCoordinate.hpp"
#include "../../Utils/FAlignedMemory.hpp"
#include "../StarPUUtils/FStarPUDefaultAlign.hpp"
#include <list>
#include <functional>
/**
* @brief The FGroupOfParticlesDyn class manages the leaves in block allocation.
*/
class FGroupOfParticlesDyn {
/** One header is allocated at the beginning of each block */
struct alignas(FStarPUDefaultAlign::StructAlign) BlockHeader{
MortonIndex startingIndex;
MortonIndex endingIndex;
int numberOfLeavesInBlock;
int blockIndexesTableSize;
size_t offsetSymbPart;
};
/** Information about a leaf */
struct alignas(FStarPUDefaultAlign::StructAlign) LeafHeader {
size_t offSetSymb;
size_t offSetDown;
size_t sizeSymb;
size_t sizeDown;
};
protected:
static const int MemoryAlignementBytes = FP2PDefaultAlignement;
//< This value is for not used leaves
static const int LeafIsEmptyFlag = -1;
//< The size of memoryBuffer in byte
size_t allocatedMemoryInByteSymb;
//< Pointer to a block memory
unsigned char* memoryBuffer;
//< Pointer to the header inside the block memory
BlockHeader* blockHeader;
//< Pointer to the indexes table inside the block memory
int* blockIndexesTable;
//< Pointer to leaves information
LeafHeader* leafHeader;
//< Pointers to particle position x, y, z
unsigned char* symbPart;
//< Pointers to the particles data inside the block memory
unsigned char* downPart;
size_t allocatedMemoryInByteDown;
/** To know if we have to delete the buffer */
bool deleteBuffer;
public:
/**
* Init from a given buffer
* @param inBuffer
* @param inAllocatedMemoryInByte
*/
FGroupOfParticlesDyn(unsigned char* inBuffer, const size_t inAllocatedMemoryInByte,
unsigned char* inAttributes)
: allocatedMemoryInByteSymb(inAllocatedMemoryInByte), memoryBuffer(inBuffer),
blockHeader(nullptr), blockIndexesTable(nullptr), leafHeader(nullptr), symbPart(nullptr),
downPart(nullptr), allocatedMemoryInByteDown(0), deleteBuffer(false){
// Move the pointers to the correct position
blockHeader = reinterpret_cast<BlockHeader*>(inBuffer);
inBuffer += sizeof(BlockHeader);
blockIndexesTable = reinterpret_cast<int*>(inBuffer);
inBuffer += (blockHeader->blockIndexesTableSize*sizeof(int));
leafHeader = reinterpret_cast<LeafHeader*>(inBuffer);
inBuffer += (sizeof(LeafHeader)*blockHeader->numberOfLeavesInBlock);
symbPart = reinterpret_cast<unsigned char*>(blockHeader)+blockHeader->offsetSymbPart;
downPart = inAttributes;
}
/**
* @brief FGroupOfParticlesDyn
* @param inStartingIndex first leaf morton index
* @param inEndingIndex last leaf morton index + 1
* @param inNumberOfLeaves total number of leaves in the interval (should be <= inEndingIndex-inEndingIndex)
*/
FGroupOfParticlesDyn(const MortonIndex inStartingIndex, const MortonIndex inEndingIndex, const int inNumberOfLeaves,
const size_t sizePerLeafSymb[], const size_t sizePerLeafDown[])
: allocatedMemoryInByteSymb(0), memoryBuffer(nullptr), blockHeader(nullptr), blockIndexesTable(nullptr), leafHeader(nullptr),
symbPart(nullptr), downPart(nullptr), allocatedMemoryInByteDown(0), deleteBuffer(true){
size_t totalSymb = 0;
size_t totalDown = 0;
for(int idxLeaf = 0 ; idxLeaf < inNumberOfLeaves ; ++idxLeaf){
totalSymb += sizePerLeafSymb[idxLeaf];
totalDown += sizePerLeafDown[idxLeaf];
}
// Find the number of leaf to allocate in the blocks
const int blockIndexesTableSize = int(inEndingIndex-inStartingIndex);
FAssertLF(inNumberOfLeaves <= blockIndexesTableSize);
// Total number of bytes in the block
const size_t memoryToAllocSymb = sizeof(BlockHeader)
+ (blockIndexesTableSize*sizeof(int))
+ (inNumberOfLeaves*sizeof(LeafHeader))
+ (totalSymb+MemoryAlignementBytes-1);
// Allocate
allocatedMemoryInByteSymb = memoryToAllocSymb;
memoryBuffer = (unsigned char*)FAlignedMemory::AllocateBytes<MemoryAlignementBytes>(memoryToAllocSymb);
FAssertLF(memoryBuffer);
memset(memoryBuffer, 0, memoryToAllocSymb);
allocatedMemoryInByteDown = totalDown;
downPart = (unsigned char*)FAlignedMemory::AllocateBytes<MemoryAlignementBytes>(allocatedMemoryInByteDown);
FAssertLF(downPart);
memset(downPart, 0, allocatedMemoryInByteDown);
// Move the pointers to the correct position
unsigned char* bufferPtr = memoryBuffer;
blockHeader = reinterpret_cast<BlockHeader*>(bufferPtr);
bufferPtr += sizeof(BlockHeader);
blockIndexesTable = reinterpret_cast<int*>(bufferPtr);
bufferPtr += (blockIndexesTableSize*sizeof(int));
leafHeader = reinterpret_cast<LeafHeader*>(bufferPtr);
bufferPtr += (inNumberOfLeaves*sizeof(LeafHeader));
symbPart = reinterpret_cast<unsigned char*>(size_t(bufferPtr+MemoryAlignementBytes-1) & ~size_t(MemoryAlignementBytes-1));
FAssertLF(size_t(bufferPtr-memoryBuffer) <= allocatedMemoryInByteSymb);
// Init header
blockHeader->startingIndex = inStartingIndex;
blockHeader->endingIndex = inEndingIndex;
blockHeader->numberOfLeavesInBlock = inNumberOfLeaves;
blockHeader->blockIndexesTableSize = blockIndexesTableSize;
blockHeader->offsetSymbPart = size_t(symbPart)-size_t(blockHeader);
if(inNumberOfLeaves){
leafHeader[0].sizeSymb = sizePerLeafSymb[0];
leafHeader[0].sizeDown = sizePerLeafDown[0];
leafHeader[0].offSetSymb = 0;
leafHeader[0].offSetDown = 0;
for(int idxLeaf = 1 ; idxLeaf < inNumberOfLeaves ; ++idxLeaf){
leafHeader[idxLeaf].sizeSymb = sizePerLeafSymb[idxLeaf];
leafHeader[idxLeaf].sizeDown = sizePerLeafDown[idxLeaf];
leafHeader[idxLeaf].offSetSymb = leafHeader[idxLeaf-1].sizeSymb + leafHeader[idxLeaf-1].offSetSymb;
leafHeader[idxLeaf].offSetDown = leafHeader[idxLeaf-1].sizeDown + leafHeader[idxLeaf-1].offSetDown;
}
FAssertLF(leafHeader[inNumberOfLeaves-1].offSetSymb+leafHeader[inNumberOfLeaves-1].sizeSymb == totalSymb);
FAssertLF(leafHeader[inNumberOfLeaves-1].offSetDown+leafHeader[inNumberOfLeaves-1].sizeDown == totalDown);
}
// Set all index to not used
for(int idxLeafPtr = 0 ; idxLeafPtr < blockIndexesTableSize ; ++idxLeafPtr){
blockIndexesTable[idxLeafPtr] = LeafIsEmptyFlag;
}
}
/** Call the destructor of leaves and dealloc block memory */
~FGroupOfParticlesDyn(){
if(deleteBuffer){
FAlignedMemory::DeallocBytes(memoryBuffer);
FAlignedMemory: