FDumbCostKernel.hpp 6.98 KB
Newer Older
1
// ===================================================================================
2 3 4 5
// Copyright ScalFmm 2016 INRIA, Olivier Coulaud, Bérenger Bramas,
// Matthias Messner olivier.coulaud@inria.fr, berenger.bramas@inria.fr
// This software is a computer program whose purpose is to compute the
// FMM.
6
//
7
// This software is governed by the CeCILL-C and LGPL licenses and
8
// abiding by the rules of distribution of free software.
9 10 11
// An extension to the license is given to allow static linking of scalfmm
// inside a proprietary application (no matter its license).
// See the main license file for more details.
12
//
13 14 15
// 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
16 17 18
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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
// ===================================================================================

// ==== CMAKE ====
// Keep in private GIT
// @SCALFMM_PRIVATE


#ifndef DUMBCOSTKERNEL_HPP
#define DUMBCOSTKERNEL_HPP

#include <stdexcept>

#include "Utils/FGlobal.hpp"

#include "Utils/FSmartPointer.hpp"

#include "Components/FAbstractKernels.hpp"

class FTreeCoordinate;

/**
 * \author Quentin Khan, Matthias Messner (original file: FChebFlopsSymKernel)
 * \brief Dumb cost computation for FMM.
 *
 * Please read the license
 *
 * This kernel implements a dumb cost the cost computation for FMM operators
 * exploiting the symmetries in the far-field. It implements all interfaces
 * (P2P, P2M, M2M, M2L, L2L, L2P) which are required by the
 * FFmmAlgorithm and FFmmAlgorithmThread.
 *
 * \tparam Freal Type of real number representation
 * \tparam CellClass Type of cell
 * \tparam ContainerClass Type of container to store particles
 * \tparam OctreeClass Class of the octree to work on.
 */
template < typename FReal, class CellClass, class ContainerClass, class OctreeClass>
class FDumbCostKernel : public FAbstractKernels<CellClass, ContainerClass>
{
public:
    // Class types available to the rest of the world
    /// Type of real number representation
    using _FReal = FReal;
    /// Type of cell
    using _CellClass = CellClass;
    /// Type of container to store particles
    using _ContainerClass = ContainerClass;
    /// Class of the octree to work on
    using _OctreeClass = OctreeClass;


    /// The tree the kernel is working on. Needed to attain cells in the P2P
    /// operator (we only get the particles containers otherwise)
    const OctreeClass* const _tree;

    /// The tree height
    const unsigned int _treeHeight;

    /// count permuted local and multipole expansions
78
    unsigned int _countExp[343];
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

    /// Flops count for each operator of the FMM. 
    unsigned long long flopsP2M = 0,
        flopsM2M = 0,
        flopsM2L = 0,
        flopsL2L = 0,
        flopsL2P = 0,
        flopsP2P = 0;

    /// Operators count.
    unsigned long long countP2M = 0,
        countM2M = 0,
        countM2L = 0,
        countL2L = 0,
        countL2P = 0,
        countP2P = 0;

public:
    /**
     * The constructor initializes all constant attributes and it reads the
     * precomputed and compressed M2L operators from a binary file (a
     * runtime_error is thrown if the required file is not valid).
     */
    FDumbCostKernel(OctreeClass* tree, const FReal Epsilon) :
          _tree(tree),
104 105 106
          _treeHeight(_tree->getHeight()) {
        //_countExp = new unsigned int [343];
    }
107 108 109 110

    /** Copy constructor */
    FDumbCostKernel(const FDumbCostKernel& other) :
        _tree(other._tree),
111 112
        _treeHeight(other._treeHeight) {
        // _countExp = new unsigned int [343];
113 114 115 116
    }

    /** Destructor */
    ~FDumbCostKernel() {
117
        // delete [] _countExp;
118 119
    }

120
    void P2M(CellClass* const cell, const ContainerClass* const SourceParticles) override {
121 122 123 124 125 126 127 128 129
        FSize tmpCost = SourceParticles->getNbParticles();
        flopsP2M += tmpCost;
        cell->addCost(tmpCost);
        countP2M++;
    }


    void M2M(CellClass* const FRestrict cell,
             const CellClass* const FRestrict* const FRestrict ChildrenCells,
130
             const int /*TreeLevel*/) override {
131 132 133 134 135 136 137 138 139 140 141
        FSize flops = 0;
        for ( unsigned int childIdx = 0; childIdx < 8; ++childIdx )
            if ( ChildrenCells[childIdx] )    
                flops += 1;
        flopsM2M += flops;
        cell->addCost(flops);
        countM2M++;
    }


    void M2L(CellClass* const FRestrict cell,
142 143 144 145
             const CellClass* /*SourceCells*/[],
             const int /*positions*/[],
             const int size,
             const int /* TreeLevel */) override {
146
        FSize flops = 0;
147 148 149 150

		memset(_countExp, 0, sizeof(int) * 343);
        for (int idx = 0; idx < size; ++idx) {
            flops += 1;
151 152 153 154 155 156 157 158 159 160
        }
            
        flopsM2L += flops;
        cell->addCost(flops);
        countM2L++;
    }


    void L2L(const CellClass* const FRestrict /* not needed */,
             CellClass* FRestrict *const FRestrict ChildCells,
161
             const int /* TreeLevel*/) override {
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
        FSize flops = 0;
        FSize tmpCost = 0;
        for (unsigned int childIdx = 0; childIdx < 8; ++childIdx ) {
            if (ChildCells[childIdx]) {
                tmpCost = 1;
                flops += tmpCost;
                ChildCells[childIdx]->addCost(tmpCost);
            }            
        }

        flopsL2L += flops;
        countL2L++;
    }



    void L2P(const CellClass* const cell,
179
             ContainerClass* const TargetParticles) override {
180 181 182 183 184 185 186 187 188 189 190
        FSize tmpCost = TargetParticles->getNbParticles();
        flopsL2P += tmpCost;
        cell->addCost(tmpCost);
        countL2P++;
    }

    

    void P2P(const FTreeCoordinate& LeafCellCoordinate, // needed for periodic boundary conditions
             ContainerClass* const FRestrict TargetParticles,
             const ContainerClass* const FRestrict SourceParticles,
191 192 193
             ContainerClass* const /*NeighborSourceParticles*/[],
             const int /*positions*/[],
             const int size) override {
194 195 196 197 198 199
        FSize srcPartCount = SourceParticles->getNbParticles();
        FSize tgtPartCount = TargetParticles->getNbParticles();

        FSize tmpCost = srcPartCount * tgtPartCount;


200
        CellClass* cell = _tree->getCell(
201
            LeafCellCoordinate.getMortonIndex(),
202 203 204 205 206 207 208 209 210 211 212 213 214 215
            _treeHeight - 1);

        flopsP2P += tmpCost;
        cell->addNearCost(tmpCost);
        countP2P++;
    }

    void P2POuter(const FTreeCoordinate& LeafCellCoordinate, // needed for periodic boundary conditions
             ContainerClass* const FRestrict TargetParticles,
             ContainerClass* const /*NeighborSourceParticles*/[],
             const int /*positions*/[],
             const int size) override {
        FSize tmpCost = 0;

216
        CellClass* cell = _tree->getCell(
217
            LeafCellCoordinate.getMortonIndex(),
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
            _treeHeight - 1);

        flopsP2P += tmpCost;
        cell->addNearCost(tmpCost);
        countP2P++;
    }
};





#endif 

// [--END--]