diff --git a/Src/Core/FFmmAlgorithmThreadProc.hpp b/Src/Core/FFmmAlgorithmThreadProc.hpp index fae02da01df2c2973809325c379c49afe7552930..984143181c50c6963e588d64c442a6a38de0cef1 100644 --- a/Src/Core/FFmmAlgorithmThreadProc.hpp +++ b/Src/Core/FFmmAlgorithmThreadProc.hpp @@ -466,6 +466,9 @@ public: FDEBUG(FTic prepareCounter); FDEBUG(FTic gatherCounter); + ////////////////////////////////////////////////////////////////// + // First know what to send to who + ////////////////////////////////////////////////////////////////// // pointer to send typename OctreeClass::Iterator* toSend[nbProcess * OctreeHeight]; @@ -560,6 +563,9 @@ public: } + ////////////////////////////////////////////////////////////////// + // Gather this information + ////////////////////////////////////////////////////////////////// FDEBUG(gatherCounter.tic()); // All process say to each others @@ -569,6 +575,11 @@ public: mpiassert( MPI_Allgather( indexToSend, nbProcess * OctreeHeight, MPI_INT, globalReceiveMap, nbProcess * OctreeHeight, MPI_INT, MPI_COMM_WORLD), __LINE__ ); FDEBUG(gatherCounter.tac()); + + ////////////////////////////////////////////////////////////////// + // Send and receive for real + ////////////////////////////////////////////////////////////////// + FDEBUG(sendCounter.tic()); // Then they can send and receive (because they know what they will receive) // To send in asynchrone way @@ -608,6 +619,10 @@ public: } FDEBUG(sendCounter.tac()); + ////////////////////////////////////////////////////////////////// + // Do M2L + ////////////////////////////////////////////////////////////////// + { typename OctreeClass::Iterator octreeIterator(tree); octreeIterator.moveDown(); @@ -643,6 +658,9 @@ public: } } + ////////////////////////////////////////////////////////////////// + // Wait received data and compute + ////////////////////////////////////////////////////////////////// // Wait to receive every things (and send every things) MPI_Waitall(iterRequest, requests, 0); @@ -675,6 +693,7 @@ public: } // for each cells do{ + // copy cells that need data from others if(leafsNeedOther[idxLevel]->get(realCellId++)){ iterArray[numberOfCells++] = octreeIterator; } @@ -725,6 +744,10 @@ public: FDEBUG( FDebug::Controller << "\t\t Prepare : " << prepareCounter.cumulated() << " s\n" ); } + ////////////////////////////////////////////////////////////////// + // ---------------- L2L --------------- + ////////////////////////////////////////////////////////////////// + { // second L2L FDEBUG( FDebug::Controller.write("\tStart Downward Pass (L2L)\n").write(FDebug::Flush); ); FDEBUG(FTic counterTime); @@ -1076,6 +1099,7 @@ public: MPI_Waitall(iterRequest, requests, 0); FDEBUG(waitCounter.tac()); + // Create an octree with leaves from others OctreeClass otherP2Ptree( tree->getHeight(), tree->getSubHeight(), tree->getBoxWidth(), tree->getBoxCenter() ); for(int idxProc = 0 ; idxProc < nbProcess ; ++idxProc){ for(int idxPart = 0 ; idxPart < globalReceiveMap[idxProc * nbProcess + idProcess] ; ++idxPart){ diff --git a/Src/Files/FMpiTreeBuilder.hpp b/Src/Files/FMpiTreeBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7183936c48c18444fd6f64fe76840777e1737dc --- /dev/null +++ b/Src/Files/FMpiTreeBuilder.hpp @@ -0,0 +1,563 @@ +#ifndef FMPITREEBUILDER_H +#define FMPITREEBUILDER_H + + +#include "../Utils/FQuickSort.hpp" + +template<class ContainerClass, class ParticleClass> +class FMpiTreeBuilder{ + static long getTreeCoordinate(const FReal inRelativePosition, const FReal boxWidthAtLeafLevel) { + const FReal indexFReal = inRelativePosition / boxWidthAtLeafLevel; + const long index = FMath::dfloor(indexFReal); + if( index && FMath::LookEqual(inRelativePosition, boxWidthAtLeafLevel * index ) ){ + return index - 1; + } + return index; + } + + /** get current rank */ + static int MpiGetRank(MPI_Comm comm = MPI_COMM_WORLD){ + int rank(0); + MPI_Comm_rank(comm, &rank); + return rank; + } + + /** get current nb procs */ + static int MpiGetNbProcs(MPI_Comm comm = MPI_COMM_WORLD){ + int nb(0); + MPI_Comm_size(comm, &nb); + return nb; + } + + static void receiveDataFromTag(const int inSize, const int inTag, void* const inData, int* const inSource = 0, int* const inFilledSize = 0){ + MPI_Status status; + MPI_Recv(inData, inSize, MPI_CHAR, MPI_ANY_SOURCE, inTag, MPI_COMM_WORLD, &status); + if(inSource) *inSource = status.MPI_SOURCE; + if(inFilledSize) MPI_Get_count(&status,MPI_CHAR,inFilledSize); + } + + template< class T > + static T GetLeft(const T inSize) { + const float step = (float(inSize) / MpiGetNbProcs()); + return T(FMath::Ceil(step * MpiGetRank())); + } + + template< class T > + static T GetRight(const T inSize) { + const float step = (float(inSize) / MpiGetNbProcs()); + const T res = T(FMath::Ceil(step * (MpiGetRank()+1))); + if(res > inSize) return inSize; + else return res; + } + + template< class T > + static T GetOtherRight(const T inSize, const int other) { + const float step = (float(inSize) / MpiGetNbProcs()); + const T res = T(FMath::Ceil(step * (other+1))); + if(res > inSize) return inSize; + else return res; + } + + struct ParticlesGroup { + int number; + int positionInArray; + MortonIndex index; + ParticlesGroup(const int inNumber = 0 , const int inPositionInArray = 0, const MortonIndex inIndex = 0) + : number(inNumber), positionInArray(inPositionInArray), index(inIndex) { + } + }; + + + struct IndexedParticle{ + MortonIndex index; + ParticleClass particle; + + operator MortonIndex(){ + return this->index; + } + }; + +public: + template <class OctreeClass, class LoaderClass> + static bool SplitAndSortFile(OctreeClass& treeInterval, int& myNbParticlesCounter, LoaderClass& loader){ + const int rank = MpiGetRank(); + const int nbProcs = MpiGetNbProcs(); + const int NbLevels = treeInterval.getHeight(); + + IndexedParticle* outputArray = 0; + long outputSize = 0; + { + // create particles + IndexedParticle*const realParticlesIndexed = new IndexedParticle[loader.getNumberOfParticles()]; + F3DPosition boxCorner(loader.getCenterOfBox() - (loader.getBoxWidth()/2)); + FTreeCoordinate host; + const FReal boxWidthAtLeafLevel = loader.getBoxWidth() / (1 << (NbLevels - 1) ); + for(long idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){ + loader.fillParticle(realParticlesIndexed[idxPart].particle); + host.setX( getTreeCoordinate( realParticlesIndexed[idxPart].particle.getPosition().getX() - boxCorner.getX(), boxWidthAtLeafLevel )); + host.setY( getTreeCoordinate( realParticlesIndexed[idxPart].particle.getPosition().getY() - boxCorner.getY(), boxWidthAtLeafLevel )); + host.setZ( getTreeCoordinate( realParticlesIndexed[idxPart].particle.getPosition().getZ() - boxCorner.getZ(), boxWidthAtLeafLevel )); + realParticlesIndexed[idxPart].index = host.getMortonIndex(NbLevels - 1); + } + + // sort particles + FQuickSort::QsMpi<IndexedParticle,MortonIndex>(realParticlesIndexed, loader.getNumberOfParticles(),outputArray,outputSize); + delete [] (realParticlesIndexed); + } + // be sure there is no splited leaves + { + MortonIndex otherFirstIndex = -1; + { + FMpi::Request req[2]; + int reqiter = 0; + if( 0 < rank && outputSize){ + MPI_Isend( &outputArray[0].index, 1, MPI_LONG_LONG, rank - 1, 0, MPI_COMM_WORLD, &req[reqiter++]); + } + if( rank != nbProcs - 1){ + MPI_Irecv(&otherFirstIndex, 1, MPI_LONG_LONG, rank + 1, 0, MPI_COMM_WORLD, &req[reqiter++]); + } + + MPI_Waitall(reqiter,req,0); + + if( 0 < rank && !outputSize){ + MPI_Send( &otherFirstIndex, 1, MPI_LONG_LONG, rank - 1, 0, MPI_COMM_WORLD); + } + } + // at this point every one know the first index of his right neighbors + const bool needToRecvBeforeSend = (rank != 0 && ((outputSize && outputArray[0].index == otherFirstIndex) || !outputSize)); + if( needToRecvBeforeSend || (rank == nbProcs - 1) ){ + long sendByOther = 0; + MPI_Recv(&sendByOther, 1, MPI_LONG, rank - 1, 0, MPI_COMM_WORLD,0); + if(sendByOther){ + const IndexedParticle* const reallocOutputArray = outputArray; + const long reallocOutputSize = outputSize; + + outputSize += sendByOther; + outputArray = new IndexedParticle[outputSize]; + memcpy(&outputArray[sendByOther], reallocOutputArray, reallocOutputSize * sizeof(IndexedParticle)); + delete[] reallocOutputArray; + + MPI_Recv(outputArray, sizeof(IndexedParticle) * sendByOther, MPI_BYTE, rank - 1, 0, MPI_COMM_WORLD, 0); + } + } + if(rank != nbProcs - 1){ + long idxPart = outputSize - 1 ; + while(idxPart >= 0 && outputArray[idxPart].index == otherFirstIndex){ + --idxPart; + } + long toSend = outputSize - 1 - idxPart; + MPI_Send( &toSend, 1, MPI_LONG, rank + 1, 0, MPI_COMM_WORLD); + if(toSend){ + MPI_Send( &outputArray[idxPart + 1], toSend * sizeof(IndexedParticle), MPI_BYTE, rank + 1, 0, MPI_COMM_WORLD); + } + if( rank != 0 && !needToRecvBeforeSend ){ + long sendByOther = 0; + MPI_Recv(&sendByOther, 1, MPI_LONG, rank - 1, 0, MPI_COMM_WORLD, 0); + if(sendByOther){ + const IndexedParticle* const reallocOutputArray = outputArray; + const long reallocOutputSize = outputSize; + + outputSize += sendByOther; + outputArray = new IndexedParticle[outputSize]; + memcpy(&outputArray[sendByOther], reallocOutputArray, reallocOutputSize * sizeof(IndexedParticle)); + delete[] reallocOutputArray; + + MPI_Recv(outputArray, sizeof(IndexedParticle) * sendByOther, MPI_BYTE, rank - 1, 0, MPI_COMM_WORLD,0); + } + } + } + } + + // we can insert into the tree + for(int idxPart = 0 ; idxPart < outputSize ; ++idxPart){ + treeInterval.insert(outputArray[idxPart].particle); + } + myNbParticlesCounter = outputSize; + + return true; + } + + template <class OctreeClass, class LoaderClass> + static bool SplitAndSortFileWithoutQS(OctreeClass& treeInterval, int& myNbParticlesCounter, LoaderClass& loader){ + const int rank = MpiGetRank(); + const int nbProcs = MpiGetNbProcs(); + + ////////////////////////////////////////////////////////////////////////////////// + // My method + ////////////////////////////////////////////////////////////////////////////////// + FVector<ParticlesGroup> groups; + ParticleClass*const realParticles = reinterpret_cast<ParticleClass*>(new char[loader.getNumberOfParticles() * sizeof(ParticleClass)]); + + { + OctreeClass sortingTree(treeInterval.getHeight(), treeInterval.getSubHeight() ,loader.getBoxWidth(),loader.getCenterOfBox()); + + ParticleClass particle; + for(long idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){ + loader.fillParticle(particle); + sortingTree.insert(particle); + } + + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + int indexPart = 0; + + typename OctreeClass::Iterator octreeIterator(&sortingTree); + octreeIterator.gotoBottomLeft(); + do{ + typename ContainerClass::ConstBasicIterator iter(*octreeIterator.getCurrentListTargets()); + const MortonIndex indexAtThisLeaf = octreeIterator.getCurrentGlobalIndex(); + + groups.push(ParticlesGroup(octreeIterator.getCurrentListTargets()->getSize(),indexPart, indexAtThisLeaf)); + + while( iter.hasNotFinished() ){ + realParticles[indexPart] = iter.data(); + ++indexPart; + iter.gotoNext(); + } + } while(octreeIterator.moveRight()); + + } + + ////////////////////////////////////////////////////////////////////////////////// + // We send the particle that do not belong to us + ////////////////////////////////////////////////////////////////////////////////// + + MortonIndex min = 0; + MortonIndex max = 0; + + MPI_Reduce( &groups[0].index, &min, 1, MPI_LONG_LONG, MPI_MIN, 0, MPI_COMM_WORLD ); + MPI_Reduce( &groups[groups.getSize() - 1].index, &max, 1, MPI_LONG_LONG, MPI_MAX, 0, MPI_COMM_WORLD ); + + MPI_Bcast ( &min, 1, MPI_LONG_LONG, 0, MPI_COMM_WORLD ); + MPI_Bcast ( &max, 1, MPI_LONG_LONG, 0, MPI_COMM_WORLD ); + + const MortonIndex startIndex = GetLeft(max - min + 1) + min; + const MortonIndex endIndex = GetRight(max - min + 1) + min; + + int*const needToReceive = new int[nbProcs * nbProcs]; + memset(needToReceive,0,nbProcs * nbProcs * sizeof(int)); + + FMpi::Request requests[nbProcs]; + { + int needToSend[nbProcs]; + memset(needToSend, 0, sizeof(int) * nbProcs); + + MortonIndex rightMortonIndex = min; + int groudIndex = 0; + for(int idxProc = 0 ; idxProc < nbProcs && groudIndex < groups.getSize() ; ++idxProc){ + rightMortonIndex = GetOtherRight(max - min + 1, idxProc) + min; + + if(idxProc != rank){ + int size = 0; + int currentGroupIndex = groudIndex; + while(groudIndex < groups.getSize() && groups[groudIndex].index < rightMortonIndex){ + size += groups[groudIndex].number; + ++groudIndex; + } + needToSend[idxProc] = size; + + MPI_Isend(&realParticles[groups[currentGroupIndex].positionInArray], sizeof(ParticleClass) * size, MPI_BYTE , idxProc, 1, MPI_COMM_WORLD, &requests[idxProc]); + } + else{ + needToSend[idxProc] = 0; + while(groudIndex < groups.getSize() && groups[groudIndex].index < rightMortonIndex){ + const int end = groups[groudIndex].positionInArray + groups[groudIndex].number; + for(int idxPart = groups[groudIndex].positionInArray ; idxPart < end ; ++idxPart){ + //std::cout << "\t I keep (" << realParticles[idxPart].getPosition().getX() << ";" << realParticles[idxPart].getPosition().getY() << ";" << realParticles[idxPart].getPosition().getZ() << ")" << std::endl; + treeInterval.insert(realParticles[idxPart]); + ++myNbParticlesCounter; + } + ++groudIndex; + } + } + } + + MPI_Allgather( needToSend, nbProcs, MPI_INT, needToReceive, nbProcs, MPI_INT, MPI_COMM_WORLD); + } + + + ////////////////////////////////////////////////////////////////////////////////// + // We receive others particles and insert them in the tree + ////////////////////////////////////////////////////////////////////////////////// + int CounterProcToReceive(0); + int maxPartToReceive(0); + for(int idxProc = 0 ; idxProc < nbProcs ; ++idxProc){ + if(idxProc != rank && needToReceive[nbProcs * idxProc + rank]){ + ++CounterProcToReceive; + if(maxPartToReceive < needToReceive[nbProcs * idxProc + rank]){ + maxPartToReceive = needToReceive[nbProcs * idxProc + rank]; + } + } + } + + + ParticleClass*const iterParticles = reinterpret_cast<ParticleClass*>(new char[maxPartToReceive * sizeof(ParticleClass)]); + // we receive message from nb proc - 1 (from every other procs + for(int idxProc = 0 ; idxProc < CounterProcToReceive ; ++idxProc){ + MPI_Status status; + MPI_Probe( MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status ); + const int source = status.MPI_SOURCE; + + const int nbPartFromProc = needToReceive[nbProcs * source + rank]; + int received(0); + + MPI_Recv(iterParticles, sizeof(ParticleClass) * nbPartFromProc, MPI_BYTE, source, 1, MPI_COMM_WORLD, &status); + MPI_Get_count(&status,MPI_BYTE, &received); + + for(int idxPart = 0 ; idxPart < nbPartFromProc ; ++idxPart){ + //std::cout << "\t We receive a new particle (" << (*iterParticles).getPosition().getX() << ";" << (*iterParticles).getPosition().getY() << ";" << (*iterParticles).getPosition().getZ() << ")" << std::endl; + treeInterval.insert(iterParticles[idxPart]); + ++myNbParticlesCounter; + } + } + + for(int idxProc = 0 ; idxProc < nbProcs ; ++idxProc){ + if(idxProc != rank && needToReceive[nbProcs * rank + idxProc ]){ + MPI_Wait(&requests[idxProc], 0); + } + } + + delete [] reinterpret_cast<char*>(realParticles); + delete [] needToReceive; + + return true; + } + + template <class OctreeClass> + static bool IntervalsToTree(OctreeClass& realTree, OctreeClass& treeInterval, const int myNbParticlesCounter){ + const int rank = MpiGetRank(); + const int nbProcs = MpiGetNbProcs(); + + ////////////////////////////////////////////////////////////////////////////////// + // We inform the master proc about the data we have + ////////////////////////////////////////////////////////////////////////////////// + + FVector<ParticlesGroup> groups; + ParticleClass*const realParticles = myNbParticlesCounter?new ParticleClass[myNbParticlesCounter]:0; + + int nbLeafs = 0; + + // we might now have any particles in our interval + if(myNbParticlesCounter){ + typename OctreeClass::Iterator octreeIterator(&treeInterval); + octreeIterator.gotoBottomLeft(); + int indexPart = 0; + do{ + typename ContainerClass::ConstBasicIterator iter(*octreeIterator.getCurrentListTargets()); + const MortonIndex indexAtThisLeaf = octreeIterator.getCurrentGlobalIndex(); + + groups.push(ParticlesGroup(octreeIterator.getCurrentListTargets()->getSize(),indexPart, indexAtThisLeaf)); + + while( iter.hasNotFinished() ){ + realParticles[indexPart] = iter.data(); + ++indexPart; + iter.gotoNext(); + } + + ++nbLeafs; + } while(octreeIterator.moveRight()); + } + + // receive from left and right + if((rank == 0)){ + MPI_Send(&nbLeafs, sizeof(int), MPI_BYTE , 1, 0, MPI_COMM_WORLD); + } + else if(rank == nbProcs - 1){ + MPI_Send(&nbLeafs, sizeof(int), MPI_BYTE , rank - 1, 0, MPI_COMM_WORLD); + } + // receive + int leftLeafs = 0; + int rightLeafs = 0; + if(!(rank == 0) && rank != nbProcs - 1){ + for(int idxToReceive = 0 ; idxToReceive < 2 ; ++idxToReceive){ + int source(0); + int temp = 0; + receiveDataFromTag(sizeof(int), 0, &temp, &source); + if(source < rank){ // come from left + leftLeafs = temp; + temp += nbLeafs; + MPI_Send(&temp, sizeof(int), MPI_BYTE , rank + 1, 0, MPI_COMM_WORLD); + } + else { // come from right + rightLeafs = temp; + temp += nbLeafs; + MPI_Send(&temp, sizeof(int), MPI_BYTE , rank - 1, 0, MPI_COMM_WORLD); + } + } + } + else { + if((rank == 0)){ // come from right + receiveDataFromTag(sizeof(int), 0, &rightLeafs); + } + else { // come from left + receiveDataFromTag(sizeof(int), 0, &leftLeafs); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // We balance the data + ////////////////////////////////////////////////////////////////////////////////// + + const int totalNbLeafs = (leftLeafs + nbLeafs + rightLeafs); + const int myLeftLeaf = GetLeft(totalNbLeafs); + const int myRightLeaf = GetRight(totalNbLeafs); + + const bool iNeedToSendToLeft = leftLeafs < myLeftLeaf; + const bool iNeedToSendToRight = myRightLeaf < leftLeafs + nbLeafs; + + const bool iWillReceiveFromRight = leftLeafs + nbLeafs < myRightLeaf; + const bool iWillReceiveFromLeft = leftLeafs > myLeftLeaf; + + const bool iDoNotHaveEnoughtToSendRight = myRightLeaf < leftLeafs; + const bool iDoNotHaveEnoughtToSendLeft = leftLeafs + nbLeafs < myLeftLeaf; + + ParticleClass* rpart(0); + int rpartSize(0); + + // Do I need to send to right? + if(iNeedToSendToRight){ + int iNeedToSend = leftLeafs + nbLeafs - myRightLeaf; + int iCanSend = nbLeafs; + int idxSend (0); + + MPI_Send(&iNeedToSend, sizeof(int), MPI_BYTE , rank + 1, 0, MPI_COMM_WORLD); + + while(idxSend < iNeedToSend && idxSend < iCanSend){ + MPI_Send(&groups[nbLeafs - idxSend - 1].number, sizeof(int), MPI_BYTE , rank + 1, 0, MPI_COMM_WORLD); + MPI_Send(&realParticles[groups[nbLeafs - idxSend - 1].positionInArray], sizeof(ParticleClass) * groups[nbLeafs - idxSend - 1].number, + MPI_BYTE , rank + 1, 0, MPI_COMM_WORLD); + + ++idxSend; + } + // I need to wait (idxSend == iCanSend && idxSend < iNeedToSend) + if( iDoNotHaveEnoughtToSendRight ){ // I need to wait + int nbLeafsToRead(0); + receiveDataFromTag(sizeof(int), 0, &nbLeafsToRead); + for(int idxToRead = 0 ; idxToRead < nbLeafsToRead ; ++idxToRead){ + int nbPartToRead(0); + receiveDataFromTag(sizeof(int), 0, &nbPartToRead); + + if(rpartSize < nbPartToRead){ + rpartSize = nbPartToRead; + delete [] (reinterpret_cast<char*>(rpart)); + rpart = reinterpret_cast<ParticleClass*>(new char[nbPartToRead*sizeof(ParticleClass)]); + } + + receiveDataFromTag(nbPartToRead*sizeof(ParticleClass), 0, rpart); + if(idxSend < iNeedToSend){ + MPI_Send(&nbPartToRead, sizeof(int), MPI_BYTE , rank + 1, 0, MPI_COMM_WORLD); + MPI_Send(rpart, sizeof(ParticleClass) * nbPartToRead, MPI_BYTE , rank + 1, 0, MPI_COMM_WORLD); + + ++idxSend; + } + else{ + //insert into tree + for(int idxPart = 0 ; idxPart < nbPartToRead ; ++idxPart){ + realTree.insert(rpart[idxPart]); + } + } + } + } + } + // will I receive from left + if(iNeedToSendToLeft){ + int iNeedToSend = myLeftLeaf - leftLeafs; + int iCanSend = nbLeafs; + int idxSend (0); + + MPI_Send(&iNeedToSend, sizeof(int), MPI_BYTE , rank - 1, 1, MPI_COMM_WORLD); + + while(idxSend < iNeedToSend && idxSend < iCanSend){ + MPI_Send(&groups[idxSend].number, sizeof(int), MPI_BYTE , rank - 1, 1, MPI_COMM_WORLD); + MPI_Send(&realParticles[groups[idxSend].positionInArray], sizeof(ParticleClass) * groups[idxSend].number, + MPI_BYTE , rank - 1, 1, MPI_COMM_WORLD); + + ++idxSend; + } + // Can I do it now? + if( iDoNotHaveEnoughtToSendLeft ){ + int nbLeafsToRead(0); + receiveDataFromTag(sizeof(int), 1, &nbLeafsToRead); + for(int idxToRead = 0 ; idxToRead < nbLeafsToRead ; ++idxToRead){ + int nbPartToRead(0); + receiveDataFromTag(sizeof(int), 1, &nbPartToRead); + + if(rpartSize < nbPartToRead){ + rpartSize = nbPartToRead; + delete [] (reinterpret_cast<char*>(rpart)); + rpart = reinterpret_cast<ParticleClass*>(new char[nbPartToRead*sizeof(ParticleClass)]); + } + + receiveDataFromTag(nbPartToRead*sizeof(ParticleClass), 1, rpart); + if(idxSend < iNeedToSend){ + MPI_Send(&nbPartToRead, sizeof(int), MPI_BYTE , rank - 1, 1, MPI_COMM_WORLD); + MPI_Send(rpart, sizeof(ParticleClass) * nbPartToRead, MPI_BYTE , rank - 1, 1, MPI_COMM_WORLD); + + ++idxSend; + } + else{ + for(int idxPart = 0 ; idxPart < nbPartToRead ; ++idxPart){ + realTree.insert(rpart[idxPart]); + } + } + } + } + } + + // If i will receive from left and I did no already have + if(!(iNeedToSendToRight && iDoNotHaveEnoughtToSendRight) && iWillReceiveFromLeft){ + int nbLeafsToRead(0); + receiveDataFromTag(sizeof(int), 0, &nbLeafsToRead); + for(int idxToRead = 0 ; idxToRead < nbLeafsToRead ; ++idxToRead){ + int nbPartToRead(0); + receiveDataFromTag(sizeof(int), 0, &nbPartToRead); + //printf("%d I will receive %d particles\n",rank, nbPartToRead); + if(rpartSize < nbPartToRead){ + rpartSize = nbPartToRead; + delete [] (reinterpret_cast<char*>(rpart)); + rpart = reinterpret_cast<ParticleClass*>(new char[nbPartToRead*sizeof(ParticleClass)]); + } + + receiveDataFromTag(nbPartToRead*sizeof(ParticleClass), 0, rpart); + for(int idxPart = 0 ; idxPart < nbPartToRead ; ++idxPart){ + realTree.insert(rpart[idxPart]); + } + } + } + // If i will receive from right and I did no already have + if(!(iNeedToSendToLeft && iDoNotHaveEnoughtToSendLeft) && iWillReceiveFromRight){ + int nbLeafsToRead(0); + receiveDataFromTag(sizeof(int), 1, &nbLeafsToRead); + for(int idxToRead = 0 ; idxToRead < nbLeafsToRead ; ++idxToRead){ + int nbPartToRead(0); + receiveDataFromTag(sizeof(int), 1, &nbPartToRead); + //printf("%d I will receive %d particles\n",rank, nbPartToRead); + if(rpartSize < nbPartToRead){ + rpartSize = nbPartToRead; + delete [] (reinterpret_cast<char*>(rpart)); + rpart = reinterpret_cast<ParticleClass*>(new char[nbPartToRead*sizeof(ParticleClass)]); + } + + receiveDataFromTag(nbPartToRead*sizeof(ParticleClass), 1, rpart); + for(int idxPart = 0 ; idxPart < nbPartToRead ; ++idxPart){ + realTree.insert(rpart[idxPart]); + } + } + } + + // insert the particles we already have + if(leftLeafs != totalNbLeafs){ + for(int idxLeafInsert = FMath::Max(myLeftLeaf-leftLeafs,0) ; idxLeafInsert < totalNbLeafs - rightLeafs - leftLeafs - FMath::Max(0,leftLeafs + nbLeafs - myRightLeaf) ; ++idxLeafInsert){ + for(int idxPart = 0 ; idxPart < groups[idxLeafInsert].number ; ++idxPart){ + realTree.insert(realParticles[groups[idxLeafInsert].positionInArray + idxPart]); + } + } + } + + delete [] reinterpret_cast<char*>(rpart); + + return true; + } +}; + +#endif // FMPITREEBUILDER_H