Mentions légales du service

Skip to content
Snippets Groups Projects
statisticsOnOctree.cpp 13.64 KiB
// ===================================================================================
// 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 <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>

#include "../../Src/Utils/FParameters.hpp"
#include "../../Src/Containers/FOctree.hpp"

#include "../../Src/Components/FBasicCell.hpp"
#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Components/FBasicParticleContainer.hpp"


#include "../../Src/Utils/FMath.hpp"
#include "../../Src/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
//!
//!  <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> General arguments:</b>
//!     \param   -help(-h)      to see the parameters available in this driver
//!     \param   -depth          The depth of the octree
//!     \param   -subdepth     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    -bin              if the input file in binary mode
//!     \param   -outfile name Generic name  for output file  (without extension)
//!
//!  <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
//
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
                   <<	     "      -subdepth      specifies the size of the sub octree   " << std::endl
                   <<     "      -infile name    specifies the name of the particle distribution" << std::endl
                   <<    "        -bin              if the input file in binary mode"<< std::endl
                   <<     "      -outfile name  specifies the file for the diagnostics" << std::endl
                   <<     "      -histP              build the histogram of the particle number per leaf"<<std::endl;
}

int main(int argc, char ** argv){
	typedef FBasicParticleContainer<0>                                    ContainerClass;
	typedef FSimpleLeaf< ContainerClass >                              LeafClass;
	typedef FOctree< FBasicCell, ContainerClass , LeafClass >  OctreeClass;
	if(FParameters::existParameter(argc, argv, "-h")||FParameters::existParameter(argc, argv, "-help")|| (argc < 3 )){
		usage() ;
		exit(-1);
	}
	//
	//   Octree parameters
	//
	const int TreeHeight        = FParameters::getValue(argc,argv,"-depth", 5);
	const int SubTreeHeight  = FParameters::getValue(argc,argv,"-subdepth", 3);
	//
	//  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 <<	 "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, "-histP")){
				int size = maxParticles+1;
				int * hist = new int [size] ;
				memset(hist,0,(size)*sizeof(int));
				octreeIterator.gotoBottomLeft();
				do{
					nbPart  = octreeIterator.getCurrentSrcTargets()->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;
}