Commit 6f55fa9a authored by BRAMAS Berenger's avatar BRAMAS Berenger
Browse files

Create the periodic system using normal FMM functions for all kernels, add...

Create the periodic system using normal FMM functions for all kernels, add unit test for all 3 kernels, be aware that current particles are randomly generated and not real system for periodic simulations
parent 74ca87da
......@@ -17,6 +17,7 @@
#include "../Utils/FDebug.hpp"
#include "../Utils/FGlobal.hpp"
#include "../Utils/FGlobalPeriodic.hpp"
#include "../Utils/FPoint.hpp"
#include "../Utils/FMath.hpp"
#include "../Utils/FNoCopyable.hpp"
......@@ -694,19 +695,19 @@ public:
FTreeCoordinate center;
center.setPositionFromMorton(inIndex, inLevel);
const int limite = FMath::pow2(inLevel);
const int boxLimite = FMath::pow2(inLevel);
int idxNeighbors = 0;
// We test all cells around
for(int idxX = -1 ; idxX <= 1 ; ++idxX){
if(!FMath::Between(center.getX() + idxX,0,limite)) continue;
if(!FMath::Between(center.getX() + idxX,0,boxLimite)) continue;
for(int idxY = -1 ; idxY <= 1 ; ++idxY){
if(!FMath::Between(center.getY() + idxY,0,limite)) continue;
if(!FMath::Between(center.getY() + idxY,0,boxLimite)) continue;
for(int idxZ = -1 ; idxZ <= 1 ; ++idxZ){
if(!FMath::Between(center.getZ() + idxZ,0,limite)) continue;
if(!FMath::Between(center.getZ() + idxZ,0,boxLimite)) continue;
// if we are not on the current cell
if( !(!idxX && !idxY && !idxZ) ){
......@@ -780,18 +781,18 @@ public:
const FTreeCoordinate parentCell(workingCell.getX()>>1,workingCell.getY()>>1,workingCell.getZ()>>1);
// Limite at parent level number of box (split by 2 by level)
const int limite = FMath::pow2(inLevel-1);
const int boxLimite = FMath::pow2(inLevel-1);
int idxNeighbors = 0;
// We test all cells around
for(int idxX = -1 ; idxX <= 1 ; ++idxX){
if(!FMath::Between(parentCell.getX() + idxX,0,limite)) continue;
if(!FMath::Between(parentCell.getX() + idxX,0,boxLimite)) continue;
for(int idxY = -1 ; idxY <= 1 ; ++idxY){
if(!FMath::Between(parentCell.getY() + idxY,0,limite)) continue;
if(!FMath::Between(parentCell.getY() + idxY,0,boxLimite)) continue;
for(int idxZ = -1 ; idxZ <= 1 ; ++idxZ){
if(!FMath::Between(parentCell.getZ() + idxZ,0,limite)) continue;
if(!FMath::Between(parentCell.getZ() + idxZ,0,boxLimite)) continue;
// if we are not on the current cell
if( idxX || idxY || idxZ ){
......@@ -838,43 +839,62 @@ public:
*/
int getPeriodicInteractionNeighbors(const CellClass* inNeighbors[343],
const FTreeCoordinate& workingCell,
const int inLevel) const{
const int inLevel, const int inDirection) const{
// Then take each child of the parent's neighbors if not in directNeighbors
// Father coordinate
const FTreeCoordinate parentCell(workingCell.getX()>>1,workingCell.getY()>>1,workingCell.getZ()>>1);
// Limite at parent level number of box (split by 2 by level)
const int limite = FMath::pow2(inLevel-1);
const int boxLimite = FMath::pow2(inLevel-1);
// This is not on a border we can use normal interaction list method
if( !(parentCell.getX() == 0 || parentCell.getY() == 0 || parentCell.getZ() == 0 ||
parentCell.getX() == limite - 1 || parentCell.getY() == limite - 1 || parentCell.getZ() == limite - 1 ) ) {
parentCell.getX() == boxLimite - 1 || parentCell.getY() == boxLimite - 1 || parentCell.getZ() == boxLimite - 1 ) ) {
return getInteractionNeighbors( inNeighbors, workingCell, inLevel);
}
else{
// reset
memset(inNeighbors, 0, sizeof(CellClass*) * 343);
const int startX = (testPeriodicCondition(inDirection, DirMinusX) || parentCell.getX() != 0 ?-1:0);
const int endX = (testPeriodicCondition(inDirection, DirPlusX) || parentCell.getX() != boxLimite - 1 ?1:0);
const int startY = (testPeriodicCondition(inDirection, DirMinusY) || parentCell.getY() != 0 ?-1:0);
const int endY = (testPeriodicCondition(inDirection, DirPlusY) || parentCell.getY() != boxLimite - 1 ?1:0);
const int startZ = (testPeriodicCondition(inDirection, DirMinusZ) || parentCell.getZ() != 0 ?-1:0);
const int endZ = (testPeriodicCondition(inDirection, DirPlusZ) || parentCell.getZ() != boxLimite - 1 ?1:0);
int idxNeighbors = 0;
// We test all cells around
for(int idxX = -1 ; idxX <= 1 ; ++idxX){
for(int idxY = -1 ; idxY <= 1 ; ++idxY){
for(int idxZ = -1 ; idxZ <= 1 ; ++idxZ){
for(int idxX = startX ; idxX <= endX ; ++idxX){
for(int idxY = startY ; idxY <= endY ; ++idxY){
for(int idxZ = startZ ; idxZ <= endZ ; ++idxZ){
// if we are not on the current cell
if( idxX || idxY || idxZ ){
const FTreeCoordinate otherParent(parentCell.getX() + idxX,parentCell.getY() + idxY,parentCell.getZ() + idxZ);
FTreeCoordinate otherParentInBox(otherParent);
// periodic
if( otherParentInBox.getX() < 0 ) otherParentInBox.setX( otherParentInBox.getX() + limite );
else if( limite <= otherParentInBox.getX() ) otherParentInBox.setX( otherParentInBox.getX() - limite );
if( otherParentInBox.getX() < 0 ){
otherParentInBox.setX( otherParentInBox.getX() + boxLimite );
}
else if( boxLimite <= otherParentInBox.getX() ){
otherParentInBox.setX( otherParentInBox.getX() - boxLimite );
}
if( otherParentInBox.getY() < 0 ) otherParentInBox.setY( otherParentInBox.getY() + limite );
else if( limite <= otherParentInBox.getY() ) otherParentInBox.setY( otherParentInBox.getY() - limite );
if( otherParentInBox.getY() < 0 ){
otherParentInBox.setY( otherParentInBox.getY() + boxLimite );
}
else if( boxLimite <= otherParentInBox.getY() ){
otherParentInBox.setY( otherParentInBox.getY() - boxLimite );
}
if( otherParentInBox.getZ() < 0 ) otherParentInBox.setZ( otherParentInBox.getZ() + limite );
else if( limite <= otherParentInBox.getZ() ) otherParentInBox.setZ( otherParentInBox.getZ() - limite );
if( otherParentInBox.getZ() < 0 ){
otherParentInBox.setZ( otherParentInBox.getZ() + boxLimite );
}
else if( boxLimite <= otherParentInBox.getZ() ){
otherParentInBox.setZ( otherParentInBox.getZ() - boxLimite );
}
const MortonIndex mortonOtherParent = otherParentInBox.getMortonIndex(inLevel-1) << 3;
......@@ -942,19 +962,19 @@ public:
*/
int getLeafsNeighbors(ContainerClass* inNeighbors[27], const FTreeCoordinate& center, const int inLevel){
memset( inNeighbors, 0 , 27 * sizeof(ContainerClass*));
const int limite = FMath::pow2(inLevel);
const int boxLimite = FMath::pow2(inLevel);
int idxNeighbors = 0;
// We test all cells around
for(int idxX = -1 ; idxX <= 1 ; ++idxX){
if(!FMath::Between(center.getX() + idxX,0,limite)) continue;
if(!FMath::Between(center.getX() + idxX,0,boxLimite)) continue;
for(int idxY = -1 ; idxY <= 1 ; ++idxY){
if(!FMath::Between(center.getY() + idxY,0,limite)) continue;
if(!FMath::Between(center.getY() + idxY,0,boxLimite)) continue;
for(int idxZ = -1 ; idxZ <= 1 ; ++idxZ){
if(!FMath::Between(center.getZ() + idxZ,0,limite)) continue;
if(!FMath::Between(center.getZ() + idxZ,0,boxLimite)) continue;
// if we are not on the current cell
if( idxX || idxY || idxZ ){
......@@ -975,55 +995,66 @@ public:
return idxNeighbors;
}
/** This function fill an array with the neighbors of a cell
* @param inNeighbors the array to store the elements
* @param inIndex the index of the element we want the neighbors
* @param inLevel the level of the element
* @return the number of neighbors
*/
int getPeriodicLeafsNeighbors(ContainerClass* inNeighbors[27], const FTreeCoordinate& center, const int inLevel){
memset(inNeighbors , 0 , 27 * sizeof(ContainerClass*));
const int limite = FMath::pow2(inLevel);
int getPeriodicLeafsNeighbors(ContainerClass* inNeighbors[27], FTreeCoordinate inOffsets[27], bool*const isPeriodic,
const FTreeCoordinate& center, const int inLevel, const int inDirection){
const int boxLimite = FMath::pow2(inLevel);
if( center.getX() != 0 && center.getY() != 0 && center.getZ() != 0 &&
center.getX() != boxLimite - 1 && center.getY() != boxLimite - 1 && center.getZ() != boxLimite - 1 ){
(*isPeriodic) = false;
return getLeafsNeighbors(inNeighbors, center, inLevel);
}
(*isPeriodic) = true;
memset(inNeighbors , 0 , 27 * sizeof(ContainerClass*));
int idxNeighbors = 0;
// We test all cells around
for(int idxX = -1 ; idxX <= 1 ; ++idxX){
for(int idxY = -1 ; idxY <= 1 ; ++idxY){
for(int idxZ = -1 ; idxZ <= 1 ; ++idxZ){
const int startX = (testPeriodicCondition(inDirection, DirMinusX) || center.getX() != 0 ?-1:0);
const int endX = (testPeriodicCondition(inDirection, DirPlusX) || center.getX() != boxLimite - 1 ?1:0);
const int startY = (testPeriodicCondition(inDirection, DirMinusY) || center.getY() != 0 ?-1:0);
const int endY = (testPeriodicCondition(inDirection, DirPlusY) || center.getY() != boxLimite - 1 ?1:0);
const int startZ = (testPeriodicCondition(inDirection, DirMinusZ) || center.getZ() != 0 ?-1:0);
const int endZ = (testPeriodicCondition(inDirection, DirPlusZ) || center.getZ() != boxLimite - 1 ?1:0);
// We test all cells around
for(int idxX = startX ; idxX <= endX ; ++idxX){
for(int idxY = startY ; idxY <= endY ; ++idxY){
for(int idxZ = startZ ; idxZ <= endZ ; ++idxZ){
// if we are not on the current cell
if( idxX || idxY || idxZ ){
FTreeCoordinate other(center.getX() + idxX,center.getY() + idxY,center.getZ() + idxZ);
// To give the orientation of the neighbors
FTreeCoordinate offset;
int xoffset = 0, yoffset = 0, zoffset = 0;
if( other.getX() < 0 ){
other.setX( other.getX() + limite );
offset.setX(-1);
other.setX( other.getX() + boxLimite );
xoffset = -1;
}
else if( limite <= other.getX() ){
other.setX( other.getX() - limite );
offset.setX(1);
else if( boxLimite <= other.getX() ){
other.setX( other.getX() - boxLimite );
xoffset = 1;
}
if( other.getY() < 0 ){
other.setY( other.getY() + limite );
offset.setY(-1);
other.setY( other.getY() + boxLimite );
yoffset = -1;
}
else if( limite <= other.getY() ){
other.setY( other.getY() - limite );
offset.setY(1);
else if( boxLimite <= other.getY() ){
other.setY( other.getY() - boxLimite );
yoffset = 1;
}
if( other.getZ() < 0 ){
other.setZ( other.getZ() + limite );
offset.setZ(-1);
other.setZ( other.getZ() + boxLimite );
zoffset = -1;
}
else if( limite <= other.getZ() ){
other.setZ( other.getZ() - limite );
offset.setZ(1);
else if( boxLimite <= other.getZ() ){
other.setZ( other.getZ() - boxLimite );
zoffset = 1;
}
const MortonIndex mortonOther = other.getMortonIndex(inLevel);
......@@ -1031,7 +1062,9 @@ public:
ContainerClass* const leaf = getLeafSrc(mortonOther);
// add to list if not null
if(leaf){
inNeighbors[(((idxX + 1) * 3) + (idxY +1)) * 3 + idxZ + 1] = leaf;
const int index = (((idxX + 1) * 3) + (idxY +1)) * 3 + idxZ + 1;
inNeighbors[index] = leaf;
inOffsets[index].setPosition(xoffset,yoffset,zoffset);
++idxNeighbors;
}
}
......
This diff is collapsed.
......@@ -61,7 +61,8 @@ class FFmmAlgorithmThreadProcPeriodic : protected FAssertable {
const FMpi::FComm& comm; //< MPI comm
CellClass root; //< root of tree needed by the periodicity
int periodicLimit; //< the upper periodic limit
int nbLevelAboveRoot; //< the upper periodic limit
int offsetHeight;
typename OctreeClass::Iterator* iterArray;
int numberOfLeafs; //< To store the size at the previous level
......@@ -89,6 +90,33 @@ class FFmmAlgorithmThreadProcPeriodic : protected FAssertable {
public:
/** To know how many times the box is repeated in each direction
* -x +x -y +y -z +z
*/
int repeatedBox() const {
return nbLevelAboveRoot == -1 ? 3 : 7 * (1<<(nbLevelAboveRoot));
}
/** This function has to be used to init the kernel with correct args
* it return the box seen from a kernel point of view from the periodicity the user ask for
* this is computed using the originalBoxWidth given in parameter
* @param originalBoxWidth the real system size
* @return the size the kernel should use
*/
int boxwidthForKernel(const FReal originalBoxWidth) const {
return originalBoxWidth * ((1<<(offsetHeight+1)) - 1);
}
/** This function has to be used to init the kernel with correct args
* it return the tree heigh seen from a kernel point of view from the periodicity the user ask for
* this is computed using the originalTreeHeight given in parameter
* @param originalTreeHeight the real tree heigh
* @return the heigh the kernel should use
*/
int treeHeightForKernel(const FReal originalTreeHeight) const {
return OctreeHeight + offsetHeight;
}
Interval& getWorkingInterval(const int level){
return getWorkingInterval(level, idProcess);
}
......@@ -102,13 +130,14 @@ public:
* @param inKernels the kernels to call
* An assert is launched if one of the arguments is null
*/
FFmmAlgorithmThreadProcPeriodic(const FMpi::FComm& inComm, OctreeClass* const inTree, KernelClass* const inKernels, const int inPeriodicLimit = 5)
: tree(inTree) , kernels(0), comm(inComm), periodicLimit(inPeriodicLimit), numberOfLeafs(0),
FFmmAlgorithmThreadProcPeriodic(const FMpi::FComm& inComm, OctreeClass* const inTree, KernelClass* const inKernels, const int inUpperLevel = 5)
: tree(inTree) , kernels(0), comm(inComm), nbLevelAboveRoot(inUpperLevel), offsetHeight(inUpperLevel+2), numberOfLeafs(0),
MaxThreads(omp_get_max_threads()), nbProcess(inComm.processCount()), idProcess(inComm.processId()),
OctreeHeight(tree->getHeight()),intervals(new Interval[inComm.processCount()]),
workingIntervalsPerLevel(new Interval[inComm.processCount() * tree->getHeight()]) {
fassert(tree, "tree cannot be null", __LINE__, __FILE__);
fassert(-1 <= inUpperLevel, "inUpperLevel cannot be < -1", __LINE__, __FILE__);
this->kernels = new KernelClass*[MaxThreads];
for(int idxThread = 0 ; idxThread < MaxThreads ; ++idxThread){
......@@ -277,7 +306,7 @@ private:
int firstProcThatSend = idProcess + 1;
// for each levels
for(int idxLevel = OctreeHeight - 2 ; idxLevel >= 1 ; --idxLevel ){
for(int idxLevel = OctreeHeight - 2 ; idxLevel > 0 ; --idxLevel ){
// No more work for me
if(idProcess != 0
&& getWorkingInterval((idxLevel+1), idProcess).max <= getWorkingInterval((idxLevel+1), idProcess - 1).max){
......@@ -1430,62 +1459,78 @@ private:
/** Periodicity */
void processPeriodicLevels(){
if( !periodicLimit ){
return;
}
// If nb level == -1 nothing to do
if( nbLevelAboveRoot == -1 ){
return;
}
CellClass upperCells[periodicLimit];
upperCells[0] = root;
// in other situation, we have to compute M2L a level 1
// but also
// the cell at level >= 0
CellClass upperCells[nbLevelAboveRoot+1];
upperCells[nbLevelAboveRoot] = root;
// Then M2M from level 0 to level -LIMITE
{
CellClass* virtualChild[8];
for(int idxLevel = 1 ; idxLevel < periodicLimit ; ++idxLevel){
for(int idxChild = 0 ; idxChild < 8 ; ++idxChild){
virtualChild[idxChild] = &upperCells[idxLevel-1];
// Then M2M from level 0 to level -LIMITE
{
CellClass* virtualChild[8];
for(int idxLevel = nbLevelAboveRoot - 1 ; idxLevel >= 0 ; --idxLevel){
FMemUtils::setall(virtualChild, &upperCells[idxLevel+1], 8);
kernels[0]->M2M( &upperCells[idxLevel], virtualChild, idxLevel + 2);
}
kernels[0]->M2M( &upperCells[idxLevel], virtualChild, -idxLevel);
}
}
// Then M2L at all level
{
// We say that we are in the child index 0
// So we can compute one time the relative indexes
const CellClass* neighbors[343];
memset(neighbors, 0, sizeof(CellClass*) * 343);
for(int idxX = -2 ; idxX <= 3 ; ++idxX){
for(int idxY = -2 ; idxY <= 3 ; ++idxY){
for(int idxZ = -2 ; idxZ <= 3 ; ++idxZ){
if( FMath::Abs(idxX) > 1 || FMath::Abs(idxY) > 1 || FMath::Abs(idxZ) > 1){
neighbors[(((idxX+3)*7) + (idxY+3))*7 + (idxZ + 3)] = reinterpret_cast<const CellClass*>(~0);
// Then M2L at all level
{
// We say that we are in the child index 0
// So we can compute one time the relative indexes
const CellClass* neighbors[343];
memset(neighbors, 0, sizeof(CellClass*) * 343);
for(int idxX = -2 ; idxX <= 3 ; ++idxX){
for(int idxY = -2 ; idxY <= 3 ; ++idxY){
for(int idxZ = -2 ; idxZ <= 3 ; ++idxZ){
if( FMath::Abs(idxX) > 1 || FMath::Abs(idxY) > 1 || FMath::Abs(idxZ) > 1){
neighbors[(((idxX+3)*7) + (idxY+3))*7 + (idxZ + 3)] = reinterpret_cast<const CellClass*>(~0);
}
}
}
}
}
const int counter = 189;
for(int idxLevel = 0 ; idxLevel < periodicLimit ; ++idxLevel ){
for(int idxNeigh = 0 ; idxNeigh < 343 ; ++idxNeigh){
if(neighbors[idxNeigh]){
neighbors[idxNeigh] = &upperCells[idxLevel];
for(int idxLevel = nbLevelAboveRoot ; idxLevel > 0 ; --idxLevel ){
for(int idxNeigh = 0 ; idxNeigh < 343 ; ++idxNeigh){
if(neighbors[idxNeigh]){
neighbors[idxNeigh] = &upperCells[idxLevel];
}
}
kernels[0]->M2L( &upperCells[idxLevel] , neighbors, 189, idxLevel + 2);
}
// We had the last level border
memset(neighbors, 0, sizeof(CellClass*) * 343);
for(int idxX = -3 ; idxX <= 3 ; ++idxX){
for(int idxY = -3 ; idxY <= 3 ; ++idxY){
for(int idxZ = -3 ; idxZ <= 3 ; ++idxZ){
if( FMath::Abs(idxX) > 1 || FMath::Abs(idxY) > 1 || FMath::Abs(idxZ) > 1){
neighbors[(((idxX+3)*7) + (idxY+3))*7 + (idxZ + 3)] = &upperCells[0];
}
}
}
}
kernels[0]->M2L( &upperCells[idxLevel] , neighbors, counter, -idxLevel);
kernels->M2L( &upperCells[0] , neighbors, 343-27, 2);
}
}
// Finally L2L until level 0
{
CellClass* virtualChild[8];
memset(virtualChild, 0, sizeof(CellClass*) * 8);
for(int idxLevel = periodicLimit - 1 ; idxLevel > 0 ; --idxLevel){
virtualChild[0] = &upperCells[idxLevel-1];
kernels[0]->L2L( &upperCells[idxLevel], virtualChild, -idxLevel);
// Finally L2L until level 0
{
CellClass* virtualChild[8];
memset(virtualChild, 0, sizeof(CellClass*) * 8);
for(int idxLevel = 0 ; idxLevel < nbLevelAboveRoot ; ++idxLevel){
virtualChild[0] = &upperCells[idxLevel+1];
kernels[0]->L2L( &upperCells[idxLevel], virtualChild, idxLevel + 2);
}
}
}
root = upperCells[0];
}
root = upperCells[nbLevelAboveRoot];
}
};
......
#ifndef FGLOBALPERIODIC_HPP
#define FGLOBALPERIODIC_HPP
///////////////////////////////////////////////////////
// Periodic condition definition
///////////////////////////////////////////////////////
enum PeriodicCondition {
DirPlusX = 1 << 0,
DirMinusX = 1 << 1,
DirPlusY = 1 << 2,
DirMinusY = 1 << 3,
DirPlusZ = 1 << 4,
DirMinusZ = 1 << 5,
DirX = (DirPlusX | DirMinusX),
DirY = (DirPlusY | DirMinusY),
DirZ = (DirPlusZ | DirMinusZ),
AllDirs = (DirX | DirY | DirZ)
};
bool testPeriodicCondition(const int conditions, const PeriodicCondition testConditions) {
return (conditions & testConditions) == testConditions;
}
#endif // FGLOBALPERIODIC_HPP
......@@ -86,8 +86,8 @@ int main(int argc, char ** argv){
const int NbLevels = FParameters::getValue(argc,argv,"-h", 4);
const int SizeSubLevels = FParameters::getValue(argc,argv,"-sh", 2);
const int DevP = FParameters::getValue(argc,argv,"-P", 5);
const int BoundaryDeep = FParameters::getValue(argc,argv,"-bd", 5);
const int DevP = FParameters::getValue(argc,argv,"-P", 9);
const int PeriodicDeep = FParameters::getValue(argc,argv,"-per", 2);
const char* const filename = FParameters::getStr(argc,argv,"-f", "../Data/testEwal417.dt");
FTic counter;
......@@ -119,6 +119,7 @@ int main(int argc, char ** argv){
for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
loader.fillParticle(particles[idxPart]);
// reset forces and insert in the tree
particles[idxPart].setIndex(idxPart);
ParticleClass part = particles[idxPart];
part.setForces(0,0,0);
part.setPotential(0);
......@@ -130,46 +131,61 @@ int main(int argc, char ** argv){
// -----------------------------------------------------
std::cout << "Create kernel ..." << std::endl;
std::cout << "Create kernel & run simu ..." << std::endl;
counter.tic();
KernelClass kernels(DevP, NbLevels,loader.getBoxWidth(),loader.getCenterOfBox(), BoundaryDeep);
counter.tac();
std::cout << "Done " << " in " << counter.elapsed() << "s)." << std::endl;
// -----------------------------------------------------
std::cout << "Working on particles ..." << std::endl;
FmmClass algo(&tree,&kernels,BoundaryDeep);
counter.tic();
FmmClass algo(&tree,PeriodicDeep);
KernelClass kernels( DevP, algo.treeHeightForKernel(),
algo.boxwidthForKernel(loader.getBoxWidth()), loader.getCenterOfBox());
algo.setKernel(&kernels);
algo.execute();
counter.tac();
std::cout << "Done " << "(@Algorithm = " << counter.elapsed() << "s)." << std::endl;
// -----------------------------------------------------
{
FMath::FAccurater potentialDiff;
FMath::FAccurater fx, fy, fz;
OctreeClass::Iterator octreeIterator(&tree);
octreeIterator.gotoBottomLeft();
do{
ContainerClass::ConstBasicIterator iter(*octreeIterator.getCurrentListTargets());
while( iter.hasNotFinished() ){
std::cout << ">> index " << iter.data().getIndex() << " type " << iter.data().getType() << std::endl;
std::cout << "x " << iter.data().getPosition().getX() << " y " << iter.data().getPosition().getY() << " z " << iter.data().getPosition().getZ() << std::endl;
std::cout << "fx " << iter.data().getForces().getX() << " fy " << iter.data().getForces().getY() << " fz " << iter.data().getForces().getZ() << std::endl;
std::cout << "physical value " << iter.data().getPhysicalValue() << " potential " << iter.data().getPotential() << std::endl;
const ParticleClass& part = particles[iter.data().getIndex()];
std::cout << "x " << part.getPosition().getX() << " y " << part.getPosition().getY() << " z " << part.getPosition().getZ() << std::endl;
std::cout << "fx " <<part.getForces().getX() << " fy " << part.getForces().getY() << " fz " << part.getForces().getZ() << std::endl;
std::cout << "physical value " << part.getPhysicalValue() << " potential " << part.getPotential() << std::endl;
std::cout << ">> index " << iter.data().getIndex() << " type " << iter.data().getType() << std::endl;
std::cout << "Good x " << part.getPosition().getX() << " y " << part.getPosition().getY() << " z " << part.getPosition().getZ() << std::endl;
std::cout << "FMM x " << iter.data().getPosition().getX() << " y " << iter.data().getPosition().getY() << " z " << iter.data().getPosition().getZ() << std::endl;
std::cout << "Good fx " <<part.getForces().getX() << " fy " << part.getForces().getY() << " fz " << part.getForces().getZ() << std::endl;
std::cout << "FMM fx " << iter.data().getForces().getX() << " fy " << iter.data().getForces().getY() << " fz " << iter.data().getForces().getZ() << std::endl;
std::cout << "GOOD physical value " << part.getPhysicalValue() << " potential " << part.getPotential() << std::endl;
std::cout << "FMM physical value " << iter.data().getPhysicalValue() << " potential " << iter.data().getPotential() << std::endl;
std::cout << "\n";
potentialDiff.add(part.getPotential(),iter.data().getPotential());
fx.add(part.getForces().getX(),iter.data().getForces().getX());
fy.add(part.getForces().getY(),iter.data().getForces().getY());
fz.add(part.getForces().getZ(),iter.data().getForces().getZ());