// =================================================================================== // Copyright ScalFmm 2011 INRIA, Olivier Coulaud, Berenger Bramas // 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 #include #include #include #include #include "Utils/FParameters.hpp" #include "Containers/FOctree.hpp" #include "adaptiveTree/FAdaptCell.hpp" #include "adaptiveTree/FAdaptTools.hpp" #include "Components/FSimpleIndexedLeaf.hpp" #include "Components/FBasicParticleContainer.hpp" #include "Utils/FMath.hpp" #include "Files/FFmaGenericLoader.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 //! //! for particles: min/max particles per leaf, the average number, the variance and the average number of P2P neighbors. //! //! For each level in the octree //! //! \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. //! //! General arguments: //! \param -help(-h) to see the parameters available in this driver //! \param -depth The depth of the octree //! \param -sh Specifies the size of the sub octree //! //! \param -infile name Name of the particles file. The file have to be in our FMA format //! \param -outfile name Generic name for output file (without extension) //! //! Statistics options: //! \param -stat to build the statistivs on the octree //! \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. (only if -stat is set) // \param -sM s_min^M threshold for Multipole expansion (l+1)^2 for Spherical harmonics" // \param -sL s_min^M threshold for local expansion (l+1)^2 for Spherical harmonics" // Simply create particles and try the kernels // void usage() { std::cout << "Driver to obtain statistics on the octree" << std::endl; std::cout << "Options "<< std::endl << " -help to see the parameters " << std::endl << " -depth the depth of the octree "<< std::endl << " -sh specifies the size of the sub octree " << std::endl << " -infile name specifies the name of the particle distribution" << std::endl << " -outfile name specifies the file for the diagnostics" << std::endl << " -histP build the histogram of the particle number per leaf"< ContainerClass; typedef FSimpleIndexedLeaf LeafClass; typedef FAdaptCell CellClass; typedef FOctree OctreeClass; // if(FParameters::existParameter(argc, argv, "-h")||FParameters::existParameter(argc, argv, "-help")|| (argc < 3 )){ usage() ; exit(-1); } // // Octree parameters // const int NbLevels = FParameters::getValue(argc,argv,"-depth", 5); const int SizeSubLevels = FParameters::getValue(argc,argv,"-sh", 3); const int sminM = FParameters::getValue(argc,argv,"-sM", 0); const int sminL = FParameters::getValue(argc,argv,"-sL", 0); // // input and output Files parameters // const char* const filename = FParameters::getStr(argc,argv,"-infile", "../Data/test20k.fma"); const std::string genericFileName(FParameters::getStr(argc,argv,"-outfile", "output")); // std::cout << "Opening : " << filename << "\n"; FFmaGenericLoader loader(filename); if(!loader.isOpen()){ std::cout << "Loader Error, " << filename << " is missing\n"; return 1; } // // ----------------------------------------------------- OctreeClass tree(NbLevels, SizeSubLevels,loader.getBoxWidth(),loader.getCenterOfBox()); // // ----------------------------------------------------- // Creating and Inserting particles in the tree // ----------------------------------------------------- // std::cout << "Tree box is cubic "<getNbParticles() ; minParticles = FMath::Min(minParticles,nbPart) ; maxParticles = FMath::Max(maxParticles,nbPart) ; nbTPart += nbPart; varianceParticles += FReal(nbPart*nbPart) ; ++nbLeafs; if(nbPart < sminM){ ++removeM; } } 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(nbLeafs)/static_cast(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; std::cout << "[STAT] number of P2M to remove: " << removeM << std::endl; // // Histogram of particles per leaf // if(FParameters::existParameter(argc, argv, "-histP")){ int size = maxParticles+1; int * hist = new int [size] ; memset(hist,0,(size)*sizeof(int)); octreeIterator.gotoBottomLeft(); do{ nbPart = octreeIterator.getCurrentListTargets()->getNbParticles() ; ++hist[nbPart] ; } while(octreeIterator.moveRight()); // // write data // std::ofstream outfile( genericFileName + ".txt", std::ofstream::out); if(!outfile) { std::cout << "Cannot open file "<< std::endl; exit(-1) ; } // outfile << "# Particle histogram. "<< size << " chunk" <= 1 ; --idxLevel){ removeM =0 ; 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 CellClass* neighborsM2L[343]; do{ ++nbCellsAtLevel; // Check number of if( idxLevel != NbLevels - 1 ){ nbChildForMyCell=0 ; auto** child = octreeIterator.getCurrentChild(); auto & myCell = *(octreeIterator.getCurrentCell()); int nbPart = 0 ; // std::cout << "NB: "; for(int idxChild = 0 ; idxChild < 8 ; ++idxChild){ if(child[idxChild]) { ++nbChildForMyCell; nbPart += child[idxChild]->getnbPart(); // std::cout << " "<< child[idxChild]->getnbPart(); } } // std::cout << std::endl; octreeIterator.getCurrentCell()->addPart(nbPart); if(octreeIterator.getCurrentCell()->getnbPart() < sminM){ ++removeM; } nbChildAtLevel += nbChildForMyCell ; if(nbChildForMyCell>1) { ++adaptiveCell ; } else {myCell.setCelladaptive();} } const CellClass* 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<> Number of M2M to remove: " << removeM << 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 == NbLevels - 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"; std::cout << "nbCellsAtTop " << nbCellsAtTop <