testPartitionsMapping.cpp 6.52 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
// ===================================================================================

// ==== CMAKE =====
// @FUSE_MPI
// ================

#include <iostream>

#include <cstdio>
#include <cstdlib>


#include "../../Src/Kernels/Rotation/FRotationCell.hpp"
#include "../../Src/Kernels/Rotation/FRotationKernel.hpp"

#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Kernels/P2P/FP2PParticleContainerIndexed.hpp"

#include "../../Src/Utils/FParameters.hpp"
#include "../../Src/Utils/FMemUtils.hpp"
39
#include "../../Src/Utils/FPartitionsMapping.hpp"
40 41 42 43 44 45 46 47 48 49 50

#include "../../Src/Containers/FOctree.hpp"
#include "../../Src/Containers/FVector.hpp"

#include "../../Src/Files/FRandomLoader.hpp"
#include "../../Src/Files/FMpiTreeBuilder.hpp"

#include "../../Src/Core/FFmmAlgorithm.hpp"
#include "../../Src/Core/FFmmAlgorithmThread.hpp"
#include "../../Src/Core/FFmmAlgorithmThreadProc.hpp"

51
#include "../../Src/Utils/FLeafBalance.hpp"
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 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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

#include "../../Src/Utils/FParameterNames.hpp"

/**
 * This program runs the FMM Algorithm Distributed with the Rotation kernel
 */

// Simply create particles and try the kernels
int main(int argc, char* argv[])
{
    FHelpDescribeAndExit(argc, argv,
                         "Test with MPI the chebyshev FMM and compare it to the direct computation for debugging purpose.",
                         FParameterDefinitions::NbParticles, FParameterDefinitions::OctreeHeight,
                         FParameterDefinitions::OctreeSubHeight, FParameterDefinitions::NbThreads);

    typedef double FReal;

    FMpi app(argc,argv);

    const FSize nbParticles       = FParameters::getValue(argc,argv, FParameterDefinitions::NbParticles.options, 10000000ULL);
    const unsigned int TreeHeight    = FParameters::getValue(argc, argv, FParameterDefinitions::OctreeHeight.options, 5);
    FTic time;

    std::cout << ">> This executable has to be used to test Proc Rotation Algorithm. \n";

    // init particles position and physical value
    struct TestParticle{
        FPoint<FReal> position;
        const FPoint<FReal>& getPosition(){
            return position;
        }
    };

    // open particle file
    std::cout << "Creating : " << nbParticles << "\n" << std::endl;
    FRandomLoader<FReal> loader(nbParticles, 1.0, FPoint<FReal>(0,0,0), app.global().processId());

    time.tic();
    std::unique_ptr<TestParticle[]> particles(new TestParticle[loader.getNumberOfParticles()]);
    for(FSize idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
        loader.fillParticle(&particles[idxPart].position);
    }

    FPartitionsMapping<FReal> map(app.global());

    FVector<FPartitionsMapping<double>::TestParticle<0> > finalParticles = map.distributeParticles<0>(loader.getNumberOfParticles(),
                                                                   loader.getCenterOfBox(),
                                                                   loader.getBoxWidth(), TreeHeight,
                                                                   [&](const int idx, FPoint<FReal>* position, std::array<FReal, 0>* /*val*/){
        position->setPosition(particles[idx].position.getX(),
                              particles[idx].position.getY(),
                              particles[idx].position.getZ());
    });

    // Test every particles exist
    {
        std::unique_ptr<int[]> count(new int[app.global().processCount() * nbParticles]);
        memset(count.get(), 0, sizeof(int) * app.global().processCount() * nbParticles);
        for(FSize part = 0 ; part < finalParticles.getSize() ; ++part){
            const FSize idx = finalParticles[part].initialProcOwner*nbParticles + finalParticles[part].localIndex;
            FAssertLF(count[idx] == 0)
            count[idx] = 1;
        }

        FMpi::Assert( MPI_Allreduce(MPI_IN_PLACE, count.get(), app.global().processCount()*nbParticles, MPI_INT, MPI_SUM,
                      app.global().getComm()), __LINE__);

        for(FSize part = 0 ; part < app.global().processCount()*nbParticles ; ++part){
            FAssertLF(count[part] == 1);
        }
    }

    // Test to send data
    {
        std::unique_ptr<std::array<FReal, 2>[]> toDistr(new std::array<FReal, 2>[nbParticles]);
        for(FSize idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
            toDistr[idxPart][0] = app.global().processId();
            toDistr[idxPart][1] = FReal(idxPart);
        }

        std::unique_ptr<std::array<FReal, 2>[]> res = map.distributeData<2>(toDistr.get());

        for(FSize part = 0 ; part < finalParticles.getSize() ; ++part){
            if(int(res[part][0]) != finalParticles[part].initialProcOwner)
                    std::cout << "[" << app.global().processId() << "]Res proc is " << res[part][0] << " should be " << finalParticles[part].initialProcOwner << std::endl;
            if(int(res[part][1]) != finalParticles[part].localIndex)
                    std::cout << "[" << app.global().processId() << "]Res localidx is " << res[part][1] << " should be " << finalParticles[part].localIndex << std::endl;
        }

        std::unique_ptr<std::array<FReal, 2>[]> resBack = map.getResultingData<2>(res.get());

        for(FSize part = 0 ; part < loader.getNumberOfParticles() ; ++part){
            if(int(resBack[part][0]) != app.global().processId())
                    std::cout << "[" << app.global().processId() << "]ResBack proc is " << resBack[part][0] << " should be " << app.global().processId() << std::endl;
            if(int(resBack[part][1]) != part)
                    std::cout << "[" << app.global().processId() << "]ResBack localidx is " << resBack[part][1] << " should be " << part << std::endl;
        }
    }

    return 0;
}