Commit a6c704f8 authored by BRAMAS Berenger's avatar BRAMAS Berenger

Finished the group tree

parent 75044b07
......@@ -2,6 +2,7 @@
#define FGROUPATTACHEDLEAF_HPP
#include "../Utils/FGlobal.hpp"
#include "../Utils/FAssert.hpp"
/**
* This class is "attached" to a buffer.
......@@ -19,11 +20,13 @@ protected:
//< 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:
/** Empty constructor to point to nothing */
FGroupAttachedLeaf() : nbParticles(-1) {
memset(positionsPointers, 0, sizeof(FReal*) * 3);
memset(attributes, 0, sizeof(AttributeClass*) * NbAttributesPerParticle);
}
/**
* @brief FGroupAttachedLeaf
* @param inNbParticles the number of particles in the leaf
......@@ -41,9 +44,37 @@ public:
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);
for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
attributes[idxAttribute] = reinterpret_cast<AttributeClass*>(reinterpret_cast<unsigned char*>(inAttributesBuffer) + idxAttribute*inLeadingAttributes);
}
}
/** Copy the attached group to another one (copy the pointer not the content!) */
FGroupAttachedLeaf(const FGroupAttachedLeaf& other) : nbParticles(other.nbParticles) {
positionsPointers[0] = other.positionsPointers[0];
positionsPointers[1] = other.positionsPointers[1];
positionsPointers[2] = other.positionsPointers[2];
// Redirect pointers to data
for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
attributes[idxAttribute] = other.attributes[idxAttribute];
}
}
/** Copy the attached group to another one (copy the pointer not the content!) */
FGroupAttachedLeaf& operator=(const FGroupAttachedLeaf& other){
nbParticles = (other.nbParticles);
positionsPointers[0] = other.positionsPointers[0];
positionsPointers[1] = other.positionsPointers[1];
positionsPointers[2] = other.positionsPointers[2];
// Redirect pointers to data
for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
attributes[idxAttribute] = other.attributes[idxAttribute];
}
return (*this);
}
/**
......@@ -105,6 +136,42 @@ public:
static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
return attributes[index];
}
/** Return true if it has been attached to a memoy block */
bool isAttachedToSomething() const {
return nbParticles != -1;
}
/** Allocate a new leaf by calling its constructor */
template<class ParticleClassContainer>
void copyFromContainer(const ParticleClassContainer* particles, const int offsetInSrcContainer){
FAssertLF(isAttachedToSomething());
// Copy position
memcpy(positionsPointers[0], particles->getPositions()[0] + offsetInSrcContainer, nbParticles*sizeof(FReal));
memcpy(positionsPointers[1], particles->getPositions()[1] + offsetInSrcContainer, nbParticles*sizeof(FReal));
memcpy(positionsPointers[2], particles->getPositions()[2] + offsetInSrcContainer, nbParticles*sizeof(FReal));
// Copy data
for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
memcpy(attributes[idxAttribute], particles->getAttribute(idxAttribute) + offsetInSrcContainer, nbParticles*sizeof(AttributeClass));
}
}
/** Copy data for one particle (from the ParticleClassContainer into the attached buffer) */
template<class ParticleClassContainer>
void setParticle(const int destPartIdx, const int srcPartIdx, const ParticleClassContainer* particles){
// Copy position
positionsPointers[0][destPartIdx] = particles->getPositions()[0][srcPartIdx];
positionsPointers[1][destPartIdx] = particles->getPositions()[1][srcPartIdx];
positionsPointers[2][destPartIdx] = particles->getPositions()[2][srcPartIdx];
// Copy data
for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
attributes[idxAttribute][destPartIdx] = particles->getAttribute(idxAttribute)[srcPartIdx];
}
}
};
#endif // FGROUPATTACHEDLEAF_HPP
......@@ -152,25 +152,13 @@ public:
}
/** 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){
void newLeaf(const MortonIndex inIndex, const int id, const int nbParticles, const size_t offsetInGroup){
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 */
......@@ -192,16 +180,16 @@ public:
/** Return the address of the leaf if it exists (or NULL) */
template<class ParticlesAttachedClass>
ParticlesAttachedClass* getLeaf(const MortonIndex leafIndex){
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);
positionOffset,
particleAttributes[0] + leafHeader[id].offSet,
attributeOffset);
}
return NULL;
return ParticlesAttachedClass();
}
};
......
......@@ -2,16 +2,21 @@
#define FGROUPTREE_HPP
#include "../Utils/FAssert.hpp"
#include "../Utils/FPoint.hpp"
#include "../Utils/FQuickSort.hpp"
#include "../Containers/FTreeCoordinate.hpp"
#include "FGroupOfCells.hpp"
#include "FGroupOfParticles.hpp"
#include "FGroupAttachedLeaf.hpp"
#include <list>
#include <functional>
template <class CellClass, unsigned NbAttributesPerParticle, class AttributeClass = FReal>
class FGroupTree {
typedef FGroupAttachedLeaf<NbAttributesPerParticle,AttributeClass> BasicAttachedClass;
//< This value is for not used cells
static const int CellIsEmptyFlag = -1;
......@@ -25,6 +30,35 @@ protected:
//< all the blocks of leaves
std::list<FGroupOfParticles<NbAttributesPerParticle,AttributeClass>*> particleBlocks;
//< the space system center
const FPoint boxCenter;
//< the space system corner (used to compute morton index)
const FPoint boxCorner;
//< the space system width
const FReal boxWidth;
//< the width of a box at width level
const FReal boxWidthAtLeafLevel;
int getTreeCoordinate(const FReal inRelativePosition) const {
FAssertLF( (inRelativePosition >= 0 && inRelativePosition <= this->boxWidth), "inRelativePosition : ",inRelativePosition );
if(inRelativePosition == this->boxWidth){
return FMath::pow2(treeHeight-1)-1;
}
const FReal indexFReal = inRelativePosition / boxWidthAtLeafLevel;
return static_cast<int>(indexFReal);
}
FTreeCoordinate getCoordinateFromPosition(const FReal xpos,const FReal ypos,const FReal zpos) const {
// box coordinate to host the particle
FTreeCoordinate host;
// position has to be relative to corner not center
host.setX( getTreeCoordinate( xpos - this->boxCorner.getX() ));
host.setY( getTreeCoordinate( ypos - this->boxCorner.getY() ));
host.setZ( getTreeCoordinate( zpos - this->boxCorner.getZ() ));
return host;
}
public:
/** This constructor create a blocked octree from a usual octree
......@@ -34,7 +68,9 @@ public:
*/
template<class OctreeClass>
FGroupTree(const int inTreeHeight, const int inNbElementsPerBlock, OctreeClass*const inOctreeSrc)
: treeHeight(inTreeHeight), nbElementsPerBlock(inNbElementsPerBlock), cellBlocksPerLevel(0){
: treeHeight(inTreeHeight), nbElementsPerBlock(inNbElementsPerBlock), cellBlocksPerLevel(0),
boxCenter(inOctreeSrc->getBoxCenter()), boxCorner(inOctreeSrc->getBoxCenter(),-(inOctreeSrc->getBoxWidth()/2)),
boxWidth(inOctreeSrc->getBoxWidth()), boxWidthAtLeafLevel(inOctreeSrc->getBoxWidth()/FReal(1<<inTreeHeight)){
cellBlocksPerLevel = new std::list<FGroupOfCells<CellClass>*>[treeHeight];
// Iterate on the tree and build
......@@ -78,7 +114,10 @@ public:
// Add leaf
newParticleBlock->newLeaf(oldNode->getMortonIndex(), cellIdInBlock,
blockIteratorInOctree.getCurrentLeaf()->getSrc()->getNbParticles(),
nbParticlesBeforeLeaf, blockIteratorInOctree.getCurrentLeaf()->getSrc(), 0);
nbParticlesBeforeLeaf);
BasicAttachedClass attachedLeaf = newParticleBlock->template getLeaf<BasicAttachedClass>(oldNode->getMortonIndex());
attachedLeaf.copyFromContainer(blockIteratorInOctree.getCurrentLeaf()->getSrc(), 0);
nbParticlesBeforeLeaf += blockIteratorInOctree.getCurrentLeaf()->getSrc()->getNbParticles();
cellIdInBlock += 1;
......@@ -138,15 +177,185 @@ public:
}
/**
* This constructor create a group tree from a particle container index.
* The morton index are computed and the particles are sorted in a first stage.
* Then the leaf level is done.
* Finally the other leve are proceed one after the other.
* It should be easy to make it parallel using for and tasks.
*/
template<class ParticleContainer>
FGroupTree(const int inTreeHeight, const FReal inBoxWidth, const FPoint& inBoxCenter,
const int inNbElementsPerBlock, ParticleContainer* inParticlesContainer, const bool particlesAreSorted = false):
treeHeight(inTreeHeight),nbElementsPerBlock(inNbElementsPerBlock),cellBlocksPerLevel(0),
boxCenter(inBoxCenter), boxCorner(inBoxCenter,-(inBoxWidth/2)), boxWidth(inBoxWidth),
boxWidthAtLeafLevel(inBoxWidth/FReal(1<<inTreeHeight)){
cellBlocksPerLevel = new std::list<FGroupOfCells<CellClass>*>[treeHeight];
MortonIndex* currentBlockIndexes = new MortonIndex[nbElementsPerBlock];
// First we work at leaf level
{
// Build morton index for particles
struct ParticleSortingStruct{
int originalIndex;
MortonIndex mindex;
operator MortonIndex(){
return mindex;
}
};
// Convert position to morton index
const int nbParticles = inParticlesContainer->getNbParticles();
ParticleSortingStruct* particlesToSort = new ParticleSortingStruct[nbParticles];
{
const FReal* xpos = inParticlesContainer->getPositions()[0];
const FReal* ypos = inParticlesContainer->getPositions()[1];
const FReal* zpos = inParticlesContainer->getPositions()[2];
for(int idxPart = 0 ; idxPart < nbParticles ; ++idxPart){
const FTreeCoordinate host = getCoordinateFromPosition( xpos[idxPart], ypos[idxPart], zpos[idxPart] );
const MortonIndex particleIndex = host.getMortonIndex(treeHeight-1);
particlesToSort[idxPart].mindex = particleIndex;
particlesToSort[idxPart].originalIndex = idxPart;
}
}
// Sort if needed
if(particlesAreSorted == false){
FQuickSort<ParticleSortingStruct, MortonIndex, int>::QsOmp(particlesToSort, nbParticles);
}
// Convert to block
const int idxLevel = (treeHeight - 1);
int* nbParticlesPerLeaf = new int[nbElementsPerBlock];
int firstParticle = 0;
// We need to proceed each group in sub level
while(firstParticle != nbParticles){
int sizeOfBlock = 0;
int lastParticle = firstParticle + 1;
// Count until end of sub group is reached or we have enough cells
while(sizeOfBlock < nbElementsPerBlock && lastParticle < nbParticles){
if(sizeOfBlock == 0 || currentBlockIndexes[sizeOfBlock-1] != particlesToSort[lastParticle].mindex){
currentBlockIndexes[sizeOfBlock] = particlesToSort[lastParticle].mindex;
nbParticlesPerLeaf[sizeOfBlock] = 1;
sizeOfBlock += 1;
}
else{
nbParticlesPerLeaf[sizeOfBlock-1] += 1;
}
lastParticle += 1;
}
// Create a group
FGroupOfCells<CellClass>*const newBlock = new FGroupOfCells<CellClass>(currentBlockIndexes[0],
currentBlockIndexes[sizeOfBlock-1]+1,
sizeOfBlock);
FGroupOfParticles<NbAttributesPerParticle, AttributeClass>*const newParticleBlock = new FGroupOfParticles<NbAttributesPerParticle, AttributeClass>(currentBlockIndexes[0],
currentBlockIndexes[sizeOfBlock-1]+1,
sizeOfBlock, lastParticle-firstParticle);
// Init cells
int nbParticlesBeforeLeaf = 0;
for(int cellIdInBlock = 0; cellIdInBlock != sizeOfBlock ; ++cellIdInBlock){
newBlock->newCell(currentBlockIndexes[cellIdInBlock], cellIdInBlock);
CellClass* newNode = newBlock->getCell(currentBlockIndexes[cellIdInBlock]);
newNode->setMortonIndex(currentBlockIndexes[cellIdInBlock]);
FTreeCoordinate coord;
coord.setPositionFromMorton(currentBlockIndexes[cellIdInBlock], idxLevel);
newNode->setCoordinate(coord);
// Add leaf
newParticleBlock->newLeaf(currentBlockIndexes[cellIdInBlock], cellIdInBlock,
nbParticlesPerLeaf[cellIdInBlock], nbParticlesBeforeLeaf);
BasicAttachedClass attachedLeaf = newParticleBlock->template getLeaf<BasicAttachedClass>(currentBlockIndexes[cellIdInBlock]);
// Copy each particle from the original position
for(int idxPart = 0 ; idxPart < nbParticlesPerLeaf[cellIdInBlock] ; ++idxPart){
attachedLeaf.setParticle(idxPart, particlesToSort[idxPart + firstParticle].originalIndex, inParticlesContainer);
}
nbParticlesBeforeLeaf += nbParticlesPerLeaf[cellIdInBlock];
}
// Keep the block
cellBlocksPerLevel[idxLevel].push_back(newBlock);
particleBlocks.push_back(newParticleBlock);
sizeOfBlock = 0;
firstParticle = lastParticle;
}
delete[] nbParticlesPerLeaf;
delete[] particlesToSort;
}
// For each level from heigth - 2 to 1
for(int idxLevel = treeHeight-2; idxLevel > 0 ; --idxLevel){
typename std::list<FGroupOfCells<CellClass>*>::const_iterator iterChildCells = cellBlocksPerLevel[idxLevel+1].begin();
const typename std::list<FGroupOfCells<CellClass>*>::const_iterator iterChildEndCells = cellBlocksPerLevel[idxLevel+1].end();
MortonIndex currentCellIndex = (*iterChildCells)->getStartingIndex();
int sizeOfBlock = 0;
// We need to proceed each group in sub level
while(iterChildCells != iterChildEndCells){
// Count until end of sub group is reached or we have enough cells
while(sizeOfBlock < nbElementsPerBlock && currentCellIndex != (*iterChildCells)->getEndingIndex()){
if((sizeOfBlock == 0 || currentBlockIndexes[sizeOfBlock-1] != (currentCellIndex>>3))
&& (*iterChildCells)->exists(currentCellIndex)){
currentBlockIndexes[sizeOfBlock] = (currentCellIndex>>3);
sizeOfBlock += 1;
}
currentCellIndex += 1;
}
// If we are at the end of the sub group, move to next
if(currentCellIndex == (*iterChildCells)->getEndingIndex()){
++iterChildCells;
// Update morton index
if(iterChildCells != iterChildEndCells){
currentCellIndex = (*iterChildCells)->getStartingIndex();
}
}
// If group is full
if(sizeOfBlock == nbElementsPerBlock || (sizeOfBlock && iterChildCells == iterChildEndCells)){
// Create a group
FGroupOfCells<CellClass>*const newBlock = new FGroupOfCells<CellClass>(currentBlockIndexes[0],
currentBlockIndexes[sizeOfBlock-1]+1,
sizeOfBlock);
// Init cells
for(int cellIdInBlock = 0; cellIdInBlock != sizeOfBlock ; ++cellIdInBlock){
newBlock->newCell(currentBlockIndexes[cellIdInBlock], cellIdInBlock);
CellClass* newNode = newBlock->getCell(currentBlockIndexes[cellIdInBlock]);
newNode->setMortonIndex(currentBlockIndexes[cellIdInBlock]);
FTreeCoordinate coord;
coord.setPositionFromMorton(currentBlockIndexes[cellIdInBlock], idxLevel);
newNode->setCoordinate(coord);
}
// Keep the block
cellBlocksPerLevel[idxLevel].push_back(newBlock);
sizeOfBlock = 0;
}
}
}
delete[] currentBlockIndexes;
}
////////////////////////////////////////////////////////////////////
// Work in progress part, build the tree from an array of particles
// Can be deleted
////////////////////////////////////////////////////////////////////
/** @brief This private method take an array of Morton index to
* create the block and the cells, using the constructor of
* FGroupOfCells !!
*/
FGroupOfCells<CellClass> * createBlockFromArray(MortonIndex head[]){
/*FGroupOfCells<CellClass> * createBlockFromArray(MortonIndex head[]){
//Store the start and end
MortonIndex start = head[0];
MortonIndex end = start;
......@@ -170,13 +379,13 @@ public:
//(this->getCell(head[idx]))->setCoordinate();
}
return newBlock;
}
}*/
/** This constructor build the BlockOctree from an Octree, but only
* the cells at leaf level are read. The cells ares constructed with
* several walk through the leafs.
*/
template<class OctreeClass>
/*template<class OctreeClass>
FGroupTree(const int inTreeHeight, const int inNbElementsPerBlock, OctreeClass*const inOctreeSrc, int FLAG):
treeHeight(inTreeHeight),nbElementsPerBlock(inNbElementsPerBlock),cellBlocksPerLevel(0)
{
......@@ -271,10 +480,10 @@ public:
}
printf("toto \n");
delete[] head;
}
}*/
////////////////////////////////////////////////////////////////////
// End work in progress part, build the tree from an array of particles
// End of can be deleted
////////////////////////////////////////////////////////////////////
......@@ -349,8 +558,8 @@ public:
while(iterCells != iterEndCells && iterLeaves != iterEndLeaves){
(*iterCells)->forEachCell([&](CellClass* aCell){
ParticlesAttachedClass*const aLeaf = (*iterLeaves)->getLeaf(aCell->getMortonIndex());
FAssertLF(aLeaf);
ParticlesAttachedClass aLeaf = (*iterLeaves)->getLeaf(aCell->getMortonIndex());
FAssertLF(aLeaf.isAttachedToSomething());
function(aCell, aLeaf);
delete aLeaf;
});
......
......@@ -45,29 +45,30 @@ int main(int argc, char* argv[]){
OctreeClass tree(NbLevels, SizeSubLevels, loader.getBoxWidth(), loader.getCenterOfBox());
FP2PParticleContainer<> allParticles;
for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
FPoint particlePosition;
FReal physicalValue;
loader.fillParticle(&particlePosition,&physicalValue);
tree.insert(particlePosition, physicalValue );
allParticles.push(particlePosition, physicalValue);
}
std::cout << "Done " << "(@Creating and Inserting Particles = " << counter.tacAndElapsed() << "s)." << std::endl;
const int groupSize = FParameters::getValue(argc,argv,"-bs", 250);
counter.tic();
GroupOctreeClass groupedTree(NbLevels, groupSize, &tree, 0);
std::cout << "Done " << "(@Converting the tree with leafs only = " << counter.tacAndElapsed() << "s). Group size is " << groupSize << "." << std::endl;
counter.tic();
GroupOctreeClass groupedTree2(NbLevels, groupSize, &tree);
std::cout << "Done " << "(@Converting the tree with all Octree = " << counter.tacAndElapsed() << "s). Group size is " << groupSize << "." << std::endl;
counter.tic();
GroupOctreeClass groupedTree3(NbLevels, loader.getBoxWidth(), loader.getCenterOfBox(), groupSize, &allParticles);
std::cout << "Done " << "(@Converting the tree with all Octree = " << counter.tacAndElapsed() << "s). Group size is " << groupSize << "." << std::endl;
groupedTree.printInfoBlocks();
groupedTree2.printInfoBlocks();
groupedTree3.printInfoBlocks();
return 0;
}
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