FGroupOfParticles.hpp 14.2 KB
Newer Older
1 2 3

// Keep in private GIT
// @SCALFMM_PRIVATE
4 5 6 7
#ifndef FGROUPOFPARTICLES_HPP
#define FGROUPOFPARTICLES_HPP


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

#include <list>
#include <functional>


/**
* @brief The FGroupOfParticles class manages the leaves in block allocation.
*/
21
template <class FReal, unsigned NbSymbAttributes, unsigned NbAttributesPerParticle, class AttributeClass = FReal>
22 23
class FGroupOfParticles {
    /** One header is allocated at the beginning of each block */
BRAMAS Berenger's avatar
BRAMAS Berenger committed
24
    struct alignas(FStarPUDefaultAlign::StructAlign) BlockHeader{
25 26 27
        MortonIndex startingIndex;
        MortonIndex endingIndex;
        int numberOfLeavesInBlock;
28 29

        //< The real number of particles allocated
30
        FSize nbParticlesAllocatedInGroup;
31 32
        //< Starting point of position
        size_t offsetPosition;
33
        //< Bytes difference/offset between position
34
        size_t positionsLeadingDim;
35
        //< Bytes difference/offset between attributes
36
        size_t attributeLeadingDim;
37
        //< The total number of particles in the group
38
        FSize nbParticlesInGroup;
39 40 41
    };

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

48

49
protected:
50
    static const int MemoryAlignementBytes     = FP2PDefaultAlignement;
51 52 53 54 55 56 57 58 59
    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){
60
        return nbParticles + (MemoryAlignementParticles - (nbParticles%MemoryAlignementParticles));
61 62
    }

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

    //< Pointer to the header inside the block memory
    BlockHeader*    blockHeader;
    //< Pointer to leaves information
    LeafHeader*     leafHeader;
    //< The total number of particles in the group
73
    const FSize nbParticlesInGroup;
74 75 76 77 78

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

    //< Pointers to the particles data inside the block memory
79
    AttributeClass* attributesBuffer;
80
    AttributeClass* particleAttributes[NbSymbAttributes+NbAttributesPerParticle];
81

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

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

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

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

    /**
123 124 125 126 127
 * @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)
 */
128
    FGroupOfParticles(const MortonIndex inStartingIndex, const MortonIndex inEndingIndex, const int inNumberOfLeaves, const FSize inNbParticles)
129
        : allocatedMemoryInByte(0), memoryBuffer(nullptr), blockHeader(nullptr), leafHeader(nullptr), nbParticlesInGroup(inNbParticles),
130
          deleteBuffer(true){
131 132 133
        memset(particlePosition, 0, sizeof(particlePosition));
        memset(particleAttributes, 0, sizeof(particleAttributes));

134
        const FSize nbParticlesAllocatedInGroup = RoundToUpperParticles(nbParticlesInGroup+(MemoryAlignementParticles-1)*inNumberOfLeaves);
135

136
        // Find the number of leaf to allocate in the blocks
137
        FAssertLF(int(inEndingIndex-inStartingIndex) >= inNumberOfLeaves);
138
        // Total number of bytes in the block
139
        const size_t sizeOfOneParticle = (3*sizeof(FReal) + NbSymbAttributes*sizeof(AttributeClass));
140
        const size_t memoryToAlloc = sizeof(BlockHeader)
141
                                    + (inNumberOfLeaves*sizeof(MortonIndex))
142 143
                                    + (inNumberOfLeaves*sizeof(LeafHeader))
                                    + nbParticlesAllocatedInGroup*sizeOfOneParticle;
144 145

        // Allocate
146 147
        FAssertLF(0 <= int(memoryToAlloc) && int(memoryToAlloc) < std::numeric_limits<int>::max());
        allocatedMemoryInByte = memoryToAlloc;
148
        memoryBuffer = (unsigned char*)FAlignedMemory::AllocateBytes<MemoryAlignementBytes>(memoryToAlloc);
149 150 151 152
        FAssertLF(memoryBuffer);
        memset(memoryBuffer, 0, memoryToAlloc);

        // Move the pointers to the correct position
153 154 155 156
        unsigned char* bufferPtr = memoryBuffer;
        blockHeader         = reinterpret_cast<BlockHeader*>(bufferPtr);
        bufferPtr += sizeof(BlockHeader);
        leafHeader          = reinterpret_cast<LeafHeader*>(bufferPtr);
157 158 159 160 161

        // Init header
        blockHeader->startingIndex = inStartingIndex;
        blockHeader->endingIndex   = inEndingIndex;
        blockHeader->numberOfLeavesInBlock  = inNumberOfLeaves;
162
        blockHeader->nbParticlesAllocatedInGroup = nbParticlesAllocatedInGroup;
163 164

        // Init particle pointers
165
        blockHeader->positionsLeadingDim = (sizeof(FReal) * nbParticlesAllocatedInGroup);
166 167 168 169
        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);
170

171 172
        blockHeader->offsetPosition = size_t(particlePosition[0]) - size_t(memoryBuffer);

173
        // Redirect pointer to data
174
        blockHeader->attributeLeadingDim = (sizeof(AttributeClass) * nbParticlesAllocatedInGroup);
175

176 177 178 179 180 181
        AttributeClass* symAttributes = (AttributeClass*)(&particlePosition[2][blockHeader->nbParticlesAllocatedInGroup]);
        for(unsigned idxAttribute = 0 ; idxAttribute < NbSymbAttributes ; ++idxAttribute){
            particleAttributes[idxAttribute] = symAttributes;
            symAttributes += blockHeader->nbParticlesAllocatedInGroup;
        }

182 183
        attributesBuffer = (AttributeClass*)FAlignedMemory::AllocateBytes<MemoryAlignementBytes>(blockHeader->attributeLeadingDim*NbAttributesPerParticle);
        memset(attributesBuffer, 0, blockHeader->attributeLeadingDim*NbAttributesPerParticle);
184
        for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
185
            particleAttributes[idxAttribute+NbSymbAttributes] = &attributesBuffer[idxAttribute*nbParticlesAllocatedInGroup];
186 187 188
        }

        // Set all index to not used
189 190
        for(int idxLeafPtr = 0 ; idxLeafPtr < inNumberOfLeaves ; ++idxLeafPtr){
            leafHeader[idxLeafPtr].mindex = -1;
191 192 193 194 195
        }
    }

    /** Call the destructor of leaves and dealloc block memory */
    ~FGroupOfParticles(){
196
        if(deleteBuffer){
197 198
            FAlignedMemory::DeallocBytes(memoryBuffer);
            FAlignedMemory::DeallocBytes(attributesBuffer);
199 200 201 202 203 204
        }
    }

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

207
    /** The the size of the allocated buffer */
BRAMAS Berenger's avatar
BRAMAS Berenger committed
208
    size_t getBufferSizeInByte() const {
209 210 211
        return allocatedMemoryInByte;
    }

212
    /** Give access to the buffer to send the data */
213
    const unsigned char* getRawAttributesBuffer() const{
214
        return reinterpret_cast<const unsigned char*>(attributesBuffer);
215 216 217 218
    }

    /** Give access to the buffer to send the data */
    unsigned char* getRawAttributesBuffer(){
219
        return reinterpret_cast<unsigned char*>(attributesBuffer);
220 221 222
    }

    /** The the size of the allocated buffer */
BRAMAS Berenger's avatar
BRAMAS Berenger committed
223
    size_t getAttributesBufferSizeInByte() const {
224
        return blockHeader->attributeLeadingDim*NbAttributesPerParticle;
225 226
    }

227 228 229 230 231
    /** To know if the object will delete the memory block */
    bool getDeleteMemory() const{
        return deleteBuffer;
    }

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    /** 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 */
248
    FSize getNbParticlesInGroup() const {
249 250 251 252 253
        return nbParticlesInGroup;
    }

    /** The size of the interval endingIndex-startingIndex (set from the constructor) */
    int getSizeOfInterval() const {
254
        return int(blockHeader->endingIndex-blockHeader->startingIndex);
255 256 257 258 259 260 261
    }

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

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    /** 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;
    }

287 288
    /** Return true if inIndex is located in the current block and is not empty */
    bool exists(const MortonIndex inIndex) const {
289
        return isInside(inIndex) && (getLeafIndex(inIndex) != -1);
290 291 292
    }

    /** Allocate a new leaf by calling its constructor */
293
    size_t newLeaf(const MortonIndex inIndex, const int id, const FSize nbParticles, const size_t offsetInGroup){
294 295
        FAssertLF(isInside(inIndex));
        FAssertLF(!exists(inIndex));
296
        FAssertLF(id < blockHeader->numberOfLeavesInBlock);
297
        FAssertLF(offsetInGroup < size_t(blockHeader->nbParticlesAllocatedInGroup));
298 299
        leafHeader[id].nbParticles = nbParticles;
        leafHeader[id].offSet = offsetInGroup;
300
        leafHeader[id].mindex = inIndex;
301 302

        const size_t nextLeafOffsetInGroup = RoundToUpperParticles(offsetInGroup+nbParticles);
303
        FAssertLF(nextLeafOffsetInGroup <= size_t(blockHeader->nbParticlesAllocatedInGroup + MemoryAlignementParticles));
304
        return nextLeafOffsetInGroup;
305 306 307 308 309
    }

    /** Iterate on each allocated leaves */
    template<class ParticlesAttachedClass>
    void forEachLeaf(std::function<void(ParticlesAttachedClass*)> function){
310 311 312
        for(int idxLeafPtr = 0 ; idxLeafPtr < blockHeader->numberOfLeavesInBlock ; ++idxLeafPtr){
            ParticlesAttachedClass leaf(leafHeader[idxLeafPtr].nbParticles,
                                            particlePosition[0] + leafHeader[idxLeafPtr].offSet,
313
                                            blockHeader->positionsLeadingDim,
314
                                            (attributesBuffer?particleAttributes[NbSymbAttributes] + leafHeader[idxLeafPtr].offSet:nullptr),
315
                                            blockHeader->attributeLeadingDim);
316
            function(&leaf);
317 318 319 320 321 322
        }
    }


    /** Return the address of the leaf if it exists (or NULL) */
    template<class ParticlesAttachedClass>
323 324 325
    ParticlesAttachedClass getLeaf(const int id){
        FAssertLF(id < blockHeader->numberOfLeavesInBlock);
        return ParticlesAttachedClass(leafHeader[id].nbParticles,
326
                                          particlePosition[0] + leafHeader[id].offSet,
327
                                            blockHeader->positionsLeadingDim,
328
                                            (attributesBuffer?particleAttributes[NbSymbAttributes] + leafHeader[id].offSet:nullptr),
329
                                            blockHeader->attributeLeadingDim);
330 331 332 333 334 335
    }
};



#endif // FGROUPOFPARTICLES_HPP