MAJ terminée. Nous sommes passés en version 14.6.2 . Pour consulter les "releases notes" associées c'est ici :

https://about.gitlab.com/releases/2022/01/11/security-release-gitlab-14-6-2-released/
https://about.gitlab.com/releases/2022/01/04/gitlab-14-6-1-released/

Commit 9296784b authored by BRAMAS Berenger's avatar BRAMAS Berenger
Browse files

Update the thread tree builder and add an example

parent dd19bd5e
......@@ -15,23 +15,28 @@
// ===================================================================================
#ifndef FTREEBUILDER_H
#define FTREEBUILDER_H
#include <omp.h>
#include "ScalFmmConfig.h"
#include "../Utils/FLog.hpp"
#include "../Utils/FQuickSort.hpp"
#include "../Utils/FTic.hpp"
#include "../Utils/FAssert.hpp"
#include "../Containers/FOctree.hpp"
#include "ScalFmmConfig.h"
#include "../Components/FBasicParticleContainer.hpp"
#include <omp.h>
#include <memory>
/**
* @author Cyrille Piacibello
* @author Cyrille Piacibello, Berenger Bramas
* @class FTreeBuilder
* @brief
* Please read the license
*
* This class provides a way to insert efficiently large amount of
* particles inside a tree.
* This class provides a way to insert efficiently large amount of particles inside a tree.
*
* This is a static class. It's useless to instance it. This class use
* the Threaded QuickSort or the output of FMpiTreeBuilder in order to
......@@ -39,216 +44,205 @@
*
*/
template<class ParticleClass, class OctreeClass, class LeafClass>
template<class OctreeClass, class LeafClass>
class FTreeBuilder{
private:
/**
* This method has been taken from the octree class,
* it computes a tree coordinate (x or y or z) from real cartesian position
*/
static int GetTreeCoordinate(const FReal inRelativePosition, const FReal boxWidthAtLeafLevel,
const FReal boxWidth, const int height) {
FAssertLF( (inRelativePosition >= 0 && inRelativePosition <= boxWidth), "inRelativePosition : ",inRelativePosition );
if(inRelativePosition == boxWidth){
return FMath::pow2(height-1)-1;
}
const FReal indexFReal = inRelativePosition / boxWidthAtLeafLevel;
return static_cast<int>(indexFReal);
const FReal boxWidth, const int height) {
FAssertLF( (inRelativePosition >= 0 && inRelativePosition <= boxWidth), "inRelativePosition : ",inRelativePosition );
if(inRelativePosition == boxWidth){
return FMath::pow2(height-1)-1;
}
const FReal indexFReal = inRelativePosition / boxWidthAtLeafLevel;
return static_cast<int>(indexFReal);
}
/**
* A particle may not have a MortonIndex Method (set/get morton
* index) But in this algorithm they are sorted based on their
* morton indexes. So an IndexedParticle is storing a real
* particle + its index.
*
*/
/** This class is the relation between particles and their morton idx */
struct IndexedParticle{
public:
MortonIndex index;
ParticleClass particle;
operator MortonIndex() const {
return this->index;
}
bool operator<=(const IndexedParticle& rhs){
return this->index <= rhs.index;
}
MortonIndex mindex;
int particlePositionInArray;
// To sort according to the mindex
bool operator<=(const IndexedParticle& rhs) const {
return this->mindex <= rhs.mindex;
}
};
public:
/**
*
* Fill the tree with the parts from the array.
* The Particles must provide a getPosition and a getPhysicalValue(), method.
*/
template<class ContainerClass>
static void BuildTreeFromArray(ContainerClass* arrayToBeInserted, const FSize numberOfParticle, OctreeClass * tree,
bool isAlreadySorted=false){
//If the parts are already sorted, no need to sort again
FLOG(FTic enumTimer);
FLOG(FTic leavesPtr);
FLOG(FTic leavesOffset);
FLOG(FTic insertTimer);
FLOG(FTic copyTimer);
FLOG(FTic sortTimer);
//General values needed
int NbLevels = tree->getHeight();
FPoint centerOfBox = tree->getBoxCenter();
FReal boxWidth = tree->getBoxWidth();
FReal boxWidthAtLeafLevel = boxWidth/FReal(1 << (NbLevels - 1));
FPoint boxCorner = centerOfBox - boxWidth/2;
//We need to sort it in order to insert efficiently
//First, copy datas into an array that will be sorted and
//set Morton index for each particle
//Temporary FTreeCoordinate
FTreeCoordinate host;
IndexedParticle * toBeSorted = new IndexedParticle[numberOfParticle];
//Things to keep
FPoint* posToBeIn = new FPoint[numberOfParticle];
FReal * phyToBeIn = new FReal[numberOfParticle];
FLOG(copyTimer.tic());
for(int idxParts=0; idxParts<numberOfParticle ; ++idxParts ){
toBeSorted[idxParts].particle = arrayToBeInserted->data()[idxParts];
host.setX( GetTreeCoordinate(arrayToBeInserted->data()[idxParts].getPosition().getX() - boxCorner.getX(),
boxWidthAtLeafLevel, boxWidth, NbLevels));
host.setY( GetTreeCoordinate(arrayToBeInserted->data()[idxParts].getPosition().getY() - boxCorner.getY(),
boxWidthAtLeafLevel, boxWidth, NbLevels ));
host.setZ( GetTreeCoordinate(arrayToBeInserted->data()[idxParts].getPosition().getZ() - boxCorner.getZ(),
boxWidthAtLeafLevel, boxWidth, NbLevels ));
toBeSorted[idxParts].index = host.getMortonIndex(NbLevels-1);
}
FLOG(copyTimer.tac());
FLOG(FLog::Controller<<"Time needed for copying "<< numberOfParticle<<" particles : "<<copyTimer.elapsed() << " secondes !\n");
if(!isAlreadySorted){
//Sort dat array
FLOG(sortTimer.tic());
FQuickSort<IndexedParticle,MortonIndex>::QsOmp(toBeSorted,numberOfParticle);
FLOG(sortTimer.tac());
FLOG(FLog::Controller << "Time needed for sorting the particles : "<< sortTimer.elapsed() << " secondes !\n");
}
//Enumerate the different leaves AND copy the positions
unsigned int numberOfLeaves = 1;
FLOG(enumTimer.tic());
//First Values are copied
posToBeIn[0] = toBeSorted[0].particle.getPosition();
phyToBeIn[0] = toBeSorted[0].particle.getPhysicalValue();
for(int idxParts = 1 ; idxParts < numberOfParticle ; ++idxParts){
//Copy
posToBeIn[idxParts] = toBeSorted[idxParts].particle.getPosition();
phyToBeIn[idxParts] = toBeSorted[idxParts].particle.getPhysicalValue();
if(toBeSorted[idxParts].index != toBeSorted[idxParts-1].index){
numberOfLeaves++;
}
}
FLOG(enumTimer.tac());
FLOG(FLog::Controller << "Time needed for enumerate the leaves : "<< enumTimer.elapsed() << " secondes !\n");
FLOG(FLog::Controller << "Found " << numberOfLeaves << " leaves differents. \n");
//Store the size of each leaves
int * arrayOfSizeNbLeaves = new int[numberOfLeaves];
memset(arrayOfSizeNbLeaves,0,sizeof(int)*(numberOfLeaves));
//Init
int indexInLeafArray = -1;
arrayOfSizeNbLeaves[0] = 1;
FLOG(leavesOffset.tic());
MortonIndex currIndex = -1;
for(int idxParts = 0 ; idxParts < numberOfParticle ; ++idxParts){
if(toBeSorted[idxParts].index == currIndex){
arrayOfSizeNbLeaves[indexInLeafArray]++;
}
else{
FAssertLF(FSize(indexInLeafArray)<numberOfLeaves,"Problem there : ",indexInLeafArray);
indexInLeafArray++;
//There is alway at least 1 part in each leaf
arrayOfSizeNbLeaves[indexInLeafArray] = 1;
currIndex = toBeSorted[idxParts].index;
}
}
//Debug
int acc = 0;
for(unsigned int i=0 ; i<numberOfLeaves ; ++i){
//printf("acc : %d arrayofsize[%d] = %d \n",acc,i,arrayOfSizeNbLeaves[i]);
acc += arrayOfSizeNbLeaves[i];
}
printf("Tot : %d/%lld\n",acc,numberOfParticle);
FLOG(leavesOffset.tac());
FLOG(FLog::Controller << "Time needed for setting the offset of each leaves : "<< leavesOffset.elapsed() << " secondes !\n");
//Then, we create the leaves inside the tree
//Idx of the first part in this leaf in the array of part
int idxOfFirstPartInLeaf = 0;
//struct to store leaves and idx
struct LeafToFill{
LeafClass * leaf;
FSize idxOfLeafInPartArray;
};
FLOG(leavesPtr.tic());
LeafToFill * leavesToFill = new LeafToFill[numberOfLeaves];
memset(leavesToFill,0,sizeof(struct LeafToFill)*numberOfLeaves);
for(FSize idxLeaf = 0; idxLeaf < numberOfLeaves ; ++idxLeaf){
leavesToFill[idxLeaf].leaf = tree->createLeaf(toBeSorted[idxOfFirstPartInLeaf].index);
leavesToFill[idxLeaf].idxOfLeafInPartArray = idxOfFirstPartInLeaf;
idxOfFirstPartInLeaf += arrayOfSizeNbLeaves[idxLeaf];
}
FLOG(leavesPtr.tac());
FLOG(FLog::Controller << "Time needed for creating empty leaves : "<< leavesPtr.elapsed() << " secondes !\n");
/** In order to keep all the created leaves */
struct LeafDescriptor{
LeafClass* leafPtr;
FSize offsetInArray;
int nbParticlesInLeaf;
};
public:
FLOG(insertTimer.tic());
//Copy each parts into corresponding Leaf
#pragma omp parallel for schedule(auto)
for(FSize idxLeaf=0 ; idxLeaf<numberOfLeaves ; ++idxLeaf ){
//Task consists in copy the parts inside the leaf
leavesToFill[idxLeaf].leaf->pushArray(&posToBeIn[leavesToFill[idxLeaf].idxOfLeafInPartArray],
arrayOfSizeNbLeaves[idxLeaf],
&phyToBeIn[leavesToFill[idxLeaf].idxOfLeafInPartArray]);
}
FLOG(insertTimer.tac());
FLOG(FLog::Controller << "Time needed for inserting the parts into the leaves : "<< insertTimer.elapsed() << " secondes !\n");
//Clean the mess
delete [] leavesToFill;
delete [] arrayOfSizeNbLeaves;
delete [] posToBeIn;
delete [] phyToBeIn;
delete [] toBeSorted;
/** Should be used to insert a FBasicParticleContainer class */
template < unsigned NbAttributes, class AttributeClass>
static void BuildTreeFromArray(OctreeClass*const tree, const FBasicParticleContainer<NbAttributes, AttributeClass>& particlesContainers,
bool isAlreadySorted=false){
const FSize numberOfParticle = particlesContainers.getNbParticles();
// If the parts are already sorted, no need to sort again
FLOG(FTic enumTimer, leavesPtr, leavesOffset );
FLOG(FTic insertTimer, copyTimer);
// General values needed
const int NbLevels = tree->getHeight();
const FPoint centerOfBox = tree->getBoxCenter();
const FReal boxWidth = tree->getBoxWidth();
const FReal boxWidthAtLeafLevel = boxWidth/FReal(1 << (NbLevels - 1));
const FPoint boxCorner = centerOfBox - boxWidth/2;
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
/// We need to sort it in order to insert efficiently
////////////////////////////////////////////////////////////////
// First, copy datas into an array that will be sorted and
// set Morton index for each particle
// Temporary FTreeCoordinate
std::unique_ptr<IndexedParticle[]> particleIndexes(new IndexedParticle[numberOfParticle]);
FLOG(copyTimer.tic());
for(int idxParts=0; idxParts<numberOfParticle ; ++idxParts ){
// Get the Morton Index
const FTreeCoordinate host(
GetTreeCoordinate(particlesContainers.getPositions()[0][idxParts] - boxCorner.getX(),
boxWidthAtLeafLevel, boxWidth, NbLevels),
GetTreeCoordinate(particlesContainers.getPositions()[1][idxParts] - boxCorner.getY(),
boxWidthAtLeafLevel, boxWidth, NbLevels ),
GetTreeCoordinate(particlesContainers.getPositions()[2][idxParts] - boxCorner.getZ(),
boxWidthAtLeafLevel, boxWidth, NbLevels )
);
// Store morton index and original idx
particleIndexes[idxParts].mindex = host.getMortonIndex(NbLevels-1);
particleIndexes[idxParts].particlePositionInArray = idxParts;
}
FLOG(copyTimer.tac());
FLOG(FLog::Controller<<"Time needed for copying "<< numberOfParticle<<" particles : "<<copyTimer.elapsed() << " secondes !\n");
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
/// Sort it needed
////////////////////////////////////////////////////////////////
if(!isAlreadySorted){
//Sort dat array
FLOG(FTic sortTimer);
FQuickSort<IndexedParticle,FSize>::QsOmp( particleIndexes.get(), numberOfParticle);
FLOG(sortTimer.tac());
FLOG(FLog::Controller << "Time needed for sorting the particles : "<< sortTimer.elapsed() << " secondes !\n");
}
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
/// Get the number of leaves
////////////////////////////////////////////////////////////////
//Enumerate the different leaves AND copy the positions
unsigned int numberOfLeaves = 0;
FLOG(enumTimer.tic());
{
MortonIndex previousIndex = -1;
for(int idxParts = 0 ; idxParts < numberOfParticle ; ++idxParts){
// If not the same leaf, inc the counter
if(particleIndexes[idxParts].mindex != previousIndex){
previousIndex = particleIndexes[idxParts].mindex;
numberOfLeaves += 1;
}
}
}
FLOG(enumTimer.tac());
FLOG(FLog::Controller << "Time needed for enumerate the leaves : "<< enumTimer.elapsed() << " secondes !\n");
FLOG(FLog::Controller << "Found " << numberOfLeaves << " leaves differents. \n");
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
/// Count the number of particles per leaf
////////////////////////////////////////////////////////////////
FLOG(leavesOffset.tic());
// Store the size of each leaves
std::unique_ptr<LeafDescriptor[]> leavesDescriptor(new LeafDescriptor[numberOfLeaves]);
memset(leavesDescriptor.get(), 0, sizeof(LeafDescriptor)*(numberOfLeaves));
{
//Init
int currentLeafIndex = -1;
MortonIndex currentMortonIndex = -1;
for(int idxParts = 0 ; idxParts < numberOfParticle ; ++idxParts){
// If not the same leaf
if(particleIndexes[idxParts].mindex != currentMortonIndex){
FAssertLF(FSize(currentLeafIndex) < numberOfLeaves);
// Move to next descriptor
currentLeafIndex += 1;
currentMortonIndex = particleIndexes[idxParts].mindex;
// Fill the descriptor
leavesDescriptor[currentLeafIndex].offsetInArray = idxParts;
leavesDescriptor[currentLeafIndex].leafPtr = tree->createLeaf(currentMortonIndex);
leavesDescriptor[currentLeafIndex].nbParticlesInLeaf = 0;
}
// Inc the number of particles in the current leaf
leavesDescriptor[currentLeafIndex].nbParticlesInLeaf += 1;
}
}
FLOG(leavesOffset.tac());
FLOG(FLog::Controller << "Time needed for setting the offset of each leaves : "<< leavesOffset.elapsed() << " secondes !\n");
//Then, we create the leaves inside the tree
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
/// Insert multiple particles inside their corresponding leaf
////////////////////////////////////////////////////////////////
FLOG(insertTimer.tic());
// Copy each parts into corresponding Leaf
#pragma omp parallel
{
std::array<AttributeClass, NbAttributes> particleAttr;
const FReal*const partX = particlesContainers.getPositions()[0];
const FReal*const partY = particlesContainers.getPositions()[1];
const FReal*const partZ = particlesContainers.getPositions()[2];
#pragma omp for schedule(static)
for(FSize idxLeaf = 0 ; idxLeaf < numberOfLeaves ; ++idxLeaf ){
const int nbParticlesAlreadyInLeaf = leavesDescriptor[idxLeaf].leafPtr->getSrc()->getNbParticles();
// Reserve the space needed for the new particles
leavesDescriptor[idxLeaf].leafPtr->getSrc()->reserve(nbParticlesAlreadyInLeaf + leavesDescriptor[idxLeaf].nbParticlesInLeaf);
// For all particles
for(int idxPart = 0 ; idxPart < leavesDescriptor[idxLeaf].nbParticlesInLeaf ; ++idxPart){
// Get position in the original container
const int particleOriginalPos = particleIndexes[leavesDescriptor[idxLeaf].offsetInArray + idxPart].particlePositionInArray;
// Get the original position
FPoint particlePos( partX[particleOriginalPos],
partY[particleOriginalPos],
partZ[particleOriginalPos]);
// Copy the attributes
for(unsigned idxAttr = 0 ; idxAttr < NbAttributes; ++idxAttr){
particleAttr[idxAttr] = particlesContainers.getAttribute(idxAttr)[particleOriginalPos];
}
// Push the particle in the array
leavesDescriptor[idxLeaf].leafPtr->push(particlePos, particleAttr);
}
}
}
FLOG(insertTimer.tac());
FLOG(FLog::Controller << "Time needed for inserting the parts into the leaves : "<< insertTimer.elapsed() << " secondes !\n");
}
};
......
// ===================================================================================
// Copyright ScalFmm 2011 INRIA, Olivier Coulaud, Berenger Bramas, Matthias Messner
// olivier.coulaud@inria.fr, berenger.bramas@inria.fr
// This software is a computer program whose purpose is to compute the FMM.
//
// This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#include <limits>
#include <iostream>
#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Containers/FVector.hpp"
#include "../../Src/Containers/FOctree.hpp"
#include "../../Src/Core/FFmmAlgorithm.hpp"
#include "../../Src/Kernels/P2P/FP2PParticleContainer.hpp"
#include "../../Src/Kernels/Rotation/FRotationKernel.hpp"
#include "../../Src/Kernels/Rotation/FRotationCell.hpp"
#include "../../Src/Utils/FMath.hpp"
#include "../../Src/Utils/FMemUtils.hpp"
#include "../../Src/Utils/FParameters.hpp"
#include "../../Src/Core/FFmmAlgorithm.hpp"
#include "../../Src/Core/FFmmAlgorithmThread.hpp"
#include "../../Src/Core/FFmmAlgorithmTask.hpp"
#include "../../Src/Files/FFmaGenericLoader.hpp"
#include "../../Src/Utils/FParameterNames.hpp"
#include "../../Src/Files/FTreeBuilder.hpp"
int main(int argc, char** argv){
FHelpDescribeAndExit(argc, argv,
"Test the insertion of particle using TreeBuilder.",
FParameterDefinitions::InputFile, FParameterDefinitions::OctreeHeight,
FParameterDefinitions::OctreeSubHeight);
static const int P = 9;
typedef FRotationCell<P> CellClass;
typedef FP2PParticleContainer<> ContainerClass;
typedef FSimpleLeaf< ContainerClass > LeafClass;
typedef FOctree< CellClass, ContainerClass , LeafClass > OctreeClass;
const int NbLevels = FParameters::getValue(argc,argv,FParameterDefinitions::OctreeHeight.options, 5);
const int SizeSubLevels = FParameters::getValue(argc,argv,FParameterDefinitions::OctreeSubHeight.options, 3);
const char* const filename = FParameters::getStr(argc,argv,FParameterDefinitions::InputFile.options, "../Data/test20k.fma");
// -----------------------------------------------------
FFmaGenericLoader loader(filename);
if(!loader.isOpen()){
std::cout << "Loader Error, " << filename << " is missing\n";
return 1;
}
// -----------------------------------------------------
OctreeClass tree(NbLevels, SizeSubLevels, loader.getBoxWidth(), loader.getCenterOfBox());
// -----------------------------------------------------
{
ContainerClass particles;
for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
FPoint particlePosition;
FReal physicalValue;
loader.fillParticle(&particlePosition,&physicalValue);
particles.push(particlePosition, physicalValue );
}
FTreeBuilder<OctreeClass, LeafClass>::BuildTreeFromArray(&tree, particles);
}
// -----------------------------------------------------
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