Commit d940c321 authored by BRAMAS Berenger's avatar BRAMAS Berenger

Major update to move to new leaf a smaller revision will come after test and comments

parent 20d3b573
......@@ -32,7 +32,7 @@
* to move the particles in the tree instead of building a new
* tree.
*/
template <class OctreeClass, class ContainerClass, class ParticleClass>
template <class OctreeClass, class ContainerClass, class ExtractorClass>
class FOctreeArranger : FAssertable {
OctreeClass* const tree; //< The tree to work on
......@@ -45,7 +45,7 @@ public:
/** Arrange */
void rearrange(const int isPeriodic = DirNone){
// This vector is to keep the moving particles
FVector<ParticleClass> tomove;
ExtractorClass extractor;
// For periodic
const FReal boxWidth = tree->getBoxWidth();
......@@ -53,14 +53,17 @@ public:
const FPoint max(tree->getBoxCenter(),boxWidth/2);
{ // iterate on the leafs and found particle to remove
FVector<int> indexesToExtract;
typename OctreeClass::Iterator octreeIterator(tree);
octreeIterator.gotoBottomLeft();
do{
const MortonIndex currentIndex = octreeIterator.getCurrentGlobalIndex();
typename ContainerClass::BasicIterator iter(*octreeIterator.getCurrentListTargets());
while( iter.hasNotFinished() ){
FPoint partPos = iter.data().getPosition();
ContainerClass* particles = octreeIterator.getCurrentLeaf()->getSrc();
for(int idxPart = 0 ; idxPart < particles->getNbParticles(); ++idxPart){
FPoint partPos( particles->getPositions()[0][idxPart],
particles->getPositions()[1][idxPart],
particles->getPositions()[2][idxPart] );
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
if( TestPeriodicCondition(isPeriodic, DirPlusX) ){
while(partPos.getX() >= max.getX()){
......@@ -119,24 +122,25 @@ public:
printf("Application is exiting...\n");
}
// set pos
iter.data().setPosition(partPos);
particles->getWPositions()[0][idxPart] = partPos.getX();
particles->getWPositions()[1][idxPart] = partPos.getY();
particles->getWPositions()[2][idxPart] = partPos.getZ();
const MortonIndex particuleIndex = tree->getMortonFromPosition(iter.data().getPosition());
const MortonIndex particuleIndex = tree->getMortonFromPosition(partPos);
if(particuleIndex != currentIndex){
tomove.push(iter.data());
iter.remove();
}
else {
iter.gotoNext();
indexesToExtract.push(idxPart);
}
}
// remove from leaf
extractor.extractParticles(particles, indexesToExtract.data(), indexesToExtract.getSize());
particles->removeParticles(indexesToExtract.data(), indexesToExtract.getSize());
indexesToExtract.clear();
} while(octreeIterator.moveRight());
}
{ // insert particles that moved
for(int idxPart = 0 ; idxPart < tomove.getSize() ; ++idxPart){
tree->insert(tomove[idxPart]);
}
extractor.reinsertInTree(tree);
}
{ // Remove empty leaves
......@@ -145,7 +149,7 @@ public:
bool workOnNext = true;
do{
// Empty leaf
if( octreeIterator.getCurrentListTargets()->getSize() == 0 ){
if( octreeIterator.getCurrentListTargets()->getNbParticles() == 0 ){
const MortonIndex currentIndex = octreeIterator.getCurrentGlobalIndex();
workOnNext = octreeIterator.moveRight();
tree->removeLeaf( currentIndex );
......
......@@ -16,7 +16,8 @@
#ifndef FABSTRACTLEAF_HPP
#define FABSTRACTLEAF_HPP
#include "../Utils/FPoint.hpp"
#include "../Utils/FDebug.hpp"
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
......@@ -26,7 +27,7 @@
* This class is used to enable the use of typed particles
* (source XOR target) or simple system (source AND target)
*/
template< class ParticleClass, class ContainerClass >
template< class ContainerClass >
class FAbstractLeaf {
public:
/** Default destructor */
......@@ -39,7 +40,10 @@ public:
* Depending on the system to use the class that inherit
* this interface can sort the particle as they like.
*/
virtual void push(const ParticleClass& particle) = 0;
template<typename... Args>
void push(const FPoint& /*inParticlePosition*/, Args ... /*args*/){
FDEBUG( FDebug::Controller.write("Warning, push is not implemented!").write(FDebug::Flush) );
}
/**
* To get all the sources in a leaf
......
......@@ -13,9 +13,11 @@
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef FABSTRACTPARTICLE_HPP
#define FABSTRACTPARTICLE_HPP
#ifndef FABSTRACTPARTICLECONTAINER_HPP
#define FABSTRACTPARTICLECONTAINER_HPP
#include "../Utils/FGlobal.hpp"
#include "../Utils/FDebug.hpp"
/* forward declaration to avoid include */
class FPoint;
......@@ -36,20 +38,19 @@ class FPoint;
*
* @warning Inherite from this class when implement a specific particle type
*/
class FAbstractParticle{
public:
/** Default destructor */
virtual ~FAbstractParticle(){
}
/**
* Must be implemented by each user Particle class
* @return the position of the current cell
*/
virtual const FPoint& getPosition() const = 0;
class FAbstractParticleContainer {
public:
/** Default destructor */
virtual ~FAbstractParticleContainer(){
}
template<typename... Args>
void push(const FPoint& /*inParticlePosition*/, Args ... /*args*/){
FDEBUG( FDebug::Controller.write("Warning, push is not implemented!").write(FDebug::Flush) );
}
};
#endif //FABSTRACTPARTICLE_HPP
#endif //FABSTRACTPARTICLECONTAINER_HPP
......@@ -17,7 +17,6 @@
#define FBASICCELL_HPP
#include "../Extensions/FExtendPosition.hpp"
#include "../Extensions/FExtendMortonIndex.hpp"
#include "../Extensions/FExtendCoordinate.hpp"
......
// ===================================================================================
// Copyright ScalFmm 2011 INRIA, Olivier Coulaud, Bérenger 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".
// ===================================================================================
#ifndef FBASICPARTICLECONTAINER_HPP
#define FBASICPARTICLECONTAINER_HPP
#include "FAbstractParticleContainer.hpp"
#include <type_traits>
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
* @class FBasicParticle
* Please read the license
*
* This class defines a basic particle used for examples. It extends
* the mininum, only what is needed by FOctree and FFmmAlgorithm
* to make the things working.
* By using this extension it will implement the FAbstractParticle without
* inheriting from it.
*/
template <unsigned NbAttributesPerParticle, class AttributeClass = FReal >
class FBasicParticleContainer : public FAbstractParticleContainer {
protected:
int nbParticles;
FReal* positions[3];
AttributeClass* attributes[NbAttributesPerParticle];
int allocatedParticles;
template<int index>
void addParticleValue(const int /*insertPosition*/){
}
template<int index, typename... Args>
void addParticleValue(const int insertPosition, const AttributeClass value, Args... args){
static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
attributes[index][insertPosition] = value;
addParticleValue<index+1>( insertPosition, args...);
}
public:
FBasicParticleContainer(const FBasicParticleContainer&) = delete;
FBasicParticleContainer& operator=(const FBasicParticleContainer&) = delete;
FBasicParticleContainer() : nbParticles(0), allocatedParticles(0){
memset(positions, 0, sizeof(positions[0]) * 3);
memset(attributes, 0, sizeof(attributes[0]) * NbAttributesPerParticle);
}
~FBasicParticleContainer(){
delete[] reinterpret_cast<char*>(positions[0]);
}
int getNbParticles() const{
return nbParticles;
}
const FReal*const*const getPositions() const {
return positions;
}
FReal*const*const getWPositions() {
return positions;
}
AttributeClass* getAttribute(const int index) {
return attributes[index];
}
const AttributeClass* getAttribute(const int index) const {
return attributes[index];
}
template <int index>
AttributeClass* getAttribute() {
static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
return attributes[index];
}
template <int index>
const AttributeClass* getAttribute() const {
static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
return attributes[index];
}
template<typename... Args>
void push(const FPoint& inParticlePosition, Args... args){
if( nbParticles == allocatedParticles ){
allocatedParticles = FMath::Max(10,int(FReal(nbParticles+1)*1.5));
FReal* newData = reinterpret_cast<FReal*>(new char[(sizeof(FReal)*3 + sizeof(AttributeClass)*NbAttributesPerParticle)*allocatedParticles]);
memset( newData, 0, (sizeof(FReal)*3 + sizeof(AttributeClass)*NbAttributesPerParticle)*allocatedParticles);
const char*const toDelete = reinterpret_cast<const char*>(positions[0]);
for(int idx = 0 ; idx < 3 ; ++idx){
memcpy(newData + (allocatedParticles * idx), positions[idx], sizeof(FReal) * nbParticles);
positions[idx] = newData + (allocatedParticles * idx);
}
AttributeClass* startAddress = reinterpret_cast<AttributeClass*>(positions[2] + allocatedParticles);
for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
memcpy(startAddress + (allocatedParticles * idx), attributes[idx], sizeof(AttributeClass) * nbParticles);
attributes[idx] = startAddress + (idx * allocatedParticles);
}
delete[] toDelete;
}
positions[0][nbParticles] = inParticlePosition.getX();
positions[1][nbParticles] = inParticlePosition.getY();
positions[2][nbParticles] = inParticlePosition.getZ();
addParticleValue<0>( nbParticles, args...);
nbParticles += 1;
}
template<typename... Args>
void push(const FPoint& inParticlePosition, const bool /*isTarget*/, Args... args){
push(inParticlePosition, args...);
}
void clear(){
nbParticles = 0;
}
/** Save the current cell in a buffer */
void save(FBufferWriter& buffer) const{
buffer << nbParticles;
for(int idx = 0 ; idx < 3 ; ++idx){
buffer.write(positions[idx], nbParticles);
}
for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
buffer.write(attributes[idx], nbParticles);
}
}
/** Restore the current cell from a buffer */
void restore(FBufferReader& buffer){
buffer >> nbParticles;
if( nbParticles >= allocatedParticles ){
allocatedParticles = FMath::Max(10,int(FReal(nbParticles+1)*1.5));
FReal* newData = reinterpret_cast<FReal*>(new char[(sizeof(FReal)*3 + sizeof(AttributeClass)*NbAttributesPerParticle)*allocatedParticles]);
memset( newData, 0, (sizeof(FReal)*3 + sizeof(AttributeClass)*NbAttributesPerParticle)*allocatedParticles);
delete[] reinterpret_cast<char*>(positions[0]);
for(int idx = 0 ; idx < 3 ; ++idx){
positions[idx] = newData + (allocatedParticles * idx);
}
AttributeClass* startAddress = reinterpret_cast<AttributeClass*>(positions[2] + allocatedParticles);
for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
attributes[idx] = startAddress + (idx * allocatedParticles);
}
}
for(int idx = 0 ; idx < 3 ; ++idx){
buffer.fillArray(positions[idx], nbParticles);
}
for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
buffer.fillArray(attributes[idx], nbParticles);
}
}
/** to enable rearranging */
void removeParticles(const int indexesToRemove[], const int nbParticlesToRemove){
int offset = 1;
int idxIndexes = 1;
int idxIns = indexesToRemove[0] + 1;
for( ; idxIns < nbParticles && idxIndexes < nbParticlesToRemove ; ++idxIns){
if( idxIns == indexesToRemove[idxIndexes] ){
idxIndexes += 1;
offset += 1;
}
else{
for(int idx = 0 ; idx < 3 ; ++idx){
positions[idx][idxIns-offset] = positions[idx][idxIns];
}
for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
attributes[idx][idxIns-offset] = attributes[idx][idxIns];
}
}
}
for( ; idxIns < nbParticles ; ++idxIns){
for(int idx = 0 ; idx < 3 ; ++idx){
positions[idx][idxIns-offset] = positions[idx][idxIns];
}
for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
attributes[idx][idxIns-offset] = attributes[idx][idxIns];
}
}
nbParticles -= nbParticlesToRemove;
}
};
#endif //FBASICPARTICLECONTAINER_HPP
......@@ -13,12 +13,10 @@
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef FFmaPARTICLE_HPP
#define FFmaPARTICLE_HPP
#ifndef FFMAPARTICLECONTAINER_HPP
#define FFMAPARTICLECONTAINER_HPP
#include "../Extensions/FExtendPosition.hpp"
#include "../Extensions/FExtendPhysicalValue.hpp"
#include "FBasicParticleContainer.hpp"
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
......@@ -26,23 +24,22 @@
* Please read the license
*
* This class defines a particle for FMA loader.
* As defined in FFmaLoader it needs {FBasicParticle,FExtendPhysicalValue}
* As defined in FFmaLoader it needs
*/
class FFmaParticle : public FExtendPosition, public FExtendPhysicalValue {
class FFmaParticleContainer : public FBasicParticleContainer<1> {
typedef FBasicParticleContainer<1> Parent;
public:
/** Save the current cell in a buffer */
void save(FBufferWriter& buffer) const{
FExtendPosition::save(buffer);
FExtendPhysicalValue::save(buffer);
FReal* getPhysicalValues(){
return Parent::getAttribute(0);
}
/** Restore the current cell from a buffer */
void restore(FBufferReader& buffer){
FExtendPosition::restore(buffer);
FExtendPhysicalValue::restore(buffer);
const FReal* getPhysicalValues() const {
return Parent::getAttribute(0);
}
};
#endif //FFmaPARTICLE_HPP
#endif //FFMAPARTICLECONTAINER_HPP
......@@ -27,8 +27,8 @@
* This class is used as a leaf in simple system (source AND target)
* here there is only one list that store all particles.
*/
template< class ParticleClass , class ContainerClass>
class FSimpleLeaf : public FAbstractLeaf<ParticleClass,ContainerClass> {
template< class ContainerClass>
class FSimpleLeaf : public FAbstractLeaf<ContainerClass> {
ContainerClass particles;
public:
......@@ -40,8 +40,9 @@ public:
* To add a new particle in the leaf
* @param particle the new particle to store in the current leaf
*/
void push(const ParticleClass& particle){
this->particles.push(particle);
template<typename... Args>
void push(const FPoint& inParticlePosition, Args ... args){
this->particles.push(inParticlePosition, args...);
}
/**
......
......@@ -83,8 +83,8 @@ public:
/** After Downward */
void L2P(const CellClass* const local, ContainerClass*const particles){
// The particles is impacted by the parent cell
int*const particlesAttributes = targets->getDataDown();
for(int idxPart = 0 ; idxPart < targets ; ++idxPart){
long long int*const particlesAttributes = particles->getDataDown();
for(int idxPart = 0 ; idxPart < particles->getNbParticles() ; ++idxPart){
particlesAttributes[idxPart] += local->getDataDown();
}
}
......@@ -95,7 +95,7 @@ public:
ContainerClass* const FRestrict targets, const ContainerClass* const FRestrict sources,
ContainerClass* const directNeighborsParticles[27], const int ){
// Each particles targeted is impacted by the particles sources
long long int inc = sources->getSize();
long long int inc = sources->getNbParticles();
if(targets == sources){
inc -= 1;
}
......@@ -105,8 +105,8 @@ public:
}
}
int*const particlesAttributes = targets->getDataDown();
for(int idxPart = 0 ; idxPart < targets ; ++idxPart){
long long int*const particlesAttributes = targets->getDataDown();
for(int idxPart = 0 ; idxPart < targets->getNbParticles() ; ++idxPart){
particlesAttributes[idxPart] += inc;
}
}
......@@ -123,8 +123,8 @@ public:
}
}
int*const particlesAttributes = targets->getDataDown();
for(int idxPart = 0 ; idxPart < targets ; ++idxPart){
long long int*const particlesAttributes = targets->getDataDown();
for(int idxPart = 0 ; idxPart < targets->getNbParticles() ; ++idxPart){
particlesAttributes[idxPart] += inc;
}
}
......@@ -140,15 +140,13 @@ void ValidateFMMAlgo(OctreeClass* const tree){
const int TreeHeight = tree->getHeight();
long long int NbPart = 0;
{ // Check that each particle has been summed with all other
typename OctreeClass::Iterator octreeIterator(tree);
octreeIterator.gotoBottomLeft();
do{
if(octreeIterator.getCurrentCell()->getDataUp() != octreeIterator.getCurrentListSrc()->getSize() ){
std::cout << "Problem P2M : " << octreeIterator.getCurrentCell()->getDataUp() <<
" (should be " << octreeIterator.getCurrentListSrc()->getSize() << ")\n";
tree->forEachCellLeaf([&](CellClass* cell, LeafClass* leaf){
if(cell->getDataUp() != leaf->getSrc()->getNbParticles() ){
std::cout << "Problem P2M : " << cell->getDataUp() <<
" (should be " << leaf->getSrc()->getNbParticles() << ")\n";
}
NbPart += octreeIterator.getCurrentListSrc()->getSize();
} while(octreeIterator.moveRight());
NbPart += leaf->getSrc()->getNbParticles();
});
}
{ // Ceck if there is number of NbPart summed at level 1
typename OctreeClass::Iterator octreeIterator(tree);
......@@ -180,18 +178,14 @@ void ValidateFMMAlgo(OctreeClass* const tree){
typename OctreeClass::Iterator octreeIterator(tree);
octreeIterator.gotoBottomLeft();
do{
typename ContainerClass::BasicIterator iter(*octreeIterator.getCurrentListTargets());
const bool isUsingTsm = (octreeIterator.getCurrentListTargets() != octreeIterator.getCurrentListSrc());
while( iter.hasNotFinished() ){
// If a particles has been impacted by less than NbPart - 1 (the current particle)
// there is a problem
if( (!isUsingTsm && iter.data().getDataDown() != NbPart - 1) ||
(isUsingTsm && iter.data().getDataDown() != NbPart) ){
std::cout << "Problem L2P + P2P : " << iter.data().getDataDown() << "(" << octreeIterator.getCurrentGlobalIndex() << ")\n";
const long long int* dataDown = octreeIterator.getCurrentListTargets()->getDataDown();
for(int idxPart = 0 ; idxPart < octreeIterator.getCurrentListTargets()->getNbParticles() ; ++idxPart){
if( (!isUsingTsm && dataDown[idxPart] != NbPart - 1) ||
(isUsingTsm && dataDown[idxPart] != NbPart) ){
std::cout << "Problem L2P + P2P : " << dataDown[idxPart] <<
"(" << octreeIterator.getCurrentGlobalIndex() << ")\n";
}
iter.gotoNext();
}
} while(octreeIterator.moveRight());
}
......
// ===================================================================================
// Copyright ScalFmm 2011 INRIA, Olivier Coulaud, Bérenger 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".
// ===================================================================================
#ifndef FTESTPARTICLE_HPP
#define FTESTPARTICLE_HPP
#include "FBasicParticle.hpp"
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
* @class FTestParticle
* Please read the license
*
* This class is used in the FTestKernels, please
* look at this class to know whit it is.
*
* Particles just need the data down (after and run with FTestKernel the
* value shoud be NB PARTICLES (-1)).
*/
class FTestParticle : public FBasicParticle {
protected:
// To store data during downard pass
long long int dataDown;
public:
FTestParticle(): dataDown(0){
}
/** Default destructor */
virtual ~FTestParticle(){
}
/** Get the down data */
long long int getDataDown() const {
return this->dataDown;
}
/** Set down data */
void setDataDown(const long long int inData){
this->dataDown = inData;
}
//////////////////////////////////////////////////
/** Save the current cell in a buffer */
void save(FBufferWriter& buffer) const{
FBasicParticle::save(buffer);
buffer << dataDown;
}
/** Restore the current cell from a buffer */
void restore(FBufferReader& buffer){
FBasicParticle::restore(buffer);
buffer >> dataDown;
}
};
#endif //FTESTPARTICLE_HPP
......@@ -13,36 +13,37 @@
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef FBASICPARTICLE_HPP
#define FBASICPARTICLE_HPP
#ifndef FTESTPARTICLECONTAINER_HPP
#define FTESTPARTICLECONTAINER_HPP
#include "../Extensions/FExtendPosition.hpp"
#include "FBasicParticleContainer.hpp"
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
* @class FBasicParticle
* @class FTestParticle
* Please read the license
*
* This class defines a basic particle used for examples. It extends
* the mininum, only what is needed by FOctree and FFmmAlgorithm
* to make the things working.
* By using this extension it will implement the FAbstractParticle without
* inheriting from it.
* This class is used in the FTestKernels, please
* look at this class to know whit it is.
*
* Particles just need the data down (after and run with FTestKernel the
* value shoud be NB PARTICLES (-1)).
*/
class FBasicParticle : public FExtendPosition{
class FTestParticleContainer : public FBasicParticleContainer<1, long long int> {
typedef FBasicParticleContainer<1, long long int> Parent;
public:
/** Save the current cell in a buffer */
void save(FBufferWriter& buffer) const{
FExtendPosition::save(buffer);
long long int* getDataDown(){
return Parent::getAttribute(0);
}
/** Restore the current cell from a buffer */
void restore(FBufferReader& buffer){
FExtendPosition::restore(buffer);
const long long int* getDataDown() const {
return Parent::getAttribute(0);
}
};
#endif //FBASICPARTICLE_HPP
#endif //FTESTPARTICLECONTAINER_HPP
......@@ -30,8 +30,8 @@
*
* Particles should be typed to enable targets/sources difference.
*/
template< class ParticleClass , class ContainerClass>
class FTypedLeaf : public FAbstractLeaf<ParticleClass,ContainerClass>, public FAssertable {
template< class ContainerClass>
class FTypedLeaf : public FAbstractLeaf<ContainerClass>, public FAssertable {
ContainerClass sources; //< The sources containers
ContainerClass targets; //< The targets containers
......@@ -44,11 +44,10 @@ public:
* To add a new particle in the leaf
* @param particle the new parti