FGroupOfParticles.hpp 14.1 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 <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 28
        MortonIndex startingIndex;
        MortonIndex endingIndex;
        int numberOfLeavesInBlock;
        int blockIndexesTableSize;
29 30 31 32 33 34 35 36 37

        //< The real number of particles allocated
        int nbParticlesAllocatedInGroup;
        //< Bytes difference/offset between position
        size_t positionOffset;
        //< Bytes difference/offset between attributes
        size_t attributeOffset;
        //< The total number of particles in the group
        int nbParticlesInGroup;
38 39 40
    };

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

46

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

    //< This value is for not used leaves
    static const int LeafIsEmptyFlag = -1;

64 65
    //< The size of memoryBuffer in byte
    int allocatedMemoryInByte;
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    //< Pointer to a block memory
    unsigned char* memoryBuffer;

    //< Pointer to the header inside the block memory
    BlockHeader*    blockHeader;
    //< Pointer to the indexes table inside the block memory
    int*            blockIndexesTable;
    //< Pointer to leaves information
    LeafHeader*     leafHeader;
    //< The total number of particles in the group
    const int nbParticlesInGroup;

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

    //< Pointers to the particles data inside the block memory
82
    AttributeClass* attributesBuffer;
83
    AttributeClass* particleAttributes[NbSymbAttributes+NbAttributesPerParticle];
84

85 86 87
    /** To know if we have to delete the buffer */
    bool deleteBuffer;

88 89
public:
    /**
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 97
        : allocatedMemoryInByte(inAllocatedMemoryInByte), memoryBuffer(inBuffer),
          blockHeader(nullptr), blockIndexesTable(nullptr), leafHeader(nullptr), nbParticlesInGroup(0),
98
          attributesBuffer(nullptr), deleteBuffer(false){
99 100 101 102 103 104 105 106 107 108 109 110 111 112
        // Move the pointers to the correct position
        blockHeader         = reinterpret_cast<BlockHeader*>(memoryBuffer);
        blockIndexesTable   = reinterpret_cast<int*>(memoryBuffer+sizeof(BlockHeader));
        leafHeader          = reinterpret_cast<LeafHeader*>(memoryBuffer+sizeof(BlockHeader)+(blockHeader->blockIndexesTableSize*sizeof(int)));

        // Init particle pointers
        blockHeader->positionOffset = (sizeof(FReal) * blockHeader->nbParticlesAllocatedInGroup);
        particlePosition[0] = reinterpret_cast<FReal*>((reinterpret_cast<size_t>(leafHeader + blockHeader->numberOfLeavesInBlock)
                                                       +MemoryAlignementBytes-1) & ~(MemoryAlignementBytes-1));
        particlePosition[1] = (particlePosition[0] + blockHeader->nbParticlesAllocatedInGroup);
        particlePosition[2] = (particlePosition[1] + blockHeader->nbParticlesAllocatedInGroup);

        // Redirect pointer to data
        blockHeader->attributeOffset = (sizeof(AttributeClass) * blockHeader->nbParticlesAllocatedInGroup);
113 114 115 116 117
        AttributeClass* symAttributes = (AttributeClass*)(&particlePosition[2][blockHeader->nbParticlesAllocatedInGroup]);
        for(unsigned idxAttribute = 0 ; idxAttribute < NbSymbAttributes ; ++idxAttribute){
            particleAttributes[idxAttribute] = symAttributes;
            symAttributes += blockHeader->nbParticlesAllocatedInGroup;
        }
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 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)
 */
    FGroupOfParticles(const MortonIndex inStartingIndex, const MortonIndex inEndingIndex, const int inNumberOfLeaves, const int inNbParticles)
133 134
        : allocatedMemoryInByte(0), memoryBuffer(nullptr), blockHeader(nullptr), blockIndexesTable(nullptr), leafHeader(nullptr), nbParticlesInGroup(inNbParticles),
          deleteBuffer(true){
135 136 137
        memset(particlePosition, 0, sizeof(particlePosition));
        memset(particleAttributes, 0, sizeof(particleAttributes));

138
        const int nbParticlesAllocatedInGroup = RoundToUpperParticles(nbParticlesInGroup+(MemoryAlignementParticles-1)*inNumberOfLeaves);
139

140 141 142 143
        // Find the number of leaf to allocate in the blocks
        const int blockIndexesTableSize = int(inEndingIndex-inStartingIndex);
        FAssertLF(inNumberOfLeaves <= blockIndexesTableSize);
        // Total number of bytes in the block
144
        const size_t sizeOfOneParticle = (3*sizeof(FReal) + NbSymbAttributes*sizeof(AttributeClass));
145 146 147 148
        const size_t memoryToAlloc = sizeof(BlockHeader)
                                    + (blockIndexesTableSize*sizeof(int))
                                    + (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 158 159 160 161 162 163 164 165 166
        FAssertLF(memoryBuffer);
        memset(memoryBuffer, 0, memoryToAlloc);

        // Move the pointers to the correct position
        blockHeader         = reinterpret_cast<BlockHeader*>(memoryBuffer);
        blockIndexesTable   = reinterpret_cast<int*>(memoryBuffer+sizeof(BlockHeader));
        leafHeader          = reinterpret_cast<LeafHeader*>(memoryBuffer+sizeof(BlockHeader)+(blockIndexesTableSize*sizeof(int)));

        // Init header
        blockHeader->startingIndex = inStartingIndex;
        blockHeader->endingIndex   = inEndingIndex;
        blockHeader->numberOfLeavesInBlock  = inNumberOfLeaves;
        blockHeader->blockIndexesTableSize = blockIndexesTableSize;
167
        blockHeader->nbParticlesAllocatedInGroup = nbParticlesAllocatedInGroup;
168 169

        // Init particle pointers
170
        blockHeader->positionOffset = (sizeof(FReal) * nbParticlesAllocatedInGroup);
171 172 173 174
        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);
175 176

        // Redirect pointer to data
177
        blockHeader->attributeOffset = (sizeof(AttributeClass) * nbParticlesAllocatedInGroup);
178

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

185
        attributesBuffer = (AttributeClass*)FAlignedMemory::AllocateBytes<MemoryAlignementBytes>(blockHeader->attributeOffset*NbAttributesPerParticle);
186
        memset(attributesBuffer, 0, blockHeader->attributeOffset*NbAttributesPerParticle);
187
        for(unsigned idxAttribute = 0 ; idxAttribute < NbAttributesPerParticle ; ++idxAttribute){
188
            particleAttributes[idxAttribute+NbSymbAttributes] = &attributesBuffer[idxAttribute*nbParticlesAllocatedInGroup];
189 190 191 192 193 194 195 196 197 198
        }

        // Set all index to not used
        for(int idxLeafPtr = 0 ; idxLeafPtr < blockIndexesTableSize ; ++idxLeafPtr){
            blockIndexesTable[idxLeafPtr] = LeafIsEmptyFlag;
        }
    }

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

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

210 211 212 213 214
    /** The the size of the allocated buffer */
    int getBufferSizeInByte() const {
        return allocatedMemoryInByte;
    }

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

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

    /** The the size of the allocated buffer */
    int getAttributesBufferSizeInByte() const {
        return blockHeader->attributeOffset*NbAttributesPerParticle;
    }

230 231 232 233 234
    /** To know if the object will delete the memory block */
    bool getDeleteMemory() const{
        return deleteBuffer;
    }

235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    /** 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 */
    int getNbParticlesInGroup() const {
        return nbParticlesInGroup;
    }

    /** The size of the interval endingIndex-startingIndex (set from the constructor) */
    int getSizeOfInterval() const {
        return blockHeader->blockIndexesTableSize;
    }

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

    /** Return true if inIndex is located in the current block and is not empty */
    bool exists(const MortonIndex inIndex) const {
        return isInside(inIndex) && (blockIndexesTable[inIndex-blockHeader->startingIndex] != LeafIsEmptyFlag);
    }

    /** Allocate a new leaf by calling its constructor */
271
    size_t newLeaf(const MortonIndex inIndex, const int id, const int nbParticles, const size_t offsetInGroup){
272 273 274
        FAssertLF(isInside(inIndex));
        FAssertLF(!exists(inIndex));
        FAssertLF(id < blockHeader->blockIndexesTableSize);
275
        FAssertLF(offsetInGroup < size_t(blockHeader->nbParticlesAllocatedInGroup));
276 277 278
        blockIndexesTable[inIndex-blockHeader->startingIndex] = id;
        leafHeader[id].nbParticles = nbParticles;
        leafHeader[id].offSet = offsetInGroup;
279 280

        const size_t nextLeafOffsetInGroup = RoundToUpperParticles(offsetInGroup+nbParticles);
281
        FAssertLF(nextLeafOffsetInGroup <= size_t(blockHeader->nbParticlesAllocatedInGroup + MemoryAlignementParticles));
282
        return nextLeafOffsetInGroup;
283 284 285 286 287 288 289 290 291 292
    }

    /** Iterate on each allocated leaves */
    template<class ParticlesAttachedClass>
    void forEachLeaf(std::function<void(ParticlesAttachedClass*)> function){
        for(int idxLeafPtr = 0 ; idxLeafPtr < blockHeader->blockIndexesTableSize ; ++idxLeafPtr){
            if(blockIndexesTable[idxLeafPtr] != LeafIsEmptyFlag){
                const int id = blockIndexesTable[idxLeafPtr];
                ParticlesAttachedClass leaf(leafHeader[id].nbParticles,
                                            particlePosition[0] + leafHeader[id].offSet,
293
                        blockHeader->positionOffset,
294
                        particleAttributes[NbSymbAttributes] + leafHeader[id].offSet,
295
                        blockHeader->attributeOffset);
296 297 298 299 300 301 302 303
                function(&leaf);
            }
        }
    }


    /** Return the address of the leaf if it exists (or NULL) */
    template<class ParticlesAttachedClass>
BRAMAS Berenger's avatar
BRAMAS Berenger committed
304
    ParticlesAttachedClass getLeaf(const MortonIndex leafIndex){
305 306 307 308
        if(blockIndexesTable[leafIndex - blockHeader->startingIndex] != LeafIsEmptyFlag){
            const int id = blockIndexesTable[leafIndex - blockHeader->startingIndex];
            return ParticlesAttachedClass(leafHeader[id].nbParticles,
                                          particlePosition[0] + leafHeader[id].offSet,
309
                                            blockHeader->positionOffset,
310
                                            particleAttributes[NbSymbAttributes] + leafHeader[id].offSet,
311
                                            blockHeader->attributeOffset);
312
        }
BRAMAS Berenger's avatar
BRAMAS Berenger committed
313
        return ParticlesAttachedClass();
314 315 316 317 318 319
    }
};



#endif // FGROUPOFPARTICLES_HPP