FGroupOfParticles.hpp 17.3 KB
Newer Older
1 2

// Keep in private GIT
3 4 5 6
#ifndef FGROUPOFPARTICLES_HPP
#define FGROUPOFPARTICLES_HPP


7
#include "../../Utils/FGlobal.hpp"
8 9 10 11
#include "../../Utils/FAssert.hpp"
#include "../../Containers/FTreeCoordinate.hpp"
#include "../../Utils/FAlignedMemory.hpp"
#include "../StarPUUtils/FStarPUDefaultAlign.hpp"
12 13 14 15 16 17 18 19

#include <list>
#include <functional>


/**
* @brief The FGroupOfParticles class manages the leaves in block allocation.
*/
20
template <class FReal, unsigned NbSymbAttributes, unsigned NbAttributesPerParticle, class AttributeClass = FReal>
21 22
class FGroupOfParticles {
    /** One header is allocated at the beginning of each block */
BRAMAS Berenger's avatar
BRAMAS Berenger committed
23
    struct alignas(FStarPUDefaultAlign::StructAlign) BlockHeader{
24 25 26
        MortonIndex startingIndex;
        MortonIndex endingIndex;
        int numberOfLeavesInBlock;
27
        int idxGlobal;
28
        //< The real number of particles allocated
29
        FSize nbParticlesAllocatedInGroup;
30 31
        //< Starting point of position
        size_t offsetPosition;
32
        //< Bytes difference/offset between position
33
        size_t positionsLeadingDim;
34
        //< Bytes difference/offset between attributes
35
        size_t attributeLeadingDim;
36
        //< The total number of particles in the group
37
        FSize nbParticlesInGroup;
38 39 40
    };

    /** Information about a leaf */
BRAMAS Berenger's avatar
BRAMAS Berenger committed
41
    struct alignas(FStarPUDefaultAlign::StructAlign) LeafHeader {
42
        MortonIndex mindex;
43
        FSize nbParticles;
44 45 46
        size_t offSet;
    };

47

48
protected:
49
    static const int MemoryAlignementBytes     = FP2PDefaultAlignement;
50 51 52 53 54 55 56 57 58
    static const int MemoryAlignementParticles = MemoryAlignementBytes/sizeof(FReal);

    /** This function return the correct number of particles that should be used to have a correct pack.
     * If alignement is 32 and use double (so 4 particles in pack), then this function returns:
     * RoundToUpperParticles(1) = 1 + 3 = 4
     * RoundToUpperParticles(63) = 63 + 1 = 64
     */
    template <class NumClass>
    static NumClass RoundToUpperParticles(const NumClass& nbParticles){
59
        return nbParticles + (MemoryAlignementParticles - (nbParticles%MemoryAlignementParticles));
60 61
    }

62
    //< The size of memoryBuffer in byte
BRAMAS Berenger's avatar
BRAMAS Berenger committed
63
    size_t allocatedMemoryInByte;
64 65 66 67 68 69 70 71 72 73 74 75
    //< Pointer to a block memory
    unsigned char* memoryBuffer;

    //< Pointer to the header inside the block memory
    BlockHeader*    blockHeader;
    //< Pointer to leaves information
    LeafHeader*     leafHeader;

    //< Pointers to particle position x, y, z
    FReal* particlePosition[3];

    //< Pointers to the particles data inside the block memory
76
    AttributeClass* attributesBuffer;
77
#ifndef SCALFMM_SIMGRID_NODATA
78
    AttributeClass* particleAttributes[NbSymbAttributes+NbAttributesPerParticle];
79 80 81
#else
    AttributeClass* particleAttributes[NbSymbAttributes];
#endif
82

83 84 85
    /** To know if we have to delete the buffer */
    bool deleteBuffer;

86
public:
87 88
    typedef AttributeClass ParticleDataType;

89
    /**
90 91 92 93
     * Init from a given buffer
     * @param inBuffer
     * @param inAllocatedMemoryInByte
     */
94 95
    FGroupOfParticles(unsigned char* inBuffer, const size_t inAllocatedMemoryInByte,
                      unsigned char* inAttributes)
96
        : allocatedMemoryInByte(inAllocatedMemoryInByte), memoryBuffer(inBuffer),
97
          blockHeader(nullptr), leafHeader(nullptr),
98
          attributesBuffer(nullptr), deleteBuffer(false){
99
        // Move the pointers to the correct position
100 101 102
        blockHeader         = reinterpret_cast<BlockHeader*>(inBuffer);
        inBuffer += sizeof(BlockHeader);
        leafHeader          = reinterpret_cast<LeafHeader*>(inBuffer);
103 104

        // Init particle pointers
105 106
        FAssertLF( blockHeader->positionsLeadingDim == (sizeof(FReal) * blockHeader->nbParticlesAllocatedInGroup) );
        particlePosition[0] = reinterpret_cast<FReal*>(memoryBuffer + blockHeader->offsetPosition);
107 108 109 110
        particlePosition[1] = (particlePosition[0] + blockHeader->nbParticlesAllocatedInGroup);
        particlePosition[2] = (particlePosition[1] + blockHeader->nbParticlesAllocatedInGroup);

        // Redirect pointer to data
111
        FAssertLF(blockHeader->attributeLeadingDim == (sizeof(AttributeClass) * blockHeader->nbParticlesAllocatedInGroup));
112 113 114 115 116
        AttributeClass* symAttributes = (AttributeClass*)(&particlePosition[2][blockHeader->nbParticlesAllocatedInGroup]);
        for(unsigned idxAttribute = 0 ; idxAttribute < NbSymbAttributes ; ++idxAttribute){
            particleAttributes[idxAttribute] = symAttributes;
            symAttributes += blockHeader->nbParticlesAllocatedInGroup;
        }
117
#ifndef SCALFMM_SIMGRID_NODATA
118 119 120
        if(inAttributes){
            attributesBuffer = (AttributeClass*)inAttributes;
            for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
121
                particleAttributes[idxAttribute+NbSymbAttributes] = &attributesBuffer[idxAttribute*blockHeader->nbParticlesAllocatedInGroup];
122
            }
123
        }
124
#endif
125 126 127
    }

    /**
128 129 130 131 132
 * @brief FGroupOfParticles
 * @param inStartingIndex first leaf morton index
 * @param inEndingIndex last leaf morton index + 1
 * @param inNumberOfLeaves total number of leaves in the interval (should be <= inEndingIndex-inEndingIndex)
 */
133
    FGroupOfParticles(const MortonIndex inStartingIndex, const MortonIndex inEndingIndex, const int inNumberOfLeaves, const FSize inNbParticles)
134
        : allocatedMemoryInByte(0), memoryBuffer(nullptr), blockHeader(nullptr), leafHeader(nullptr),
135
          deleteBuffer(true){
136 137 138
        memset(particlePosition, 0, sizeof(particlePosition));
        memset(particleAttributes, 0, sizeof(particleAttributes));

139
        const FSize nbParticlesAllocatedInGroup = RoundToUpperParticles(inNbParticles+(MemoryAlignementParticles-1)*inNumberOfLeaves);
140

141
        // Find the number of leaf to allocate in the blocks
142
        FAssertLF((inEndingIndex-inStartingIndex) >= MortonIndex(inNumberOfLeaves));
143
        // Total number of bytes in the block
144
        const size_t sizeOfOneParticle = (3*sizeof(FReal) + NbSymbAttributes*sizeof(AttributeClass));
145
        const size_t memoryToAlloc = sizeof(BlockHeader)
146
                                    + (inNumberOfLeaves*sizeof(MortonIndex))
147 148
                                    + (inNumberOfLeaves*sizeof(LeafHeader))
                                    + nbParticlesAllocatedInGroup*sizeOfOneParticle;
149 150

        // Allocate
151 152
        FAssertLF(0 <= int(memoryToAlloc) && int(memoryToAlloc) < std::numeric_limits<int>::max());
        allocatedMemoryInByte = memoryToAlloc;
153
        memoryBuffer = (unsigned char*)FAlignedMemory::AllocateBytes<MemoryAlignementBytes>(memoryToAlloc);
154 155 156 157
        FAssertLF(memoryBuffer);
        memset(memoryBuffer, 0, memoryToAlloc);

        // Move the pointers to the correct position
158 159 160 161
        unsigned char* bufferPtr = memoryBuffer;
        blockHeader         = reinterpret_cast<BlockHeader*>(bufferPtr);
        bufferPtr += sizeof(BlockHeader);
        leafHeader          = reinterpret_cast<LeafHeader*>(bufferPtr);
162 163 164 165 166

        // Init header
        blockHeader->startingIndex = inStartingIndex;
        blockHeader->endingIndex   = inEndingIndex;
        blockHeader->numberOfLeavesInBlock  = inNumberOfLeaves;
167
        blockHeader->nbParticlesAllocatedInGroup = nbParticlesAllocatedInGroup;
168
        blockHeader->nbParticlesInGroup = inNbParticles;
169
        blockHeader->idxGlobal = -1;
170
        // Init particle pointers
171
        blockHeader->positionsLeadingDim = (sizeof(FReal) * nbParticlesAllocatedInGroup);
172 173 174 175
        particlePosition[0] = reinterpret_cast<FReal*>((reinterpret_cast<size_t>(leafHeader + inNumberOfLeaves)
                                                       +MemoryAlignementBytes-1) & ~(MemoryAlignementBytes-1));
        particlePosition[1] = (particlePosition[0] + nbParticlesAllocatedInGroup);
        particlePosition[2] = (particlePosition[1] + nbParticlesAllocatedInGroup);
176

177 178
        blockHeader->offsetPosition = size_t(particlePosition[0]) - size_t(memoryBuffer);

179
        // Redirect pointer to data
180
        blockHeader->attributeLeadingDim = (sizeof(AttributeClass) * nbParticlesAllocatedInGroup);
181

182 183 184 185 186
        AttributeClass* symAttributes = (AttributeClass*)(&particlePosition[2][blockHeader->nbParticlesAllocatedInGroup]);
        for(unsigned idxAttribute = 0 ; idxAttribute < NbSymbAttributes ; ++idxAttribute){
            particleAttributes[idxAttribute] = symAttributes;
            symAttributes += blockHeader->nbParticlesAllocatedInGroup;
        }
187
#ifndef SCALFMM_SIMGRID_NODATA
188 189
        attributesBuffer = (AttributeClass*)FAlignedMemory::AllocateBytes<MemoryAlignementBytes>(blockHeader->attributeLeadingDim*NbAttributesPerParticle);
        memset(attributesBuffer, 0, blockHeader->attributeLeadingDim*NbAttributesPerParticle);
190
        for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
191
            particleAttributes[idxAttribute+NbSymbAttributes] = &attributesBuffer[idxAttribute*nbParticlesAllocatedInGroup];
192
        }
193 194 195
#else
        attributesBuffer = nullptr;
#endif
196 197

        // Set all index to not used
198 199
        for(int idxLeafPtr = 0 ; idxLeafPtr < inNumberOfLeaves ; ++idxLeafPtr){
            leafHeader[idxLeafPtr].mindex = -1;
200 201 202 203 204
        }
    }

    /** Call the destructor of leaves and dealloc block memory */
    ~FGroupOfParticles(){
205
        if(deleteBuffer){
206 207
            FAlignedMemory::DeallocBytes(memoryBuffer);
            FAlignedMemory::DeallocBytes(attributesBuffer);
208 209 210 211 212 213
        }
    }

    /** Give access to the buffer to send the data */
    const unsigned char* getRawBuffer() const{
        return memoryBuffer;
214 215
    }

216
    /** The the size of the allocated buffer */
BRAMAS Berenger's avatar
BRAMAS Berenger committed
217
    size_t getBufferSizeInByte() const {
218 219 220
        return allocatedMemoryInByte;
    }

221
    /** Give access to the buffer to send the data */
222
    const unsigned char* getRawAttributesBuffer() const{
223
        return reinterpret_cast<const unsigned char*>(attributesBuffer);
224 225 226 227
    }

    /** Give access to the buffer to send the data */
    unsigned char* getRawAttributesBuffer(){
228
        return reinterpret_cast<unsigned char*>(attributesBuffer);
229 230 231
    }

    /** The the size of the allocated buffer */
BRAMAS Berenger's avatar
BRAMAS Berenger committed
232
    size_t getAttributesBufferSizeInByte() const {
233
        return blockHeader->attributeLeadingDim*NbAttributesPerParticle;
234 235
    }

236 237 238 239 240
    /** To know if the object will delete the memory block */
    bool getDeleteMemory() const{
        return deleteBuffer;
    }

241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    /** The index of the fist leaf (set from the constructor) */
    MortonIndex getStartingIndex() const {
        return blockHeader->startingIndex;
    }

    /** The index of the last leaf + 1 (set from the constructor) */
    MortonIndex getEndingIndex() const {
        return blockHeader->endingIndex;
    }

    /** The number of leaf (set from the constructor) */
    int getNumberOfLeavesInBlock() const {
        return blockHeader->numberOfLeavesInBlock;
    }

    /** Get the total number of particles in the group */
257
    FSize getNbParticlesInGroup() const {
258
        return blockHeader->nbParticlesInGroup;
259 260 261
    }

    /** The size of the interval endingIndex-startingIndex (set from the constructor) */
262 263
    MortonIndex getSizeOfInterval() const {
        return (blockHeader->endingIndex-blockHeader->startingIndex);
264 265 266 267 268 269 270
    }

    /** Return true if inIndex should be located in the current block */
    bool isInside(const MortonIndex inIndex) const{
        return blockHeader->startingIndex <= inIndex && inIndex < blockHeader->endingIndex;
    }

271 272 273 274 275 276 277 278
    int getIdxGlobal() const{
        return blockHeader->idxGlobal;
    }

    void setIdxGlobal(int idxGlobal){
        blockHeader->idxGlobal = idxGlobal;
    }

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    /** Return the idx in array of the cell */
    MortonIndex getLeafMortonIndex(const int id) const{
        FAssertLF(id < blockHeader->numberOfLeavesInBlock);
        return leafHeader[id].mindex;
    }

    /** Check if a cell exist (by binary search) and return it index */
    int getLeafIndex(const MortonIndex leafIdx) const{
        int idxLeft = 0;
        int idxRight = blockHeader->numberOfLeavesInBlock-1;
        while(idxLeft <= idxRight){
            const int idxMiddle = (idxLeft+idxRight)/2;
            if(leafHeader[idxMiddle].mindex == leafIdx){
                return idxMiddle;
            }
            if(leafIdx < leafHeader[idxMiddle].mindex){
                idxRight = idxMiddle-1;
            }
            else{
                idxLeft = idxMiddle+1;
            }
        }
        return -1;
    }

304 305
    /** Return true if inIndex is located in the current block and is not empty */
    bool exists(const MortonIndex inIndex) const {
306
        return isInside(inIndex) && (getLeafIndex(inIndex) != -1);
307 308 309
    }

    /** Allocate a new leaf by calling its constructor */
310
    size_t newLeaf(const MortonIndex inIndex, const int id, const FSize nbParticles, const size_t offsetInGroup){
311 312
        FAssertLF(isInside(inIndex));
        FAssertLF(!exists(inIndex));
313
        FAssertLF(id < blockHeader->numberOfLeavesInBlock);
314
        FAssertLF(offsetInGroup < size_t(blockHeader->nbParticlesAllocatedInGroup));
315 316
        leafHeader[id].nbParticles = nbParticles;
        leafHeader[id].offSet = offsetInGroup;
317
        leafHeader[id].mindex = inIndex;
318 319

        const size_t nextLeafOffsetInGroup = RoundToUpperParticles(offsetInGroup+nbParticles);
320
        FAssertLF(nextLeafOffsetInGroup <= size_t(blockHeader->nbParticlesAllocatedInGroup + MemoryAlignementParticles));
321
        return nextLeafOffsetInGroup;
322 323 324 325 326
    }

    /** Iterate on each allocated leaves */
    template<class ParticlesAttachedClass>
    void forEachLeaf(std::function<void(ParticlesAttachedClass*)> function){
327 328 329
        for(int idxLeafPtr = 0 ; idxLeafPtr < blockHeader->numberOfLeavesInBlock ; ++idxLeafPtr){
            ParticlesAttachedClass leaf(leafHeader[idxLeafPtr].nbParticles,
                                            particlePosition[0] + leafHeader[idxLeafPtr].offSet,
330
                                            blockHeader->positionsLeadingDim,
331
#ifndef SCALFMM_SIMGRID_NODATA
332
                                            (attributesBuffer?particleAttributes[NbSymbAttributes] + leafHeader[idxLeafPtr].offSet:nullptr),
333 334 335
#else
                                            nullptr,
#endif
336
                                            blockHeader->attributeLeadingDim);
337
            function(&leaf);
338 339 340
        }
    }

341 342 343 344
    // This function return the number of particle in the leaf who have the id
    FSize getNbParticlesInLeaf(int id) const{
        return leafHeader[id].nbParticles;
    }
345 346 347

    /** Return the address of the leaf if it exists (or NULL) */
    template<class ParticlesAttachedClass>
348 349 350
    ParticlesAttachedClass getLeaf(const int id){
        FAssertLF(id < blockHeader->numberOfLeavesInBlock);
        return ParticlesAttachedClass(leafHeader[id].nbParticles,
351
                                          particlePosition[0] + leafHeader[id].offSet,
352
                                            blockHeader->positionsLeadingDim,
353
#ifndef SCALFMM_SIMGRID_NODATA
354
                                            (attributesBuffer?particleAttributes[NbSymbAttributes] + leafHeader[id].offSet:nullptr),
355 356 357
#else
                                            nullptr,
#endif
358
                                            blockHeader->attributeLeadingDim);
359
    }
360

361 362 363 364 365 366 367 368 369
    template<class F>
    void forEachLeaf(F&& function){
        using F_ = std::remove_reference_t<F>;
        for(int idxLeafPtr = 0 ; idxLeafPtr < blockHeader->numberOfLeavesInBlock ; ++idxLeafPtr){
            auto leaf = getLeaf<typename F_::leaf_type>(idxLeafPtr);
            function(&leaf);
        }
    }
  
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412

    /** Extract methods */

    size_t getExtractBufferSize(const std::vector<int>& inLeavesIdxToExtract) const {
        size_t totalSize = 0;
        for(size_t idxEx = 0 ; idxEx < inLeavesIdxToExtract.size() ; ++idxEx){
            const int idLeaf = inLeavesIdxToExtract[idxEx];
            totalSize += leafHeader[idLeaf].nbParticles*sizeof(FReal)*NbSymbAttributes;
        }
        return totalSize;
    }

    void extractData(const std::vector<int>& inLeavesIdxToExtract,
                     unsigned char* outputBuffer, const size_t outputBufferSize) const {
        size_t idxValue = 0;
        for(size_t idxEx = 0 ; idxEx < inLeavesIdxToExtract.size() ; ++idxEx){
            const int idLeaf = inLeavesIdxToExtract[idxEx];
            for(unsigned idxAttr = 0 ; idxAttr < NbSymbAttributes ; ++idxAttr){
                const FReal* ptrData = particlePosition[0] + leafHeader[idLeaf].offSet
                        + blockHeader->positionsLeadingDim*idxAttr;
                for(int idxPart = 0 ; idxPart < leafHeader[idLeaf].nbParticles ; ++idxPart){
                    ((FReal*)outputBuffer)[idxValue++] = ptrData[idxPart];
                }
            }
        }
        FAssertLF(idxValue*sizeof(FReal) == outputBufferSize);
    }

    void restoreData(const std::vector<int>& inLeavesIdxToExtract,
                     const unsigned char* intputBuffer, const size_t inputBufferSize){
        size_t idxValue = 0;
        for(size_t idxEx = 0 ; idxEx < inLeavesIdxToExtract.size() ; ++idxEx){
            const int idLeaf = inLeavesIdxToExtract[idxEx];
            for(unsigned idxAttr = 0 ; idxAttr < NbSymbAttributes ; ++idxAttr){
                FReal* ptrData = particlePosition[0] + leafHeader[idLeaf].offSet
                        + blockHeader->positionsLeadingDim*idxAttr;
                for(int idxPart = 0 ; idxPart < leafHeader[idLeaf].nbParticles ; ++idxPart){
                    ptrData[idxPart] = ((const FReal*)intputBuffer)[idxValue++];
                }
            }
        }
        FAssertLF(idxValue*sizeof(FReal) == inputBufferSize);
    }
413 414 415 416 417
};



#endif // FGROUPOFPARTICLES_HPP