From 3723194a5201afb1c69d62d7e92b58544ffecbe1 Mon Sep 17 00:00:00 2001 From: Quentin Khan <quentin@redbite.com> Date: Mon, 23 Feb 2015 16:00:56 +0100 Subject: [PATCH] statisticsOnOctree remastered to correct some issues --- Examples/statisticsOnOctree.cpp | 562 +++++++++++++++++--------------- 1 file changed, 297 insertions(+), 265 deletions(-) diff --git a/Examples/statisticsOnOctree.cpp b/Examples/statisticsOnOctree.cpp index 24071b91b..1f878b716 100755 --- a/Examples/statisticsOnOctree.cpp +++ b/Examples/statisticsOnOctree.cpp @@ -17,6 +17,7 @@ #include <cstdlib> #include <iostream> #include <fstream> +#include <limits> #include "Utils/FParameters.hpp" #include "Containers/FOctree.hpp" @@ -24,284 +25,315 @@ #include "Components/FBasicCell.hpp" #include "Components/FSimpleLeaf.hpp" #include "Components/FBasicParticleContainer.hpp" - +#include "Kernels/P2P/FP2PParticleContainerIndexed.hpp" #include "Utils/FMath.hpp" #include "Files/FFmaGenericLoader.hpp" #include "Utils/FParameterNames.hpp" -/// \file statisticsOnOctree.cpp -//! -//! \brief Driver to generate statistics on the octree for the particle distribution given by parameter -infile -//! \authors B. Bramas, O. Coulaud -//! -//! This code gives you some statistics (Particles, Cells, P2P and M2L number of operators) on the octree -//! Those statistics are shown level by level. -//! -//! The statistics are -//! -//! <b>for particles:</b> min/max particles per leaf, the average number, the variance and the average number of P2P neighbors. -//! -//! <b>For each level in the octree</b> -//! -//! \arg The number of cells, of adaptive cells (cell with more one child) -//! \arg The average, min and max numbers of M2L operators and also its variance. -//! -//! <b> Statistics options:</b> -//! \param -histP build a file to generate histogram of particles per leaf. The data are store in file given by -outfile arguments and .txt extension - -// Simply create particles and try the kernels -// +/** + * @brief Example of ScallFFM's use. + * @author B. Bramas, O. Coulaud, Q. Khan + * + * This example presents the basics of tree traversal with ScallFFM. Reading the + * source you can find out how to load a tree from an FMA formated file and how + * to move around the tree. Some statistics are produced to show how to get the + * information stored. + * + */ + +// Typedefs to shorten code +typedef FBasicCell CellClass; +typedef FBasicParticleContainer< 0 > ContainerClass; +typedef FSimpleLeaf< ContainerClass > LeafClass; +typedef FOctree< CellClass, ContainerClass, LeafClass > OctreeClass; +namespace FPD = FParameterDefinitions; +// Constant strings for output +const std::string lhead("[STAT] "); +const std::string newline = "\n" + lhead; -int main(int argc, char ** argv){ +int main(int argc, char ** argv) +{ + // Parameter handling + // ------------------------------------------------------------------------- + // Custom parameter const FParameterNames LocalOptionHist = { - {"-histP", "--histogram-stat"} , - "Build the histogram of the particle number per leaf." + {"-histP", "--histogram-stat"}, // option enabling flags + "Build the histogram of the particle number per leaf." // option description }; + + // ScalFFM generic options processing + program's arguments description FHelpDescribeAndExit(argc, argv, "Driver to obtain statistics on the octree.", - FParameterDefinitions::InputFile, FParameterDefinitions::OctreeHeight, - FParameterDefinitions::OctreeSubHeight, - FParameterDefinitions::OutputFile, LocalOptionHist); - - - typedef FBasicParticleContainer<0> ContainerClass; - typedef FSimpleLeaf< ContainerClass > LeafClass; - typedef FOctree< FBasicCell, ContainerClass , LeafClass > OctreeClass; - - // - // Octree parameters - // - const int TreeHeight = FParameters::getValue(argc,argv,FParameterDefinitions::OctreeHeight.options, 5); - const int SubTreeHeight = FParameters::getValue(argc,argv,FParameterDefinitions::OctreeSubHeight.options, 3); - // - // input and output Files parameters - // - const char* const filename = FParameters::getStr(argc,argv,FParameterDefinitions::InputFile.options, "../Data/test20k.fma"); - const std::string genericFileName(FParameters::getStr(argc,argv,FParameterDefinitions::OutputFile.options, "output")); - // - std::cout << "Parameters "<< std::endl - << " Octree Depth "<< TreeHeight <<std::endl - << " SubOctree depth " << SubTreeHeight <<std::endl - <<std::endl; - - // - FFmaGenericLoader loader(filename); - // ----------------------------------------------------- - OctreeClass tree(TreeHeight, SubTreeHeight,loader.getBoxWidth(),loader.getCenterOfBox()); - // - // ----------------------------------------------------- - // Creating and Inserting particles in the tree - // ----------------------------------------------------- - // - std::cout << "Tree box is cubic "<<std::endl - << " Centre: "<< loader.getCenterOfBox() <<std::endl - << " Length: "<< loader.getBoxWidth() <<std::endl <<std::endl; - // - std::cout << "Creating and Inserting " << loader.getNumberOfParticles() << " particles ..." << std::endl; - std::cout << "\tHeight : " << TreeHeight << " \t sub-height : " << SubTreeHeight << std::endl; - FPoint particlePosition, minPos, maxPos; - FReal physicalValue; - for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){ - loader.fillParticle(&particlePosition,&physicalValue); - // - minPos.setX(FMath::Min(minPos.getX(),particlePosition.getX())) ; - minPos.setY(FMath::Min(minPos.getY(),particlePosition.getY())) ; - minPos.setZ(FMath::Min(minPos.getZ(),particlePosition.getZ())) ; - maxPos.setX(FMath::Max(maxPos.getX(),particlePosition.getX())) ; - maxPos.setX(FMath::Max(maxPos.getY(),particlePosition.getY())) ; - maxPos.setX(FMath::Max(maxPos.getZ(),particlePosition.getZ())) ; - // - tree.insert(particlePosition ); - } - std::cout << "Data are inside the box delimited by "<<std::endl - << " Min corner: "<< minPos<<std::endl - << " Max corner: "<< maxPos<<std::endl <<std::endl; - // - // ----------------------------------------------------- - // Start statistics - // ----------------------------------------------------- - // - { // get stats - { // get stats on the leaf level (Particles) - long int allLeaves = (1 << (3* (TreeHeight-1) )) ; - std::cout << std::endl<< "[STAT] Leaf level " << " is " << TreeHeight -1<< std::endl; - std::cout << "[STAT] potentials leafs number is " << allLeaves<< std::endl; - - FReal averageParticles = 0.0, varianceParticles = 0.0 ; - int nbLeafs = 0,minParticles = 1000000.0, maxParticles = 0.0 ; - OctreeClass::Iterator octreeIterator(&tree); - // - // Start to compute statistics on particles - // - int nbPart ,nbTPart=0; - octreeIterator.gotoBottomLeft(); - do{ - nbPart = octreeIterator.getCurrentListTargets()->getNbParticles() ; - minParticles = FMath::Min(minParticles,nbPart) ; - maxParticles = FMath::Max(maxParticles,nbPart) ; - nbTPart += nbPart; - varianceParticles += FReal(nbPart*nbPart) ; - ++nbLeafs; - } while(octreeIterator.moveRight()); - averageParticles = nbTPart/FReal(nbLeafs); - varianceParticles = varianceParticles/FReal(nbLeafs) - averageParticles*averageParticles; - // - std::cout.precision(4); - std::cout << "[STAT] Non empty leafs: " << nbLeafs << " % of non empty leaves: "<<100*static_cast<FReal>(nbLeafs)/static_cast<FReal>(allLeaves)<<" %" << std::endl; - std::cout << "[STAT] Particles on leafs:" << std::endl - << "[STAT] Min: "<< minParticles << std::endl - << "[STAT] Max: "<< maxParticles << std::endl - << "[STAT] Average: "<< averageParticles << std::endl - << "[STAT] Variance: " << varianceParticles << std::endl; - // - // Histogram of particles per leaf - // - - if(FParameters::existParameter(argc, argv, LocalOptionHist.options)){ - int size = maxParticles+1; - int * hist = new int [size] ; - memset(hist,0,(size)*sizeof(int)); - octreeIterator.gotoBottomLeft(); - do{ - nbPart = octreeIterator.getCurrentListSrc()->getNbParticles() ; - ++hist[nbPart] ; - } while(octreeIterator.moveRight()); - // - // write data - // - std::string name(genericFileName + ".txt"); - std::ofstream outfile( name.c_str(), std::ofstream::out); - if(!outfile) { - std::cout << "Cannot open file "<< std::endl; - exit(-1) ; - } // - outfile << "# Particle histogram. "<< size << " chunk" <<std::endl; - for(int i=0 ; i < size ; ++i){ - outfile << i << " " << hist[i] <<std::endl; - } - delete [] hist ; - } - FReal averageNeighbors = 0.0, varianceNeighbors =0.0 ; - int nbBox,minBox=30,maxBox=0; - octreeIterator.gotoBottomLeft(); - ContainerClass* neighborsP2P[27]; - do{ - // - // P2P Neighbors - // - nbBox = tree.getLeafsNeighbors(neighborsP2P, octreeIterator.getCurrentGlobalCoordinate(),TreeHeight-1) ; - // need the current particles and neighbors particles - minBox = FMath::Min(minBox,nbBox) ; - maxBox = FMath::Max(maxBox,nbBox) ; - averageNeighbors += FReal(nbBox); - varianceNeighbors += FReal(nbBox*nbBox) ; - } while(octreeIterator.moveRight()); - // - averageNeighbors/=FReal(nbLeafs) ; - varianceNeighbors = varianceNeighbors/nbLeafs-averageNeighbors*averageNeighbors; - // - std::cout << "[STAT] P2P Neighbors for each leaf " << std::endl - << "[STAT] Min: " << minBox << std::endl - << "[STAT] Max: " << maxBox << std::endl - << "[STAT] Average: " << averageNeighbors<< std::endl - << "[STAT] Variance: " << varianceNeighbors << std::endl<< std::endl; - } - // - // --------------- END LEAVES --------------- - // - { - long long int totalCells = 0; - long long int totalM2L = 0; - long long int totalM2ML2L = 0; - - int nbCellsAtTop = 0; - int nbCellsAtBottom = 0; - - OctreeClass::Iterator octreeIterator(&tree); - octreeIterator.gotoBottomLeft(); - - for(int idxLevel = TreeHeight - 1 ; idxLevel > 1 ; --idxLevel){ - - int nbCellsAtLevel = 0; - int nbChildAtLevel = 0, adaptiveCell=0 ,nbChildForMyCell; - int nbNeighborsAtLevel = 0; - // - int nbM2LNeighbors, minM2L=500,maxM2L=-1; - FReal averageM2LNeighbors=0.0, varianceM2LNeighbors=0.0 ; - // - const FBasicCell* neighborsM2L[343]; - do{ - ++nbCellsAtLevel; - // Check number of - if( idxLevel != TreeHeight - 1 ){ - nbChildForMyCell=0 ; - FBasicCell** child = octreeIterator.getCurrentChild(); - for(int idxChild = 0 ; idxChild < 8 ; ++idxChild){ - if(child[idxChild]) ++nbChildForMyCell; - } - nbChildAtLevel += nbChildForMyCell ; - if(nbChildForMyCell>1) ++adaptiveCell ; - } - const FBasicCell* neighbors[343]; - nbNeighborsAtLevel += tree.getInteractionNeighbors(neighbors, octreeIterator.getCurrentGlobalCoordinate(),idxLevel); - // - // M2L Neighbors - // - nbM2LNeighbors = tree.getInteractionNeighbors(neighborsM2L, octreeIterator.getCurrentGlobalCoordinate(),idxLevel); - minM2L = FMath::Min(minM2L,nbM2LNeighbors) ; - maxM2L = FMath::Max(maxM2L,nbM2LNeighbors) ; - averageM2LNeighbors += FReal(nbM2LNeighbors) ; - varianceM2LNeighbors += FReal(nbM2LNeighbors*nbM2LNeighbors) ; - } while(octreeIterator.moveRight()); - // - averageM2LNeighbors/=FReal(nbCellsAtLevel) ; - varianceM2LNeighbors = varianceM2LNeighbors/nbCellsAtLevel-averageM2LNeighbors*averageM2LNeighbors; - - std::cout << "[STAT] Level = " << idxLevel << std::endl - << "[STAT] >> Nb Cells = \t " << nbCellsAtLevel << std::endl - << "[STAT] >> Nb Adaptive Cells = \t" << adaptiveCell << " Non Adaptive (1 son): " <<100*FReal(nbCellsAtLevel-adaptiveCell)/nbCellsAtLevel<<std::endl - << "[STAT] >> Nb M2M/L2L interactions = \t" << nbChildAtLevel << std::endl - << "[STAT] >> Average M2M/L2L interactions = \t" << FReal(nbChildAtLevel)/FReal(nbCellsAtLevel) << std::endl - << "[STAT] >> Nb M2L interactions = \t" << nbNeighborsAtLevel << std::endl; - std::cout << "[STAT] >> M2L Neighbors for each leaf " << std::endl - << "[STAT] >> Min: " << minM2L << std::endl - << "[STAT] >> Max: " << maxM2L << std::endl - << "[STAT] >> Average: " << averageM2LNeighbors<< std::endl - << "[STAT] >> Variance: " << varianceM2LNeighbors << std::endl<< std::endl; - - totalCells += (long long int)(nbCellsAtLevel); - totalM2L += (long long int)(nbNeighborsAtLevel); - totalM2ML2L += (long long int)(nbChildAtLevel); - nbCellsAtTop = nbCellsAtLevel; - if( idxLevel == TreeHeight - 1 ) nbCellsAtBottom = nbCellsAtLevel; - std::cout << std::endl; - // - // Go to next level - octreeIterator.moveUp(); - octreeIterator.gotoLeft(); - // - } - // - // Global statistics on the octree - // - std::cout << "[STAT] For all the tree\n"; - std::cout << "[STAT] >> Total Nb Cells = " << totalCells-nbCellsAtTop << "\n"; - std::cout << "[STAT] >> Total Nb M2M/L2L interactions = " << totalM2ML2L << "\n"; - std::cout << "[STAT] >> Total Average M2M/L2L interactions = " << FReal(totalM2ML2L-nbCellsAtTop)/FReal(totalCells-nbCellsAtBottom) << "\n"; - std::cout << "[STAT] >> Total Nb M2L interactions per cell = " << totalM2L << "\n"; - std::cout << "[STAT] >> Total Average M2L interactions per cell = " << FReal(totalM2L)/FReal(totalCells) << "\n"; - - } - } - - // ----------------------------------------------------- - - - return 0; + FPD::InputFile, + FPD::OctreeHeight, + FPD::OctreeSubHeight, + FPD::OutputFile, + LocalOptionHist); + + + // Octree, input and output parameters + const int TreeHeight = FParameters::getValue(argc,argv,FPD::OctreeHeight.options, 4); + const int SubTreeHeight= FParameters::getValue(argc,argv,FPD::OctreeSubHeight.options, 1); + const std::string inFileName = + FParameters::getStr(argc, argv, FPD::InputFile.options, "../Data/test20k.fma"); + const std::string outFileName = + FParameters::getStr(argc, argv, FPD::OutputFile.options, "output.txt"); + + std::cout << "Parameters " << std::endl + << "\tOctree Depth : " << TreeHeight << std::endl + << "\tSubOctree depth: " << SubTreeHeight << std::endl + << "\tInput file : " << inFileName << std::endl + << "\tOutput file : " << outFileName << std::endl + << std::endl; + + + // Creating and Inserting particles in the tree + // ------------------------------------------------------------------------- + // The loader reads FMA formated files. The file header is read + // automatically : we have basic information on the tree + // structure. Initially, the tree is empty. + FFmaGenericLoader loader(inFileName.c_str()); + OctreeClass tree(TreeHeight, SubTreeHeight,loader.getBoxWidth(),loader.getCenterOfBox()); + + std::cout << newline + << "Particle file box." << newline + << "\t\tCentre: " << loader.getCenterOfBox() << newline + << "\t\tLength: " << loader.getBoxWidth() + << std::endl << std::endl; + + FReal physicalValue; + FPoint particlePosition, + minPos(loader.getBoxWidth(),loader.getBoxWidth(),loader.getBoxWidth()), + maxPos(0., 0., 0.); + + // Insertion of particles in the tree. + for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){ + // read next particle in file + loader.fillParticle(&particlePosition,&physicalValue); + // insert particle into tree + tree.insert(particlePosition); + // Box bounds stats + minPos.setX( FMath::Min(minPos.getX(), particlePosition.getX()) ) ; + minPos.setY( FMath::Min(minPos.getY(), particlePosition.getY()) ) ; + minPos.setZ( FMath::Min(minPos.getZ(), particlePosition.getZ()) ) ; + maxPos.setX( FMath::Max(maxPos.getX(), particlePosition.getX()) ) ; + maxPos.setY( FMath::Max(maxPos.getY(), particlePosition.getY()) ) ; + maxPos.setZ( FMath::Max(maxPos.getZ(), particlePosition.getZ()) ) ; + } + + std::cout << lhead + "Particle bounding box " << newline + << "\t\tMin corner: " << minPos << newline + << "\t\tMax corner: " << maxPos << std::endl << std::endl; + + + // Statistics computation + // ------------------------------------------------------------------------- + { // Moving around the leaf level to get information on particles + + long int allLeaves = (1 << (3 * (TreeHeight-1) )); // maximum number of leaves + FReal averageParticles = 0.0, varianceParticles = 0.0; + int nbLeafs = 0, nbPart = 0, nbTPart = 0; // number of particles, total number of particles + int minParticles = std::numeric_limits<int>::max(), + maxParticles = 0; + + // Compute statistics on particles + // An octree iterator is used to get through the tree. + OctreeClass::Iterator octreeIterator(&tree); + // We move to the leftmost leaf. + octreeIterator.gotoBottomLeft(); + do { + nbPart = octreeIterator.getCurrentListTargets()->getNbParticles() ; + minParticles = FMath::Min(minParticles,nbPart) ; + maxParticles = FMath::Max(maxParticles,nbPart) ; + nbTPart += nbPart; + varianceParticles += FReal(nbPart*nbPart) ; + ++ nbLeafs; + } while(octreeIterator.moveRight()); // advancing through the level + + averageParticles = nbTPart/FReal(nbLeafs); + varianceParticles = varianceParticles/FReal(nbLeafs) - averageParticles*averageParticles; + + + std::cout.precision(4); + std::cout << lhead + << "Leaf level : " << TreeHeight-1 << newline + << "Max leaf count : " << allLeaves << newline + << "Non empty leaves: " << nbLeafs + << " (" << 100 * static_cast<FReal>(nbLeafs) / static_cast<FReal>(allLeaves) + << "%)" << newline; + std::cout << "Particles in leaves:" << newline + << "\t\tMin :" << std::setw(8) << minParticles + << "\t\tMax :" << std::setw(8) << maxParticles << newline + << "\t\tAverage :" << std::setw(8) << averageParticles + << "\t\tVariance:" << std::setw(8) << varianceParticles + << std::endl << std::endl; + + + // Histogram of particles per leaf + if( FParameters::existParameter(argc, argv, LocalOptionHist.options) ) { + std::vector<int> hist(maxParticles + 1, 0); + + octreeIterator.gotoBottomLeft(); + do { + nbPart = octreeIterator.getCurrentListSrc()->getNbParticles(); + ++hist[nbPart] ; + } while(octreeIterator.moveRight()); + + // write data + std::ofstream outfile(outFileName); + if( ! outfile.good() ) { + std::cerr << "Cannot open file " << outFileName << std::endl; + exit(EXIT_FAILURE); + } + outfile << "# Particle per leaf histogram. " << hist.size() << " chunk" << std::endl; + for(unsigned int i = 0 ; i < hist.size() ; ++i){ + outfile << i << " " << hist[i] << std::endl; + } + } + // Statistics on particles done + + FReal averageNeighbors = 0.0, varianceNeighbors = 0.0 ; + int nbBox, minBox = 100000, maxBox=0; + ContainerClass* neighborsP2P[27]; + + octreeIterator.gotoBottomLeft(); + do {// P2P Neighbors + nbBox = tree.getLeafsNeighbors(neighborsP2P, + octreeIterator.getCurrentGlobalCoordinate(), + TreeHeight-1) ; + // need the current particles and neighbors particles + minBox = FMath::Min(minBox,nbBox) ; + maxBox = FMath::Max(maxBox,nbBox) ; + averageNeighbors += FReal(nbBox); + varianceNeighbors += FReal(nbBox*nbBox) ; + } while(octreeIterator.moveRight()); + + averageNeighbors /= FReal(nbLeafs) ; + varianceNeighbors = varianceNeighbors/nbLeafs-averageNeighbors*averageNeighbors; + + + std::cout << lhead + << "P2P Neighbors for each leaf " << newline + << "\t\tMin :" << std::setw(8) << minBox + << "\t\tMax :" << std::setw(8) << maxBox << newline + << "\t\tAverage :" << std::setw(8) << averageNeighbors + << "\t\tVariance:" << std::setw(8) << varianceNeighbors + << std::endl << std::endl; + } // End of leaves statistics + + + { // Internal cells statistics + long long int totalCells = 0; + long long int totalM2L = 0; + long long int totalM2ML2L = 0; + int nbCellsAtTop = 0; + int nbCellsAtBottom = 0; + + // As for the leaf level, we use an iterator got run through the tree. + OctreeClass::Iterator octreeIterator(&tree); + octreeIterator.gotoBottomLeft(); + // For each level, see end of loop to climb a level in the tree. + for(int idxLevel = TreeHeight - 1 ; idxLevel >= 1 ; --idxLevel){ + + int nbCellsAtLevel = 0; + int nbChildrenAtLevel = 0, adaptiveCell = 0, nbChildrenForMyCell; + int nbNeighborsAtLevel = 0; + + int nbM2LNeighbors = 0, minM2L = 500, maxM2L = -1; + FReal averageM2LNeighbors = 0.0, varianceM2LNeighbors = 0.0; + const CellClass* neighborsM2L[343]; + + do { + ++ nbCellsAtLevel; + // Count children + if( idxLevel != TreeHeight - 1 ) { + nbChildrenForMyCell = 0; + CellClass** children = octreeIterator.getCurrentChild(); + for( int idxChild = 0 ; idxChild < 8 ; ++ idxChild ) { + // Non existing children are NULL + if( children[idxChild] ) + ++ nbChildrenForMyCell; + } + nbChildrenAtLevel += nbChildrenForMyCell; + if( nbChildrenForMyCell > 1 ) + ++ adaptiveCell; + } + // M2L Neighbors + nbM2LNeighbors = + tree.getInteractionNeighbors(neighborsM2L, + octreeIterator.getCurrentGlobalCoordinate(), + idxLevel); + nbNeighborsAtLevel += nbM2LNeighbors; + + minM2L = FMath::Min(minM2L,nbM2LNeighbors) ; + maxM2L = FMath::Max(maxM2L,nbM2LNeighbors) ; + averageM2LNeighbors += FReal(nbM2LNeighbors) ; + varianceM2LNeighbors += FReal(nbM2LNeighbors*nbM2LNeighbors) ; + } while(octreeIterator.moveRight()); + + averageM2LNeighbors /= FReal(nbCellsAtLevel); + varianceM2LNeighbors = varianceM2LNeighbors / nbCellsAtLevel + - averageM2LNeighbors * averageM2LNeighbors; + + totalCells += (long long int)(nbCellsAtLevel); + totalM2L += (long long int)(nbNeighborsAtLevel); + totalM2ML2L += (long long int)(nbChildrenAtLevel); + nbCellsAtTop = nbCellsAtLevel; + if( idxLevel == TreeHeight - 1 ) + nbCellsAtBottom = nbCellsAtLevel; + + + std::cout << "[STAT] " + << "Level " << idxLevel + << newline + << "\tCell count : " << nbCellsAtLevel + << " (adaptive are cells with > 1 children)" << newline + << "\t\tAdaptive:" << std::setw(8) << adaptiveCell + << "\t\tNon adap:" << std::setw(8) << nbCellsAtLevel-adaptiveCell + << newline + << "\tM2M/L2L interact:" << std::setw(8) << nbChildrenAtLevel + << "\t\tAverage :" << std::setw(8) + << FReal(nbChildrenAtLevel)/FReal(nbCellsAtLevel) + << newline + << "\tM2L interactions:" << std::setw(8) << nbNeighborsAtLevel + << newline; + std::cout << "\tM2L Neighbors / leaf: " + << newline + << "\t\tMin :" << std::setw(8) << minM2L + << "\t\tMax :" << std::setw(8) << maxM2L + << newline + << "\t\tAverage :" << std::setw(8) << averageM2LNeighbors + << "\t\tVariance:" << std::setw(8) << varianceM2LNeighbors + << std::endl << std::endl; + + + // Go to next level + octreeIterator.moveUp(); + // Move to leftmost cell on new level + octreeIterator.gotoLeft(); + } + + // Global statistics on the octree + std::cout + << lhead + "Global stats" << newline + << "\tCells = " << totalCells-nbCellsAtTop << newline + << "\tM2L interactions / cell :" << std::setw(8) + << totalM2L << newline + << "\tAverage M2L inter / cell :" << std::setw(8) + << FReal(totalM2L)/FReal(totalCells) << newline + << "\tM2M/L2L interactions :" << std::setw(8) + << totalM2ML2L << newline + << "\tAverage M2M/L2L interact :" << std::setw(8) + << FReal(totalM2ML2L-nbCellsAtTop) / FReal(totalCells-nbCellsAtBottom) + << std::endl; + + } + + return 0; } -- GitLab