#include #include #include #include "../../Src/Utils/FMpi.hpp" #include "../../Src/Containers/FVector.hpp" #include "../../Src/Files/FFmaGenericLoader.hpp" #include "../../Src/Files/FMpiFmaLoader.hpp" #include "../../Src/BalanceTree/FLeafBalance.hpp" #include "../../Src/Containers/FTreeCoordinate.hpp" #include "../../Src/Utils/FQuickSortMpi.hpp" #include "../../Src/Files/FMpiTreeBuilder.hpp" #include "../../Src/Core/FCoreCommon.hpp" #include "../../Src/Utils/FPoint.hpp" #include "../../Src/Utils/FMath.hpp" #include "../../Src/Utils/FParameters.hpp" // ==== CMAKE ===== // @FUSE_MPI // ================ /* Struct Test particle : classic particle but with index In file, * which is the number of line where the part was found. It is a true * constant. */ struct TestParticle{ MortonIndex index; FSize indexInFile; FPoint position; FReal physicalValue; FPoint& getPosition(){ return position; } }; /** This method has been tacken from the octree * it computes a tree coordinate (x or y or z) from real position */ static int getTreeCoordinate(const FReal inRelativePosition, const FReal boxWidthAtLeafLevel) { const FReal indexFReal = inRelativePosition / boxWidthAtLeafLevel; const int index = int(FMath::dfloor(indexFReal)); if( index && FMath::LookEqual(inRelativePosition, boxWidthAtLeafLevel * FReal(index) ) ){ return index - 1; } return index; } /** * This function compare IndexedParticles that are in the same leaf by * sorting them along X,Y and then Z axis. The aim is to get the same * sorting output for each leaf. */ int compareLeafI(const void *a,const void *b){ FMpiTreeBuilder::IndexedParticle partA = *(reinterpret_cast::IndexedParticle*>(a)); FMpiTreeBuilder::IndexedParticle partB = *(reinterpret_cast::IndexedParticle*>(b)); if(partA.particle.getPosition().getX() < partB.particle.getPosition().getX()){ return -1; } else{ if(partA.particle.getPosition().getX() > partB.particle.getPosition().getX()){ return 1; } else{ if(partA.particle.getPosition().getY() < partB.particle.getPosition().getY()){ return -1; } else{ if(partA.particle.getPosition().getY() > partB.particle.getPosition().getY()){ return 1; } else{ if(partA.particle.getPosition().getZ() < partB.particle.getPosition().getZ()){ return -1; } else{ if(partA.particle.getPosition().getZ() > partB.particle.getPosition().getZ()){ return 1; } else{ return 0; } } } } } } } /** * Same function as above but with TestParticle instead of * IndexedParticles (pretty much same thing). */ int compareLeaf(const void *a,const void *b){ TestParticle partA = *(reinterpret_cast(a)); TestParticle partB = *(reinterpret_cast(b)); if(partA.getPosition().getX() < partB.getPosition().getX()){ return -1; } else{ if(partA.getPosition().getX() > partB.getPosition().getX()){ return 1; } else{ if(partA.getPosition().getY() < partB.getPosition().getY()){ return -1; } else{ if(partA.getPosition().getY() > partB.getPosition().getY()){ return 1; } else{ if(partA.getPosition().getZ() < partB.getPosition().getZ()){ return -1; } else{ if(partA.getPosition().getZ() > partB.getPosition().getZ()){ return 1; } else{ return 0; printf("Should not happen\n"); } } } } } } } /** * Compare two articles by MortonIndex, if same morton index, call to * compareLeaf */ int cmpTestParticles(const void* a,const void* b){ const TestParticle partA = *(reinterpret_cast(a)); const TestParticle partB = *(reinterpret_cast(b)); if(partA.index < partB.index){ return -1; } else{ if(partA.index > partB.index){ return 1; } else{ return compareLeaf(a,b); } } } /** This test aimed to validate the Tree Builder algorithms * * Each process runs a sort (from std::qsort) and then a parallel * sort and compare its particles with the global sort. * * Then, each process runs a MergeLeaves, and compare again the output * with the one from sstd::qsort. * * Finally, each process runs EqualizeAndFillTree, and compare again * the output with the one from std::sort. * */ int main(int argc,char* argv[]){ //File to sort const char* const filename = FParameters::getStr(argc,argv,"-f", "../Data/test20k.bin.fma.double"); const unsigned int TreeHeight = FParameters::getValue(argc, argv, "-depth", 5); //First part is Sequential //Since there is no MPI Loader with ascii datas, the file need to be in binary format. FFmaGenericLoader loaderSeq(filename,true); if(!loaderSeq.isOpen()) throw std::runtime_error("Particle file couldn't be opened!") ; //Get the needed informations FReal boxWidth = loaderSeq.getBoxWidth(); FReal boxWidthAtLeafLevel = boxWidth/FReal(1 << (TreeHeight - 1)); FPoint centerOfBox = loaderSeq.getCenterOfBox(); FPoint boxCorner = centerOfBox - boxWidth/2; FTreeCoordinate host; //Copy from the file to the array that will be sorted FSize nbOfParticles = loaderSeq.getNumberOfParticles(); struct TestParticle* arrayOfParticles = new struct TestParticle[nbOfParticles]; for(FSize idxParts=0 ; idxParts::IndexedParticle * arrayToBeSorted = new FMpiTreeBuilder::IndexedParticle[loader.getNumberOfParticles()]; //Copy the TestParticles into an array of indexedParticle for(int i=0 ; i::IndexedParticle* outputArray = 0; FQuickSortMpi::IndexedParticle,MortonIndex,FSize>::QsMpi(arrayToBeSorted,loader.getNumberOfParticles(),outputArray,outputSize,app.global()); //Sum the outputSize of every body for knowing where to start inside the sorted array FSize starter = 0; //We use a prefix sum MPI_Exscan(&outputSize,&starter,1,MPI_LONG_LONG_INT,MPI_SUM,app.global().getComm()); //We sort the output array relatvely to position inside leafs FSize inc = 0; FMpiTreeBuilder::IndexedParticle * saveForSort = outputArray; int nbOfPartsInLeaf = 0; while(inc < outputSize){ while(outputArray[inc].index == saveForSort->index){ inc++; nbOfPartsInLeaf++; } qsort((void*)saveForSort,nbOfPartsInLeaf,sizeof(FMpiTreeBuilder::IndexedParticle),compareLeafI); nbOfPartsInLeaf = 0; saveForSort = &outputArray[inc]; } bool resultQsMpi = true; //passed.. //Test for(int i=0 ; i QsMpi didn't make it !!\n",app.global().processId()); } else{ printf("Proc :: %d ====> QsMpi successfull !!\n",app.global().processId()); } //Test MergeLeaves bool resultMergeLeaves= true; //inputs needed TestParticle * leavesArray = 0; FSize * leavesIndices = 0; FSize leaveSize = 0; FMpiTreeBuilder::testMergeLeaves(app.global(),outputArray,&outputSize,&leavesIndices,&leavesArray,&leaveSize); //Compare again the results with the output of std::qsort //we need to know how many parts still remains FSize CounterStart = 0; //We use a prefix sum MPI_Exscan(&outputSize,&CounterStart,1,MPI_LONG_LONG_INT,MPI_SUM,app.global().getComm()); //Test if no problems for(FSize k=0 ; k MergeLeaves didn't make it !!\n",app.global().processId()); } else{ printf("Proc :: %d ====> MergeLeaves successfull !!\n",app.global().processId()); } //Test the Equalize and Fill tree FLeafBalance balancer; FVector finalParticles; bool resultEqualize = true; FMpiTreeBuilder::testEqualizeAndFillTree(app.global(),&finalParticles,leavesIndices,leavesArray,leaveSize,outputSize,&balancer); //Ok now count the Particles at the end of the Equalize int finalNbPart = finalParticles.getSize(); int finalStart = 0; MPI_Exscan(&finalNbPart,&finalStart,1,MPI_INT,MPI_SUM,app.global().getComm()); for (int k=0; k Equalize didn't make it !!\n",app.global().processId()); } else{ printf("Proc :: %d ====> Equalize successfull !!\n",app.global().processId()); } delete [] originalArray; delete [] arrayOfParticles; delete [] arrayToBeSorted; delete [] outputArray; return EXIT_SUCCESS; }