From c93165f0d48737ce788a687347f62376e9e060e1 Mon Sep 17 00:00:00 2001 From: bramas <berenger.bramas@inria.fr> Date: Sun, 19 Oct 2014 20:25:32 +0200 Subject: [PATCH] Work in progress Section Task for the blocked version --- Src/GroupTree/FGroupTaskAlgorithm.hpp | 512 ++++++++++++++++++++++++++ Tests/noDist/testBlockedRoation.cpp | 4 +- 2 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 Src/GroupTree/FGroupTaskAlgorithm.hpp diff --git a/Src/GroupTree/FGroupTaskAlgorithm.hpp b/Src/GroupTree/FGroupTaskAlgorithm.hpp new file mode 100644 index 000000000..19d7f7815 --- /dev/null +++ b/Src/GroupTree/FGroupTaskAlgorithm.hpp @@ -0,0 +1,512 @@ +#ifndef FGROUPTASKALGORITHM_HPP +#define FGROUPTASKALGORITHM_HPP + +#include "../Utils/FGlobal.hpp" +#include "../Core/FCoreCommon.hpp" +#include "../Utils/FQuickSort.hpp" +#include "../Containers/FTreeCoordinate.hpp" +#include "../Utils/FLog.hpp" +#include "../Utils/FTic.hpp" + +#include <list> +#include <vector> + +#include <omp.h> + +template <class OctreeClass, class CellContainerClass, class CellClass, class KernelClass, class ParticleGroupClass, class ParticleContainerClass> +class FGroupTaskAlgorithm { +protected: + struct OutOfBlockInteraction{ + MortonIndex outIndex; + MortonIndex insideIndex; + int outPosition; + // To sort + bool operator <=(const OutOfBlockInteraction& other) const{ + return outIndex <= other.outIndex; + } + }; + + const int MaxThreads; //< The number of threads + OctreeClass*const tree; //< The Tree + KernelClass** kernels; //< The kernels + +public: + FGroupTaskAlgorithm(OctreeClass*const inTree, KernelClass* inKernels, const int inMaxThreads = -1) + : MaxThreads(inMaxThreads==-1?omp_get_max_threads():inMaxThreads), tree(inTree), kernels(nullptr){ + FAssertLF(tree, "tree cannot be null"); + FAssertLF(inKernels, "kernels cannot be null"); + + kernels = new KernelClass*[MaxThreads]; + for(int idxThread = 0 ; idxThread < MaxThreads ; ++idxThread){ + this->kernels[idxThread] = new KernelClass(*inKernels); + } + + FLOG(FLog::Controller << "FGroupTaskAlgorithm (Max Thread " << MaxThreads << ")\n"); + } + + ~FGroupTaskAlgorithm(){ + for(int idxThread = 0 ; idxThread < MaxThreads ; ++idxThread){ + delete this->kernels[idxThread]; + } + delete[] kernels; + } + + void execute(const unsigned operationsToProceed = FFmmNearAndFarFields){ + FLOG( FLog::Controller << "\tStart FGroupTaskAlgorithm\n" ); + + #pragma omp parallel + { + #pragma omp single nowait + { + if(operationsToProceed & FFmmP2M) bottomPass(); + + if(operationsToProceed & FFmmM2M) upwardPass(); + + if(operationsToProceed & FFmmM2L) transferPass(); + + if(operationsToProceed & FFmmL2L) downardPass(); + + } + + #pragma omp single nowait + { + if( operationsToProceed & FFmmP2P ) directPass(); + } + + #pragma omp barrier + + #pragma omp single nowait + { + if( operationsToProceed & FFmmL2P ) mergePass(); + } + } + } + +protected: + void bottomPass(){ + FLOG( FTic timer; ); + typename std::list<ParticleGroupClass*>::iterator iterParticles = tree->leavesBegin(); + const typename std::list<ParticleGroupClass*>::iterator endParticles = tree->leavesEnd(); + + typename std::list<CellContainerClass*>::iterator iterCells = tree->cellsBegin(tree->getHeight()-1); + const typename std::list<CellContainerClass*>::iterator endCells = tree->cellsEnd(tree->getHeight()-1); + + while(iterParticles != endParticles && iterCells != endCells){ + CellContainerClass* leafCells = (*iterCells); + ParticleGroupClass* containers = (*iterParticles); + #pragma omp task default(shared) firstprivate(leafCells, containers) + { // Can be a task(in:iterParticles, out:iterCells) + const MortonIndex blockStartIdx = leafCells->getStartingIndex(); + const MortonIndex blockEndIdx = leafCells->getEndingIndex(); + KernelClass*const kernel = kernels[omp_get_thread_num()]; + + for(MortonIndex mindex = blockStartIdx ; mindex < blockEndIdx ; ++mindex){ + CellClass* cell = leafCells->getCell(mindex); + if(cell){ + FAssertLF(cell->getMortonIndex() == mindex); + ParticleContainerClass particles = containers->template getLeaf<ParticleContainerClass>(mindex); + FAssertLF(particles.isAttachedToSomething()); + kernel->P2M(cell, &particles); + } + } + } + + ++iterParticles; + ++iterCells; + } + // Wait for task to complete + #pragma omp taskwait + + FAssertLF(iterParticles == endParticles && iterCells == endCells); + FLOG( FLog::Controller << "\t\t bottomPass in " << timer.tacAndElapsed() << "s\n" ); + } + + void upwardPass(){ + FLOG( FTic timer; ); + for(int idxLevel = tree->getHeight()-2 ; idxLevel >= 2 ; --idxLevel){ + typename std::list<CellContainerClass*>::iterator iterCells = tree->cellsBegin(idxLevel); + const typename std::list<CellContainerClass*>::iterator endCells = tree->cellsEnd(idxLevel); + + typename std::list<CellContainerClass*>::iterator iterChildCells = tree->cellsBegin(idxLevel+1); + const typename std::list<CellContainerClass*>::iterator endChildCells = tree->cellsEnd(idxLevel+1); + + while(iterCells != endCells && iterChildCells != endChildCells){ + CellContainerClass* currentCells = (*iterCells); + + CellContainerClass* subCellGroups[8]; + memset(subCellGroups, 0, sizeof(CellContainerClass*) * 8); + + // Skip current group if needed + if( (*iterChildCells)->getEndingIndex() <= ((*iterCells)->getStartingIndex()<<3) ){ + ++iterChildCells; + } + FAssertLF(iterChildCells != endChildCells && ((*iterChildCells)->getStartingIndex()>>3) == (*iterCells)->getStartingIndex()); + // Copy at max 8 groups + int nbSubCellGroups = 0; + subCellGroups[nbSubCellGroups] = (*iterChildCells); + nbSubCellGroups += 1; + while((*iterChildCells)->getEndingIndex() <= (((*iterCells)->getStartingIndex()<<3)+7) + && (++iterChildCells) != endChildCells){ + subCellGroups[nbSubCellGroups] = (*iterChildCells); + nbSubCellGroups += 1; + } + + #pragma omp task default(none) firstprivate(idxLevel, currentCells, subCellGroups, nbSubCellGroups) + { + const MortonIndex blockStartIdx = currentCells->getStartingIndex(); + const MortonIndex blockEndIdx = currentCells->getEndingIndex(); + KernelClass*const kernel = kernels[omp_get_thread_num()]; + int idxSubCellGroup = 0; + + for(MortonIndex mindex = blockStartIdx ; mindex < blockEndIdx && idxSubCellGroup != nbSubCellGroups; ++mindex){ + CellClass* cell = currentCells->getCell(mindex); + if(cell){ + FAssertLF(cell->getMortonIndex() == mindex); + CellClass* child[8] = {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}; + + for(int idxChild = 0 ; idxChild < 8 ; ++idxChild){ + while(idxSubCellGroup != nbSubCellGroups && subCellGroups[idxSubCellGroup]->getEndingIndex() <= ((mindex<<3)+idxChild) ){ + idxSubCellGroup += 1; + } + if( idxSubCellGroup == nbSubCellGroups ){ + break; + } + child[idxChild] = subCellGroups[idxSubCellGroup]->getCell((mindex<<3)+idxChild); + FAssertLF(child[idxChild] == nullptr || child[idxChild]->getMortonIndex() == ((mindex<<3)+idxChild)); + } + + kernel->M2M(cell, child, idxLevel); + } + } + } + + ++iterCells; + } + // Wait this level before the next one + #pragma omp taskwait + + FAssertLF(iterCells == endCells); + FAssertLF((iterChildCells == endChildCells || (++iterChildCells) == endChildCells)); + FAssertLF(iterCells == endCells && (iterChildCells == endChildCells || (++iterChildCells) == endChildCells)); + } + FLOG( FLog::Controller << "\t\t upwardPass in " << timer.tacAndElapsed() << "s\n" ); + } + + void transferPass(){ + FLOG( FTic timer; ); + for(int idxLevel = tree->getHeight()-1 ; idxLevel >= 2 ; --idxLevel){ + typename std::list<CellContainerClass*>::iterator iterCells = tree->cellsBegin(idxLevel); + const typename std::list<CellContainerClass*>::iterator endCells = tree->cellsEnd(idxLevel); + + while(iterCells != endCells){ + std::vector<OutOfBlockInteraction> outsideInteractions; + + { // Can be a task(inout:iterCells, out:outsideInteractions) + const MortonIndex blockStartIdx = (*iterCells)->getStartingIndex(); + const MortonIndex blockEndIdx = (*iterCells)->getEndingIndex(); + + for(MortonIndex mindex = blockStartIdx ; mindex < blockEndIdx ; ++mindex){ + CellClass* cell = (*iterCells)->getCell(mindex); + if(cell){ + FAssertLF(cell->getMortonIndex() == mindex); + MortonIndex interactionsIndexes[189]; + int interactionsPosition[189]; + const FTreeCoordinate coord(cell->getCoordinate()); + int counter = coord.getInteractionNeighbors(idxLevel,interactionsIndexes,interactionsPosition); + + const CellClass* interactions[343]; + memset(interactions, 0, 343*sizeof(CellClass*)); + int counterExistingCell = 0; + + for(int idxInter = 0 ; idxInter < counter ; ++idxInter){ + if( blockStartIdx <= interactionsIndexes[idxInter] && interactionsIndexes[idxInter] < blockEndIdx ){ + CellClass* interCell = (*iterCells)->getCell(interactionsIndexes[idxInter]); + if(interCell){ + FAssertLF(interCell->getMortonIndex() == interactionsIndexes[idxInter]); + FAssertLF(interactions[interactionsPosition[idxInter]] == nullptr); + interactions[interactionsPosition[idxInter]] = interCell; + counterExistingCell += 1; + } + } + else if(interactionsIndexes[idxInter] < mindex){ + OutOfBlockInteraction property; + property.insideIndex = mindex; + property.outIndex = interactionsIndexes[idxInter]; + property.outPosition = interactionsPosition[idxInter]; + outsideInteractions.push_back(property); + } + } + + kernels[0]->M2L( cell , interactions, counterExistingCell, idxLevel); + } + } + } + + + // Manage outofblock interaction + FQuickSort<OutOfBlockInteraction, int>::QsSequential(outsideInteractions.data(),int(outsideInteractions.size())); + + typename std::list<CellContainerClass*>::iterator iterLeftCells = tree->cellsBegin(idxLevel); + int currentOutInteraction = 0; + while(iterLeftCells != iterCells && currentOutInteraction < int(outsideInteractions.size())){ + const MortonIndex blockStartIdx = (*iterLeftCells)->getStartingIndex(); + const MortonIndex blockEndIdx = (*iterLeftCells)->getEndingIndex(); + + while(currentOutInteraction < int(outsideInteractions.size()) && outsideInteractions[currentOutInteraction].outIndex < blockStartIdx){ + currentOutInteraction += 1; + } + + int lastOutInteraction = currentOutInteraction; + while(lastOutInteraction < int(outsideInteractions.size()) && outsideInteractions[lastOutInteraction].outIndex < blockEndIdx){ + lastOutInteraction += 1; + } + + { // Can be a task(in:currentOutInteraction, in:outsideInteractions, in:lastOutInteraction, inout:iterLeftCells, inout:iterCells) + for(int outInterIdx = currentOutInteraction ; outInterIdx < lastOutInteraction ; ++outInterIdx){ + CellClass* interCell = (*iterLeftCells)->getCell(outsideInteractions[outInterIdx].outIndex); + if(interCell){ + FAssertLF(interCell->getMortonIndex() == outsideInteractions[outInterIdx].outIndex); + CellClass* cell = (*iterCells)->getCell(outsideInteractions[outInterIdx].insideIndex); + FAssertLF(cell); + FAssertLF(cell->getMortonIndex() == outsideInteractions[outInterIdx].insideIndex); + + const CellClass* interactions[343]; + memset(interactions, 0, 343*sizeof(CellClass*)); + interactions[outsideInteractions[outInterIdx].outPosition] = interCell; + const int counter = 1; + kernels[0]->M2L( cell , interactions, counter, idxLevel); + + interactions[outsideInteractions[outInterIdx].outPosition] = nullptr; + interactions[getOppositeInterIndex(outsideInteractions[outInterIdx].outPosition)] = cell; + kernels[0]->M2L( interCell , interactions, counter, idxLevel); + } + } + } + + currentOutInteraction = lastOutInteraction; + ++iterLeftCells; + } + + ++iterCells; + } + + } + FLOG( FLog::Controller << "\t\t transferPass in " << timer.tacAndElapsed() << "s\n" ); + } + + void downardPass(){ + FLOG( FTic timer; ); + for(int idxLevel = 2 ; idxLevel <= tree->getHeight()-2 ; ++idxLevel){ + typename std::list<CellContainerClass*>::iterator iterCells = tree->cellsBegin(idxLevel); + const typename std::list<CellContainerClass*>::iterator endCells = tree->cellsEnd(idxLevel); + + typename std::list<CellContainerClass*>::iterator iterChildCells = tree->cellsBegin(idxLevel+1); + const typename std::list<CellContainerClass*>::iterator endChildCells = tree->cellsEnd(idxLevel+1); + + while(iterCells != endCells && iterChildCells != endChildCells){ + CellContainerClass* currentCells = (*iterCells); + + CellContainerClass* subCellGroups[8]; + memset(subCellGroups, 0, sizeof(CellContainerClass*) * 8); + + // Skip current group if needed + if( (*iterChildCells)->getEndingIndex() <= ((*iterCells)->getStartingIndex()<<3) ){ + ++iterChildCells; + } + FAssertLF(iterChildCells != endChildCells && ((*iterChildCells)->getStartingIndex()>>3) == (*iterCells)->getStartingIndex()); + // Copy at max 8 groups + int nbSubCellGroups = 0; + subCellGroups[nbSubCellGroups] = (*iterChildCells); + nbSubCellGroups += 1; + while((*iterChildCells)->getEndingIndex() <= (((*iterCells)->getStartingIndex()<<3)+7) + && (++iterChildCells) != endChildCells){ + subCellGroups[nbSubCellGroups] = (*iterChildCells); + nbSubCellGroups += 1; + } + + #pragma omp task default(none) firstprivate(idxLevel, currentCells, subCellGroups, nbSubCellGroups) + { + const MortonIndex blockStartIdx = currentCells->getStartingIndex(); + const MortonIndex blockEndIdx = currentCells->getEndingIndex(); + KernelClass*const kernel = kernels[omp_get_thread_num()]; + int idxSubCellGroup = 0; + + for(MortonIndex mindex = blockStartIdx ; mindex < blockEndIdx && idxSubCellGroup != nbSubCellGroups; ++mindex){ + CellClass* cell = currentCells->getCell(mindex); + if(cell){ + FAssertLF(cell->getMortonIndex() == mindex); + CellClass* child[8] = {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}; + + for(int idxChild = 0 ; idxChild < 8 ; ++idxChild){ + while(idxSubCellGroup != nbSubCellGroups && subCellGroups[idxSubCellGroup]->getEndingIndex() <= ((mindex<<3)+idxChild) ){ + idxSubCellGroup += 1; + } + if( idxSubCellGroup == nbSubCellGroups ){ + break; + } + child[idxChild] = subCellGroups[idxSubCellGroup]->getCell((mindex<<3)+idxChild); + FAssertLF(child[idxChild] == nullptr || child[idxChild]->getMortonIndex() == ((mindex<<3)+idxChild)); + } + + kernel->L2L(cell, child, idxLevel); + } + } + } + + ++iterCells; + } + + FAssertLF(iterCells == endCells && (iterChildCells == endChildCells || (++iterChildCells) == endChildCells)); + } + FLOG( FLog::Controller << "\t\t downardPass in " << timer.tacAndElapsed() << "s\n" ); + } + + void directPass(){ + FLOG( FTic timer; ); + { + typename std::list<ParticleGroupClass*>::iterator iterParticles = tree->leavesBegin(); + const typename std::list<ParticleGroupClass*>::iterator endParticles = tree->leavesEnd(); + + while(iterParticles != endParticles){ + typename std::vector<OutOfBlockInteraction> outsideInteractions; + + { // Can be a task(inout:iterCells, out:outsideInteractions) + const MortonIndex blockStartIdx = (*iterParticles)->getStartingIndex(); + const MortonIndex blockEndIdx = (*iterParticles)->getEndingIndex(); + + for(MortonIndex mindex = blockStartIdx ; mindex < blockEndIdx ; ++mindex){ + ParticleContainerClass particles = (*iterParticles)->template getLeaf<ParticleContainerClass>(mindex); + if(particles.isAttachedToSomething()){ + MortonIndex interactionsIndexes[26]; + int interactionsPosition[26]; + FTreeCoordinate coord(mindex, tree->getHeight()-1); + int counter = coord.getNeighborsIndexes(tree->getHeight(),interactionsIndexes,interactionsPosition); + + ParticleContainerClass interactionsObjects[27]; + ParticleContainerClass* interactions[27]; + memset(interactions, 0, 27*sizeof(ParticleContainerClass*)); + int counterExistingCell = 0; + + for(int idxInter = 0 ; idxInter < counter ; ++idxInter){ + if( blockStartIdx <= interactionsIndexes[idxInter] && interactionsIndexes[idxInter] < blockEndIdx ){ + interactionsObjects[counterExistingCell] = (*iterParticles)->template getLeaf<ParticleContainerClass>(interactionsIndexes[idxInter]); + if(interactionsObjects[counterExistingCell].isAttachedToSomething()){ + FAssertLF(interactions[interactionsPosition[idxInter]] == nullptr); + interactions[interactionsPosition[idxInter]] = &interactionsObjects[counterExistingCell]; + counterExistingCell += 1; + } + } + else if(interactionsIndexes[idxInter] < mindex){ + OutOfBlockInteraction property; + property.insideIndex = mindex; + property.outIndex = interactionsIndexes[idxInter]; + property.outPosition = interactionsPosition[idxInter]; + outsideInteractions.push_back(property); + } + } + + kernels[0]->P2P( coord, &particles, &particles , interactions, counterExistingCell); + } + } + } + + + // Manage outofblock interaction + FQuickSort<OutOfBlockInteraction, int>::QsSequential(outsideInteractions.data(),int(outsideInteractions.size())); + + typename std::list<ParticleGroupClass*>::iterator iterLeftParticles = tree->leavesBegin(); + int currentOutInteraction = 0; + while(iterLeftParticles != iterParticles && currentOutInteraction < int(outsideInteractions.size())){ + const MortonIndex blockStartIdx = (*iterLeftParticles)->getStartingIndex(); + const MortonIndex blockEndIdx = (*iterLeftParticles)->getEndingIndex(); + + while(currentOutInteraction < int(outsideInteractions.size()) && outsideInteractions[currentOutInteraction].outIndex < blockStartIdx){ + currentOutInteraction += 1; + } + + int lastOutInteraction = currentOutInteraction; + while(lastOutInteraction < int(outsideInteractions.size()) && outsideInteractions[lastOutInteraction].outIndex < blockEndIdx){ + lastOutInteraction += 1; + } + + { // Can be a task(in:currentOutInteraction, in:outsideInteractions, in:lastOutInteraction, inout:iterLeftParticles, inout:iterParticles) + for(int outInterIdx = currentOutInteraction ; outInterIdx < lastOutInteraction ; ++outInterIdx){ + ParticleContainerClass interParticles = (*iterLeftParticles)->template getLeaf<ParticleContainerClass>(outsideInteractions[outInterIdx].outIndex); + if(interParticles.isAttachedToSomething()){ + ParticleContainerClass particles = (*iterParticles)->template getLeaf<ParticleContainerClass>(outsideInteractions[outInterIdx].insideIndex); + FAssertLF(particles.isAttachedToSomething()); + ParticleContainerClass* interactions[27]; + memset(interactions, 0, 27*sizeof(ParticleContainerClass*)); + interactions[outsideInteractions[outInterIdx].outPosition] = &interParticles; + const int counter = 1; + kernels[0]->P2PRemote( FTreeCoordinate(outsideInteractions[outInterIdx].insideIndex, tree->getHeight()-1), &particles, &particles , interactions, counter); + + interactions[outsideInteractions[outInterIdx].outPosition] = nullptr; + interactions[getOppositeNeighIndex(outsideInteractions[outInterIdx].outPosition)] = &particles; + kernels[0]->P2PRemote( FTreeCoordinate(outsideInteractions[outInterIdx].outIndex, tree->getHeight()-1), &interParticles, &interParticles , interactions, counter); + } + } + } + + currentOutInteraction = lastOutInteraction; + ++iterLeftParticles; + } + + ++iterParticles; + } + } + FLOG( FLog::Controller << "\t\t directPass in " << timer.tacAndElapsed() << "s\n" ); + } + + void mergePass(){ + FLOG( FTic timer; ); + { + typename std::list<ParticleGroupClass*>::iterator iterParticles = tree->leavesBegin(); + const typename std::list<ParticleGroupClass*>::iterator endParticles = tree->leavesEnd(); + + typename std::list<CellContainerClass*>::iterator iterCells = tree->cellsBegin(tree->getHeight()-1); + const typename std::list<CellContainerClass*>::iterator endCells = tree->cellsEnd(tree->getHeight()-1); + + while(iterParticles != endParticles && iterCells != endCells){ + CellContainerClass* leafCells = (*iterCells); + ParticleGroupClass* containers = (*iterParticles); + #pragma omp task default(shared) firstprivate(leafCells, containers) + { // Can be a task(out:iterParticles, in:iterCells) + const MortonIndex blockStartIdx = leafCells->getStartingIndex(); + const MortonIndex blockEndIdx = leafCells->getEndingIndex(); + KernelClass*const kernel = kernels[omp_get_thread_num()]; + + for(MortonIndex mindex = blockStartIdx ; mindex < blockEndIdx ; ++mindex){ + CellClass* cell = leafCells->getCell(mindex); + if(cell){ + FAssertLF(cell->getMortonIndex() == mindex); + ParticleContainerClass particles = containers->template getLeaf<ParticleContainerClass>(mindex); + FAssertLF(particles.isAttachedToSomething()); + kernel->L2P(cell, &particles); + } + } + } + + ++iterParticles; + ++iterCells; + } + // Wait for task to complete + #pragma omp taskwait + + FAssertLF(iterParticles == endParticles && iterCells == endCells); + } + FLOG( FLog::Controller << "\t\t L2P in " << timer.tacAndElapsed() << "s\n" ); + } + + int getOppositeNeighIndex(const int index) const { + // ((idxX+1)*3 + (idxY+1)) * 3 + (idxZ+1) + return 27-index-1; + } + + int getOppositeInterIndex(const int index) const { + // ((( (xdiff+3) * 7) + (ydiff+3))) * 7 + zdiff + 3 + return 343-index-1; + } +}; + +#endif // FGROUPTASKALGORITHM_HPP diff --git a/Tests/noDist/testBlockedRoation.cpp b/Tests/noDist/testBlockedRoation.cpp index bab44800d..c664b9c16 100644 --- a/Tests/noDist/testBlockedRoation.cpp +++ b/Tests/noDist/testBlockedRoation.cpp @@ -16,6 +16,7 @@ #include "../../Src/Files/FFmaGenericLoader.hpp" #include "../../Src/GroupTree/FGroupSeqAlgorithm.hpp" +#include "../../Src/GroupTree/FGroupTaskAlgorithm.hpp" #include "../../Src/Utils/FParameterNames.hpp" @@ -43,7 +44,8 @@ int main(int argc, char* argv[]){ typedef FP2PGroupParticleContainer<> GroupContainerClass; typedef FGroupTree< GroupCellClass, GroupContainerClass, 5, FReal> GroupOctreeClass; typedef FRotationKernel< GroupCellClass, GroupContainerClass , P> GroupKernelClass; - typedef FGroupSeqAlgorithm<GroupOctreeClass, typename GroupOctreeClass::CellGroupClass, GroupCellClass, GroupKernelClass, typename GroupOctreeClass::ParticleGroupClass, GroupContainerClass > GroupAlgorithm; + //typedef FGroupSeqAlgorithm<GroupOctreeClass, typename GroupOctreeClass::CellGroupClass, GroupCellClass, GroupKernelClass, typename GroupOctreeClass::ParticleGroupClass, GroupContainerClass > GroupAlgorithm; + typedef FGroupTaskAlgorithm<GroupOctreeClass, typename GroupOctreeClass::CellGroupClass, GroupCellClass, GroupKernelClass, typename GroupOctreeClass::ParticleGroupClass, GroupContainerClass > GroupAlgorithm; // Get params const int NbLevels = FParameters::getValue(argc,argv,FParameterDefinitions::OctreeHeight.options, 5); -- GitLab