Commit 3e3c770a authored by BRAMAS Berenger's avatar BRAMAS Berenger
Browse files

Update Groupe tree to have another constructor with a left limite (mainly...

Update Groupe tree to have another constructor with a left limite (mainly usefull for the MPI version)
parent 26cf4840
......@@ -362,6 +362,198 @@ 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.
* If no limite give inLeftLimite = -1
*/
template<class ParticleContainer>
FGroupTree(const int inTreeHeight, const FReal inBoxWidth, const FPoint& inBoxCenter,
const int inNbElementsPerBlock, ParticleContainer* inParticlesContainer,
const bool particlesAreSorted, MortonIndex inLeftLimite):
treeHeight(inTreeHeight),nbElementsPerBlock(inNbElementsPerBlock),cellBlocksPerLevel(nullptr),
boxCenter(inBoxCenter), boxCorner(inBoxCenter,-(inBoxWidth/2)), boxWidth(inBoxWidth),
boxWidthAtLeafLevel(inBoxWidth/FReal(1<<(inTreeHeight-1))){
cellBlocksPerLevel = new std::vector<CellGroupClass*>[treeHeight];
MortonIndex* currentBlockIndexes = new MortonIndex[nbElementsPerBlock];
// First we work at leaf level
{
// Build morton index for particles
struct ParticleSortingStruct{
int originalIndex;
MortonIndex 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, int>::QsOmp(particlesToSort, nbParticles, [&](const ParticleSortingStruct& v1, const ParticleSortingStruct& v2){
return v1.mindex <= v2.mindex;
});
}
FAssertLF(nbParticles == 0 || inLeftLimite < particlesToSort[0].mindex);
// 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;
// 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;
}
while(lastParticle < nbParticles && currentBlockIndexes[sizeOfBlock-1] == particlesToSort[lastParticle].mindex){
nbParticlesPerLeaf[sizeOfBlock-1] += 1;
lastParticle += 1;
}
// Create a group
CellGroupClass*const newBlock = new CellGroupClass(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
size_t nbParticlesOffsetBeforeLeaf = 0;
int offsetParticles = firstParticle;
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
nbParticlesOffsetBeforeLeaf = newParticleBlock->newLeaf(currentBlockIndexes[cellIdInBlock], cellIdInBlock,
nbParticlesPerLeaf[cellIdInBlock], nbParticlesOffsetBeforeLeaf);
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 + offsetParticles].originalIndex, inParticlesContainer);
}
offsetParticles += 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){
inLeftLimite = (inLeftLimite == -1 ? inLeftLimite : (inLeftLimite>>3));
CellGroupConstIterator iterChildCells = cellBlocksPerLevel[idxLevel+1].begin();
const CellGroupConstIterator iterChildEndCells = cellBlocksPerLevel[idxLevel+1].end();
// Skip blocks that do not respect limit
while(iterChildCells != iterChildEndCells
&& ((*iterChildCells)->getEndingIndex()>>3) <= inLeftLimite){
++iterChildCells;
}
// If lower level is empty or all blocks skiped stop here
if(iterChildCells == iterChildEndCells){
break;
}
MortonIndex currentCellIndex = (*iterChildCells)->getStartingIndex();
if((currentCellIndex>>3) <= inLeftLimite) currentCellIndex = ((inLeftLimite+1)<<3);
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 && iterChildCells != iterChildEndCells ){
if((sizeOfBlock == 0 || currentBlockIndexes[sizeOfBlock-1] != (currentCellIndex>>3))
&& (*iterChildCells)->exists(currentCellIndex)){
currentBlockIndexes[sizeOfBlock] = (currentCellIndex>>3);
sizeOfBlock += 1;
currentCellIndex = (((currentCellIndex>>3)+1)<<3);
}
else{
currentCellIndex += 1;
}
// If we are at the end of the sub group, move to next
while(iterChildCells != iterChildEndCells && (*iterChildCells)->getEndingIndex() <= currentCellIndex){
++iterChildCells;
// Update morton index
if(iterChildCells != iterChildEndCells && currentCellIndex < (*iterChildCells)->getStartingIndex()){
currentCellIndex = (*iterChildCells)->getStartingIndex();
}
}
}
// If group is full
if(sizeOfBlock == nbElementsPerBlock || (sizeOfBlock && iterChildCells == iterChildEndCells)){
// Create a group
CellGroupClass*const newBlock = new CellGroupClass(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;
}
/** This function dealloc the tree by deleting each block */
~FGroupTree(){
for(int idxLevel = 0 ; idxLevel < treeHeight ; ++idxLevel){
......
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