FBasicParticleContainer.hpp 12.7 KB
Newer Older
1
// ===================================================================================
COULAUD Olivier's avatar
COULAUD Olivier committed
2
// Copyright ScalFmm 2011 INRIA, Olivier Coulaud, Berenger Bramas, Matthias Messner
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// olivier.coulaud@inria.fr, berenger.bramas@inria.fr
// This software is a computer program whose purpose is to compute the FMM.
//
// This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software.  
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info". 
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef FBASICPARTICLECONTAINER_HPP
#define FBASICPARTICLECONTAINER_HPP

#include "FAbstractParticleContainer.hpp"
20
#include "FAbstractSerializable.hpp"
21

COULAUD Olivier's avatar
COULAUD Olivier committed
22
23
24
#include "Utils/FAlignedMemory.hpp"
#include "Utils/FMath.hpp"
#include "Utils/FPoint.hpp"
25
#include "FParticleType.hpp"
26

27
28
#include <array>

29
/**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 * @author Berenger Bramas (berenger.bramas@inria.fr)
 * @class FBasicParticle
 * Please read the license
 *
 * This class defines a container which can holds one type (AttributeClass)
 * for each particle.
 * The memory is allocated for all informations, the positions and the
 * request type.
 * For example is one want to store a struct for each particle:
 * @code
 * @code struct AStruct{
 * @code ...
 * @code };
 * @code FBasicParticleContainer<1, AStruct> container;
 * And then the access is done using:
 * @code AStruct* strucs = container.getAttributes<0>();
 */
47
template <unsigned NbAttributesPerParticle, class AttributeClass = FReal >
48
class FBasicParticleContainer : public FAbstractParticleContainer, public FAbstractSerializable {
49
protected:
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    /** The number of particles in the container */
    int nbParticles;
    /** 3 pointers to 3 arrays of real to store the position */
    FReal* positions[3];
    /** The attributes requested by the user */
    AttributeClass* attributes[NbAttributesPerParticle];

    /** The allocated memory */
    int allocatedParticles;

    /////////////////////////////////////////////////////
    /////////////////////////////////////////////////////

    /** Ending call for pushing the attributes */
    template<int index>
    void addParticleValue(const int /*insertPosition*/){
    }

    /** Filling call for each attributes values */
    template<int index, typename... Args>
    void addParticleValue(const int insertPosition, const AttributeClass value, Args... args){
        // Compile test to ensure indexing
        static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
        // insert the value
        attributes[index][insertPosition] = value;
        // Continue for reamining values
        addParticleValue<index+1>( insertPosition, args...);
    }
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    /////////////////////////////////////////////////////
    /////////////////////////////////////////////////////

    void increaseSizeIfNeeded(){
        if( nbParticles == allocatedParticles ){
            // allocate memory
            const int moduloParticlesNumber = (32/sizeof(FReal)); // We want to be rounded to 32B
            allocatedParticles = (FMath::Max(10,int(FReal(nbParticles+1)*1.5)) + moduloParticlesNumber - 1) & ~(moduloParticlesNumber-1);
            // init with 0
            const size_t allocatedBytes = (sizeof(FReal)*3 + sizeof(AttributeClass)*NbAttributesPerParticle)*allocatedParticles;
            FReal* newData  = reinterpret_cast<FReal*>(FAlignedMemory::Allocate32BAligned(allocatedBytes));
            memset( newData, 0, allocatedBytes);
            // copy memory
            const char*const toDelete  = reinterpret_cast<const char*>(positions[0]);
            for(int idx = 0 ; idx < 3 ; ++idx){
                memcpy(newData + (allocatedParticles * idx), positions[idx], sizeof(FReal) * nbParticles);
                positions[idx] = newData + (allocatedParticles * idx);
            }
            // copy attributes
            AttributeClass* startAddress = reinterpret_cast<AttributeClass*>(positions[2] + allocatedParticles);
            for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
                memcpy(startAddress + (allocatedParticles * idx), attributes[idx], sizeof(AttributeClass) * nbParticles);
                attributes[idx] = startAddress + (idx * allocatedParticles);
            }
            // delete old
            FAlignedMemory::Dealloc32BAligned(toDelete);
        }
    }

108
public:
109
110
    /////////////////////////////////////////////////////
    /////////////////////////////////////////////////////
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
111

112
113
    FBasicParticleContainer(const FBasicParticleContainer&)            = delete;
    FBasicParticleContainer& operator=(const FBasicParticleContainer&) = delete;
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
114

115
116
    /////////////////////////////////////////////////////
    /////////////////////////////////////////////////////
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
117

118
119
120
121
122
    /** Basic contructor */
    FBasicParticleContainer() : nbParticles(0), allocatedParticles(0){
        memset(positions, 0, sizeof(positions[0]) * 3);
        memset(attributes, 0, sizeof(attributes[0]) * NbAttributesPerParticle);
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
123

124
    /** Simply dalloc the memory using first pointer
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
125
   */
126
127
128
129
130
    ~FBasicParticleContainer(){
        FAlignedMemory::Dealloc32BAligned(positions[0]);
    }

    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
131
132
133
   * @brief getNbParticles
   * @return  the number of particles
   */
134
135
136
137
    int getNbParticles() const{
        return nbParticles;
    }
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
138
139
140
   * @brief reset the number of particles
   * @warning Only the number of particles is set to 0, the particles are still here.
   */
141
142
143
144
145
    void resetNumberOfParticles()
    {
        nbParticles = 0 ;
    }
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
146
147
148
   * @brief getPositions
   * @return a FReal*[3] to get access to the positions
   */
149
150
151
    const FReal*const* getPositions() const {
        return positions;
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
152

153
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
154
155
156
   * @brief getWPositions
   * @return get the position in write mode
   */
157
158
159
    FReal* const* getWPositions() {
        return positions;
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
160

161
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
162
163
164
165
   * @brief getAttribute
   * @param index
   * @return the attribute at index index
   */
166
167
168
    AttributeClass* getAttribute(const int index) {
        return attributes[index];
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
169

170
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
171
172
173
174
   * @brief getAttribute
   * @param index
   * @return
   */
175
176
177
    const AttributeClass* getAttribute(const int index) const {
        return attributes[index];
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
178

179
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
180
181
   * Get the attribute with a forcing compile optimization
   */
182
183
184
185
186
    template <int index>
    AttributeClass* getAttribute() {
        static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
        return attributes[index];
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
187

188
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
189
190
   * Get the attribute with a forcing compile optimization
   */
191
192
193
194
195
    template <int index>
    const AttributeClass* getAttribute() const {
        static_assert(index < NbAttributesPerParticle, "Index to get attributes is out of scope.");
        return attributes[index];
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
196

197
198
    /////////////////////////////////////////////////////
    /////////////////////////////////////////////////////
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
199

200
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
201
202
203
   * Push called bu FSimpleLeaf
   * Should have a particle position fallowed by attributes
   */
204
205
206
    template<typename... Args>
    void push(const FPoint& inParticlePosition, Args... args){
        // enought space?
207
208
        increaseSizeIfNeeded();

209
210
211
212
213
214
215
        // insert particle data
        positions[0][nbParticles] = inParticlePosition.getX();
        positions[1][nbParticles] = inParticlePosition.getY();
        positions[2][nbParticles] = inParticlePosition.getZ();
        // insert attribute data
        addParticleValue<0>( nbParticles, args...);
        nbParticles += 1;
216
    }
217

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238

    /**
   * Push called bu FSimpleLeaf
   * Should have a particle position fallowed by attributes
   */
    template<typename... Args>
    void push(const FPoint& inParticlePosition, const std::array<AttributeClass , NbAttributesPerParticle>& values){
        // enought space?
        increaseSizeIfNeeded();

        // insert particle data
        positions[0][nbParticles] = inParticlePosition.getX();
        positions[1][nbParticles] = inParticlePosition.getY();
        positions[2][nbParticles] = inParticlePosition.getZ();
        // insert attribute data
        for(int idxVal = 0 ; idxVal < NbAttributesPerParticle ; ++idxVal){
            attributes[idxVal][nbParticles] = values[idxVal];
        }
        nbParticles += 1;
    }

239
    /**
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
240
241
   * Push called usually by FTypedLeaf with the isTarget flag in addition
   */
242
243
244
245
    template<typename... Args>
    void push(const FPoint& inParticlePosition, const FParticleType /*particleType*/, Args... args){
        push(inParticlePosition, args...);
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
246

247
248
249
250
    /** set nb particles to 0 */
    void clear(){
        nbParticles = 0;
    }
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
251

252
    /** to enable rearranging
PIACIBELLO Cyrille's avatar
PIACIBELLO Cyrille committed
253
254
255
   * indexesToRemove must be sorted
   * it removes all the particles at position indexesToRemove
   */
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
    void removeParticles(const int indexesToRemove[], const int nbParticlesToRemove){
        int offset = 1;
        int idxIndexes = 1;
        int idxIns = indexesToRemove[0] + 1;
        for( ; idxIns < nbParticles && idxIndexes < nbParticlesToRemove ; ++idxIns){
            if( idxIns == indexesToRemove[idxIndexes] ){
                idxIndexes += 1;
                offset += 1;
            }
            else{
                for(int idx = 0 ; idx < 3 ; ++idx){
                    positions[idx][idxIns-offset] = positions[idx][idxIns];
                }
                for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
                    attributes[idx][idxIns-offset] = attributes[idx][idxIns];
                }
            }
        }
        for( ; idxIns < nbParticles ; ++idxIns){
            for(int idx = 0 ; idx < 3 ; ++idx){
                positions[idx][idxIns-offset] = positions[idx][idxIns];
            }
            for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
                attributes[idx][idxIns-offset] = attributes[idx][idxIns];
            }
        }
        nbParticles -= nbParticlesToRemove;
283
    }
284
285
286
287
288
289
290

    /////////////////////////////////////////////////////
    /////////////////////////////////////////////////////

    /** The size to send a leaf */
    int getSavedSize() const{
        return int(sizeof(nbParticles) + nbParticles * (3 * sizeof(FReal) + NbAttributesPerParticle * sizeof(AttributeClass)));
291
    }
292
293
294
295
296
297
298
299
300
301
302

    /** Save the current cell in a buffer */
    template <class BufferWriterClass>
    void save(BufferWriterClass& buffer) const{
        buffer << nbParticles;
        for(int idx = 0 ; idx < 3 ; ++idx){
            buffer.write(positions[idx], nbParticles);
        }
        for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
            buffer.write(attributes[idx], nbParticles);
        }
303
    }
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
    /** Restore the current cell from a buffer */
    template <class BufferReaderClass>
    void restore(BufferReaderClass& buffer){
        buffer >> nbParticles;
        if( nbParticles >= allocatedParticles ){
            // allocate memory
            const int moduloParticlesNumber = (32/sizeof(FReal)); // We want to be rounded to 32B
            allocatedParticles = (FMath::Max(10,int(FReal(nbParticles+1)*1.5)) + moduloParticlesNumber - 1) & ~(moduloParticlesNumber-1);
            // init with 0
            const size_t allocatedBytes = (sizeof(FReal)*3 + sizeof(AttributeClass)*NbAttributesPerParticle)*allocatedParticles;
            FReal* newData  = reinterpret_cast<FReal*>(FAlignedMemory::Allocate32BAligned(allocatedBytes));
            memset( newData, 0, allocatedBytes);

            FAlignedMemory::Dealloc32BAligned(positions[0]);
            for(int idx = 0 ; idx < 3 ; ++idx){
                positions[idx] = newData + (allocatedParticles * idx);
            }
            AttributeClass* startAddress = reinterpret_cast<AttributeClass*>(positions[2] + allocatedParticles);
            for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
                attributes[idx] = startAddress + (idx * allocatedParticles);
            }
        }
        for(int idx = 0 ; idx < 3 ; ++idx){
            buffer.fillArray(positions[idx], nbParticles);
        }
        for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
            buffer.fillArray(attributes[idx], nbParticles);
        }
332
333
    }

334
335
336
337
338
339
    /** Reset the attributes to zeros */
    void resetToInitialState(){
        for(unsigned idx = 0 ; idx < NbAttributesPerParticle ; ++idx){
            memset(attributes[idx], 0, sizeof(AttributeClass) * allocatedParticles);
        }
    }
340
341
342
343
344

    /** Reset the attributes to zeros */
    void resetToInitialState(const int idxAttribute){
        memset(attributes[idxAttribute], 0, sizeof(AttributeClass) * allocatedParticles);
    }
345
346
347
348
349
350
};


#endif //FBASICPARTICLECONTAINER_HPP