Commit 7c386566 authored by BRAMAS Berenger's avatar BRAMAS Berenger

Create real class for grouped tree

parent 02106a6d
#ifndef FGROUPATTACHEDLEAF_HPP
#define FGROUPATTACHEDLEAF_HPP
#include "../Utils/FGlobal.hpp"
/**
* This class is "attached" to a buffer.
* It is a wrapper/interface to a memory area that stores all the particles info.
* The idea is to hidde the group allocation from the group tree but
* to keep the same interface than the FBasicParticlesContainer.
*/
template <unsigned NbAttributesPerParticle, class AttributeClass = FReal>
class FGroupAttachedLeaf {
protected:
//< Nb of particles in the current leaf
const int nbParticles;
//< Pointers to the positions of the particles
FReal* positionsPointers[3];
//< Pointers to the attributes of the particles
AttributeClass* attributes[NbAttributesPerParticle];
// Forbid copy even if there is no real reason to do that
FGroupAttachedLeaf(const FGroupAttachedLeaf&) = delete;
FGroupAttachedLeaf& operator=(const FGroupAttachedLeaf&) = delete;
public:
/**
* @brief FGroupAttachedLeaf
* @param inNbParticles the number of particles in the leaf
* @param inPositionBuffer the memory address of the X array of particls
* @param inLeadingPosition each position is access by inPositionBuffer + in bytes inLeadingPosition*idx
* @param inAttributesBuffer the memory address of the first attribute
* @param inLeadingAttributes each attribute is access by inAttributesBuffer + in bytes inLeadingAttributes*idx
*/
FGroupAttachedLeaf(const int inNbParticles, FReal* inPositionBuffer, const size_t inLeadingPosition,
AttributeClass* inAttributesBuffer, const size_t inLeadingAttributes)
: nbParticles(inNbParticles){
// Redirect pointers to position
positionsPointers[0] = inPositionBuffer;
positionsPointers[1] = reinterpret_cast<FReal*>(reinterpret_cast<unsigned char*>(inPositionBuffer) + inLeadingPosition);
positionsPointers[2] = reinterpret_cast<FReal*>(reinterpret_cast<unsigned char*>(inPositionBuffer) + inLeadingPosition*2);
// Redirect pointers to data
for(int idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
particleAttributes[idxAttribute] = reinterpret_cast<AttributeClass*>(reinterpret_cast<unsigned char*>(inAttributesBuffer) + idxAttribute*inLeadingAttributes);
}
}
/**
* @brief getNbParticles
* @return the number of particles in the leaf
*/
int getNbParticles() const{
return nbParticles;
}
/**
* @brief getPositions
* @return a FReal*[3] to get access to the positions
*/
const FReal*const* getPositions() const {
return positionsPointers;
}
/**
* @brief getWPositions
* @return get the position in write mode
*/
FReal* const* getWPositions() {
return positionsPointers;
}
/**
* @brief getAttribute
* @param index
* @return the attribute at index index
*/
AttributeClass* getAttribute(const int index) {
return attributes[index];
}
/**
* @brief getAttribute
* @param index
* @return
*/
const AttributeClass* getAttribute(const int index) const {
return attributes[index];
}
/**
* Get the attribute with a forcing compile optimization
*/
template <int index>
AttributeClass* getAttribute() {
static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
return attributes[index];
}
/**
* Get the attribute with a forcing compile optimization
*/
template <int index>
const AttributeClass* getAttribute() const {
static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
return attributes[index];
}
};
#endif // FGROUPATTACHEDLEAF_HPP
#ifndef FGROUPOFCELLS_HPP
#define FGROUPOFCELLS_HPP
#include "../Utils/FAssert.hpp"
#include "../Containers/FTreeCoordinate.hpp"
#include <list>
#include <functional>
/**
* @brief The FGroupOfCells class manages the cells in block allocation.
*/
template <class CellClass>
class FGroupOfCells {
/** One header is allocated at the beginning of each block */
struct BlockHeader{
MortonIndex startingIndex;
MortonIndex endingIndex;
int numberOfCellsInBlock;
int blockIndexesTableSize;
};
protected:
//< 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 the cells inside the block memory
CellClass* blockCells;
//< This value is for not used cells
static const MortonIndex CellIsEmptyFlag = -1;
public:
/**
* @brief FGroupOfCells
* @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)
*/
FGroupOfCells(const MortonIndex inStartingIndex, const MortonIndex inEndingIndex, const int inNumberOfCells)
: memoryBuffer(0), blockHeader(0), blockIndexesTable(0), blockCells(0) {
// 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) + (blockIndexesTableSize*sizeof(int)) + (inNumberOfCells*sizeof(CellClass));
// Allocate
memoryBuffer = new unsigned char[memoryToAlloc];
FAssertLF(memoryBuffer);
memset(memoryBuffer, 0, memoryToAlloc);
// Move the pointers to the correct position
blockHeader = reinterpret_cast<BlockHeader*>(memoryBuffer);
blockIndexesTable = reinterpret_cast<int*>(memoryBuffer+sizeof(BlockHeader));
blockCells = reinterpret_cast<CellClass*>(memoryBuffer+sizeof(BlockHeader)+(blockIndexesTableSize*sizeof(int)));
// Init header
blockHeader->startingIndex = inStartingIndex;
blockHeader->endingIndex = inEndingIndex;
blockHeader->numberOfCellsInBlock = inNumberOfCells;
blockHeader->blockIndexesTableSize = blockIndexesTableSize;
// 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 */
~FGroupOfCells(){
for(int idxCellPtr = 0 ; idxCellPtr < blockHeader->blockIndexesTableSize ; ++idxCellPtr){
if(blockIndexesTable[idxCellPtr] != CellIsEmptyFlag){
(&blockCells[blockIndexesTable[idxCellPtr]])->~CellClass();
}
}
delete[] memoryBuffer;
}
/** 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) */
CellClass* getCell(const MortonIndex inIndex){
if( exists(inIndex) ) return &blockCells[blockIndexesTable[inIndex-blockHeader->startingIndex]];
else return 0;
}
/** Return the address of the cell if it exists (or NULL) */
const CellClass* getCell(const MortonIndex inIndex) const {
if( exists(inIndex) ) return &blockCells[blockIndexesTable[inIndex-blockHeader->startingIndex]];
else return 0;
}
/** 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);
new((void*)&blockCells[id]) CellClass(args...);
blockIndexesTable[inIndex-blockHeader->startingIndex] = id;
}
/** Iterate on each allocated cells */
template<typename... FunctionParams>
void forEachCell(std::function<void(CellClass*)> function, FunctionParams... args){
for(int idxCellPtr = 0 ; idxCellPtr < blockHeader->blockIndexesTableSize ; ++idxCellPtr){
if(blockIndexesTable[idxCellPtr] != CellIsEmptyFlag){
function(&blockCells[blockIndexesTable[idxCellPtr]], args...);
}
}
}
};
#endif // FGROUPOFCELLS_HPP
#ifndef FGROUPOFPARTICLES_HPP
#define FGROUPOFPARTICLES_HPP
#include "../Utils/FAssert.hpp"
#include "../Containers/FTreeCoordinate.hpp"
#include <list>
#include <functional>
/**
* @brief The FGroupOfParticles class manages the leaves in block allocation.
*/
template <unsigned NbAttributesPerParticle, class AttributeClass = FReal>
class FGroupOfParticles {
/** One header is allocated at the beginning of each block */
struct BlockHeader{
MortonIndex startingIndex;
MortonIndex endingIndex;
int numberOfLeavesInBlock;
int blockIndexesTableSize;
};
/** Information about a leaf */
struct LeafHeader {
int nbParticles;
size_t offSet;
};
protected:
//< 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;
//< The total number of particles in the group
const int nbParticlesInGroup;
//< Pointers to particle position x, y, z
FReal* particlePosition[3];
//< Bytes difference/offset between position
size_t positionOffset;
//< Pointers to the particles data inside the block memory
AttributeClass* particleAttributes[NbAttributesPerParticle];
//< Bytes difference/offset between attributes
size_t attributeOffset;
//< This value is for not used leaves
static const MortonIndex LeafIsEmptyFlag = -1;
public:
/**
* @brief FGroupOfParticles
* @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)
*/
FGroupOfParticles(const MortonIndex inStartingIndex, const MortonIndex inEndingIndex, const int inNumberOfLeaves, const int inNbParticles)
: memoryBuffer(0), blockHeader(0), blockIndexesTable(0), leafHeader(0), nbParticlesInGroup(inNbParticles),
positionOffset(0), attributeOffset(0) {
memset(particlePosition, 0, sizeof(particlePosition));
memset(particleAttributes, 0, sizeof(particleAttributes));
// 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 sizeOfOneParticle = (3*sizeof(FReal) + NbAttributesPerParticle*sizeof(AttributeClass));
const size_t memoryToAlloc = sizeof(BlockHeader) + (blockIndexesTableSize*sizeof(int)) + (inNumberOfLeaves*sizeof(LeafHeader))
+ inNbParticles*sizeOfOneParticle;
// Allocate
memoryBuffer = new unsigned char[memoryToAlloc];
FAssertLF(memoryBuffer);
memset(memoryBuffer, 0, memoryToAlloc);
// Move the pointers to the correct position
blockHeader = reinterpret_cast<BlockHeader*>(memoryBuffer);
blockIndexesTable = reinterpret_cast<int*>(memoryBuffer+sizeof(BlockHeader));
leafHeader = reinterpret_cast<LeafHeader*>(memoryBuffer+sizeof(BlockHeader)+(blockIndexesTableSize*sizeof(int)));
// Init header
blockHeader->startingIndex = inStartingIndex;
blockHeader->endingIndex = inEndingIndex;
blockHeader->numberOfLeavesInBlock = inNumberOfLeaves;
blockHeader->blockIndexesTableSize = blockIndexesTableSize;
// Init particle pointers
positionOffset = (sizeof(FReal) * inNbParticles);
particlePosition[0] = reinterpret_cast<FReal*>(leafHeader + inNumberOfLeaves);
particlePosition[1] = (particlePosition[0] + inNbParticles);
particlePosition[2] = (particlePosition[1] + inNbParticles);
// Redirect pointer to data
attributeOffset = (sizeof(AttributeClass) * inNbParticles);
unsigned char* previousPointer = reinterpret_cast<unsigned char*>(particlePosition[2] + inNbParticles);
for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
particleAttributes[idxAttribute] = reinterpret_cast<AttributeClass*>(previousPointer);
previousPointer += sizeof(AttributeClass)*inNbParticles;
}
// 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 */
~FGroupOfParticles(){
delete[] memoryBuffer;
}
/** The index of the fist leaf (set from the constructor) */
MortonIndex getStartingIndex() const {
return blockHeader->startingIndex;
}
/** The index of the last leaf + 1 (set from the constructor) */
MortonIndex getEndingIndex() const {
return blockHeader->endingIndex;
}
/** The number of leaf (set from the constructor) */
int getNumberOfLeavesInBlock() const {
return blockHeader->numberOfLeavesInBlock;
}
/** Get the total number of particles in the group */
int getNbParticlesInGroup() const {
return nbParticlesInGroup;
}
/** 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] != LeafIsEmptyFlag);
}
/** Allocate a new leaf by calling its constructor */
template<class ParticleClassContainer>
void newLeaf(const MortonIndex inIndex, const int id, const int nbParticles, const size_t offsetInGroup,
const ParticleClassContainer* particles, const int offsetInSrcContainer){
FAssertLF(isInside(inIndex));
FAssertLF(!exists(inIndex));
FAssertLF(id < blockHeader->blockIndexesTableSize);
blockIndexesTable[inIndex-blockHeader->startingIndex] = id;
leafHeader[id].nbParticles = nbParticles;
leafHeader[id].offSet = offsetInGroup;
// Copy position
memcpy(particlePosition[0] + offsetInGroup, particles->getPositions()[0] + offsetInSrcContainer, nbParticles*sizeof(FReal));
memcpy(particlePosition[1] + offsetInGroup, particles->getPositions()[1] + offsetInSrcContainer, nbParticles*sizeof(FReal));
memcpy(particlePosition[2] + offsetInGroup, particles->getPositions()[2] + offsetInSrcContainer, nbParticles*sizeof(FReal));
// Copy data
for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
memcpy(particleAttributes[idxAttribute] + offsetInGroup, particles->getAttribute(idxAttribute) + offsetInSrcContainer, nbParticles*sizeof(AttributeClass));
}
}
/** Iterate on each allocated leaves */
template<class ParticlesAttachedClass>
void forEachLeaf(std::function<void(ParticlesAttachedClass*)> function){
for(int idxLeafPtr = 0 ; idxLeafPtr < blockHeader->blockIndexesTableSize ; ++idxLeafPtr){
if(blockIndexesTable[idxLeafPtr] != LeafIsEmptyFlag){
const int id = blockIndexesTable[idxLeafPtr];
ParticlesAttachedClass leaf(leafHeader[id].nbParticles,
particlePosition[0] + leafHeader[id].offSet,
positionOffset,
particleAttributes[0] + leafHeader[id].offSet,
attributeOffset);
function(&leaf);
}
}
}
/** Return the address of the leaf if it exists (or NULL) */
template<class ParticlesAttachedClass>
ParticlesAttachedClass* getLeaf(const MortonIndex leafIndex){
if(blockIndexesTable[leafIndex - blockHeader->startingIndex] != LeafIsEmptyFlag){
const int id = blockIndexesTable[leafIndex - blockHeader->startingIndex];
return ParticlesAttachedClass(leafHeader[id].nbParticles,
particlePosition[0] + leafHeader[id].offSet,
positionOffset,
particleAttributes[0] + leafHeader[id].offSet,
attributeOffset);
}
return NULL;
}
};
#endif // FGROUPOFPARTICLES_HPP
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment