From 5367316b28b03d279843e4ece8056ecf5ac2a45b Mon Sep 17 00:00:00 2001
From: Berenger Bramas <Berenger.Bramas@inria.fr>
Date: Fri, 6 Nov 2015 21:58:36 +0100
Subject: [PATCH] add a tsm utest on the chebyshev kernel

---
 UTests/utestChebyshevDirectTsm.cpp | 275 +++++++++++++++++++++++++++++
 1 file changed, 275 insertions(+)
 create mode 100644 UTests/utestChebyshevDirectTsm.cpp

diff --git a/UTests/utestChebyshevDirectTsm.cpp b/UTests/utestChebyshevDirectTsm.cpp
new file mode 100644
index 000000000..eccd79f3a
--- /dev/null
+++ b/UTests/utestChebyshevDirectTsm.cpp
@@ -0,0 +1,275 @@
+
+// ===================================================================================
+// Copyright ScalFmm 2011 INRIA,
+// 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".
+// ===================================================================================
+
+#include "Utils/FGlobal.hpp"
+
+#include "Containers/FOctree.hpp"
+#include "Containers/FVector.hpp"
+
+#include "Kernels/Chebyshev/FChebCell.hpp"
+#include "Kernels/P2P/FP2PParticleContainerIndexed.hpp"
+#include "Kernels/Interpolation/FInterpMatrixKernel.hpp"
+
+#include "Components/FTypedLeaf.hpp"
+#include "Extensions/FExtendCellType.hpp"
+#include "Kernels/Chebyshev/FChebSymKernel.hpp"
+
+#include "Files/FRandomLoader.hpp"
+#include "Files/FFmaGenericLoader.hpp"
+
+#include "Core/FFmmAlgorithmThreadTsm.hpp"
+#include "Core/FFmmAlgorithmTsm.hpp"
+
+#include "FUTester.hpp"
+
+
+/** the test class the rotation and target source model.
+ *
+ */
+class TestChebyshevDirectTsm : public FUTester<TestChebyshevDirectTsm> {
+    /** The test method to factorize all the test based on different kernels */
+    template <class FReal, class CellClass, class ContainerClass, class KernelClass, class LeafClass,
+    class OctreeClass, class FmmClass, class MatrixKernelClass>
+    void RunTest(){
+        const MatrixKernelClass MatrixKernel;
+        // Warning in make test the exec dir it Build/UTests
+        // Load particles
+        const int nbSources = 5000;
+        const int nbTargets = 5000;
+
+        FRandomLoader<FReal> loader(nbSources + nbTargets);
+
+        Print("Number of particles:");
+        Print(loader.getNumberOfParticles());
+
+        const int NbLevels      = 4;
+        const int SizeSubLevels = 3;
+
+        // Create octree
+        OctreeClass tree(NbLevels, SizeSubLevels, loader.getBoxWidth(), loader.getCenterOfBox());
+
+        const FReal physicalValue = 0.10;
+        //
+        FmaRWParticle<FReal, 8,8>* const particlesTargets = new FmaRWParticle<FReal, 8,8>[nbTargets];
+        for(FSize idxPart = 0 ; idxPart < nbTargets ; ++idxPart){
+            FPoint<FReal> position;
+            loader.fillParticle(&position);
+            // put in tree
+            tree.insert(position, FParticleTypeTarget, idxPart, physicalValue);
+            // get copy
+            particlesTargets[idxPart].setPosition(position);
+            *(particlesTargets[idxPart].setPhysicalValue()) = physicalValue;
+            *(particlesTargets[idxPart].setPotential())        = 0.0;
+            particlesTargets[idxPart].setForces()[0]        = 0.0;
+            particlesTargets[idxPart].setForces()[1]        = 0.0;
+            particlesTargets[idxPart].setForces()[2]        = 0.0;
+        }
+
+        FmaRWParticle<FReal, 8,8>* const particlesSources = new FmaRWParticle<FReal, 8,8>[nbSources];
+        for(FSize idxPart = 0 ; idxPart < nbSources ; ++idxPart){
+            FPoint<FReal> position;
+            loader.fillParticle(&position);
+            // put in tree
+            tree.insert(position, FParticleTypeSource, idxPart, physicalValue);
+            // get copy
+            particlesSources[idxPart].setPosition(position);
+            *(particlesSources[idxPart].setPhysicalValue()) = physicalValue;
+        }
+
+
+        // Run FMM
+        Print("Fmm...");
+        //KernelClass kernels(NbLevels,loader.getBoxWidth());
+        KernelClass kernels(NbLevels,loader.getBoxWidth(), loader.getCenterOfBox(), &MatrixKernel);
+        FmmClass algo(&tree,&kernels);
+        algo.execute();
+        //
+        //
+
+        // Run direct computation
+        Print("Direct...");
+        for(int idxTarget = 0 ; idxTarget < nbTargets ; ++idxTarget){
+            for(int idxOther = 0 ; idxOther < nbSources ; ++idxOther){
+                FP2P::NonMutualParticles(
+                        particlesSources[idxOther].getPosition().getX(), particlesSources[idxOther].getPosition().getY(),
+                        particlesSources[idxOther].getPosition().getZ(),particlesSources[idxOther].getPhysicalValue(),
+                        particlesTargets[idxTarget].getPosition().getX(), particlesTargets[idxTarget].getPosition().getY(),
+                        particlesTargets[idxTarget].getPosition().getZ(),particlesTargets[idxTarget].getPhysicalValue(),
+                        &particlesTargets[idxTarget].setForces()[0],&particlesTargets[idxTarget].setForces()[1],
+                        &particlesTargets[idxTarget].setForces()[2],particlesTargets[idxTarget].setPotential(),
+                        &MatrixKernel);
+            }
+        }
+
+        //
+        // Assert
+        /////////////////////////////////////////////////////////////////////////////////////////////////
+        // Compute direct energy
+        /////////////////////////////////////////////////////////////////////////////////////////////////
+        FReal energy= 0.0 , energyD = 0.0 ;
+        for(int idx = 0 ; idx <  nbTargets  ; ++idx){
+            energyD +=  particlesTargets[idx].getPotential()*particlesTargets[idx].getPhysicalValue() ;
+        }
+        /////////////////////////////////////////////////////////////////////////////////////////////////
+        // Compare
+        /////////////////////////////////////////////////////////////////////////////////////////////////
+        Print("Compute Diff...");
+        FMath::FAccurater<FReal> potentialDiff;
+        FMath::FAccurater<FReal> fx, fy, fz;
+        { // Check that each particle has been summed with all other
+
+            tree.forEachLeaf([&](LeafClass* leaf){
+                if( leaf->getTargets()->getNbParticles() ){
+                    const FReal*const potentials = leaf->getTargets()->getPotentials();
+                    const FReal*const physicalValues = leaf->getTargets()->getPhysicalValues();
+                    const FReal*const forcesX = leaf->getTargets()->getForcesX();
+                    const FReal*const forcesY = leaf->getTargets()->getForcesY();
+                    const FReal*const forcesZ = leaf->getTargets()->getForcesZ();
+                    const FSize nbParticlesInLeaf = leaf->getTargets()->getNbParticles();
+                    const FVector<FSize>& indexes = leaf->getTargets()->getIndexes();
+
+                    for(FSize idxPart = 0 ; idxPart < nbParticlesInLeaf ; ++idxPart){
+                        const FSize indexPartOrig = indexes[idxPart];
+                        potentialDiff.add(particlesTargets[indexPartOrig].getPotential(),potentials[idxPart]);
+                        fx.add(particlesTargets[indexPartOrig].getForces()[0],forcesX[idxPart]);
+                        fy.add(particlesTargets[indexPartOrig].getForces()[1],forcesY[idxPart]);
+                        fz.add(particlesTargets[indexPartOrig].getForces()[2],forcesZ[idxPart]);
+                        energy   += potentials[idxPart]*physicalValues[idxPart];
+                    }
+                }
+            });
+        }
+
+        delete[] particlesTargets;
+        delete[] particlesSources;
+        //
+        // Print for information
+
+        Print("Potential diff is = ");
+        printf("         Pot L2Norm     %e\n",potentialDiff.getL2Norm());
+        printf("         Pot RL2Norm   %e\n",potentialDiff.getRelativeL2Norm());
+        printf("         Pot RMSError   %e\n",potentialDiff.getRMSError());
+        Print("Fx diff is = ");
+        printf("         Fx L2Norm     %e\n",fx.getL2Norm());
+        printf("         Fx RL2Norm   %e\n",fx.getRelativeL2Norm());
+        printf("         Fx RMSError   %e\n",fx.getRMSError());
+        Print("Fy diff is = ");
+        printf("        Fy L2Norm     %e\n",fy.getL2Norm());
+        printf("        Fy RL2Norm   %e\n",fy.getRelativeL2Norm());
+        printf("        Fy RMSError   %e\n",fy.getRMSError());
+        Print("Fz diff is = ");
+        printf("        Fz L2Norm     %e\n",fz.getL2Norm());
+        printf("        Fz RL2Norm   %e\n",fz.getRelativeL2Norm());
+        printf("        Fz RMSError   %e\n",fz.getRMSError());
+        FReal L2error = (fx.getRelativeL2Norm()*fx.getRelativeL2Norm() + fy.getRelativeL2Norm()*fy.getRelativeL2Norm()  + fz.getRelativeL2Norm() *fz.getRelativeL2Norm()  );
+        printf(" Total L2 Force Error= %e\n",FMath::Sqrt(L2error)) ;
+        printf("  Energy Error  =   %.12e\n",FMath::Abs(energy-energyD));
+        printf("  Energy FMM    =   %.12e\n",FMath::Abs(energy));
+        printf("  Energy DIRECT =   %.12e\n",FMath::Abs(energyD));
+
+        // Assert
+        const FReal MaximumDiffPotential = FReal(9e-3);
+        const FReal MaximumDiffForces     = FReal(9e-2);
+        //
+        Print("Test1 - Error Relative L2 norm Potential ");
+        uassert(potentialDiff.getRelativeL2Norm() < MaximumDiffPotential);    //1
+        Print("Test2 - Error RMS L2 norm Potential ");
+        uassert(potentialDiff.getRMSError() < MaximumDiffPotential);  //2
+        Print("Test3 - Error Relative L2 norm FX ");
+        uassert(fx.getRelativeL2Norm()  < MaximumDiffForces);                       //3
+        Print("Test4 - Error RMS L2 norm FX ");
+        uassert(fx.getRMSError() < MaximumDiffForces);                      //4
+        Print("Test5 - Error Relative L2 norm FY ");
+        uassert(fy.getRelativeL2Norm()  < MaximumDiffForces);                       //5
+        Print("Test6 - Error RMS L2 norm FY ");
+        uassert(fy.getRMSError() < MaximumDiffForces);                      //6
+        Print("Test7 - Error Relative L2 norm FZ ");
+        uassert(fz.getRelativeL2Norm()  < MaximumDiffForces);                      //8
+        Print("Test8 - Error RMS L2 norm FZ ");
+        uassert(fz.getRMSError() < MaximumDiffForces);                                           //8
+        Print("Test9 - Error Relative L2 norm F ");
+        uassert(L2error              < MaximumDiffForces);                                            //9   Total Force
+        Print("Test10 - Relative error Energy ");
+        uassert(FMath::Abs(energy-energyD) /energyD< MaximumDiffPotential);                     //10  Total Energy
+    }
+
+    /** If memstas is running print the memory used */
+    void PostTest() {
+        if( FMemStats::controler.isUsed() ){
+            std::cout << "Memory used at the end " << FMemStats::controler.getCurrentAllocated() << " Bytes (" << FMemStats::controler.getCurrentAllocatedMB() << "MB)\n";
+            std::cout << "Max memory used " << FMemStats::controler.getMaxAllocated() << " Bytes (" << FMemStats::controler.getMaxAllocatedMB() << "MB)\n";
+            std::cout << "Total memory used " << FMemStats::controler.getTotalAllocated() << " Bytes (" << FMemStats::controler.getTotalAllocatedMB() << "MB)\n";
+        }
+    }
+
+    ///////////////////////////////////////////////////////////
+    // The tests!
+    ///////////////////////////////////////////////////////////
+
+    static const int P = 5;
+
+    /** Chebyshev */
+    void TestChebyshev(){
+        typedef double FReal;
+        typedef FInterpMatrixKernelR<FReal> MatrixKernelClass;
+        typedef FTypedChebCell<FReal,P>    CellClass;
+        typedef FP2PParticleContainerIndexed<FReal>  ContainerClass;
+
+        typedef FChebSymKernel<FReal, CellClass, ContainerClass, MatrixKernelClass, P >          KernelClass;
+
+        typedef FTypedLeaf<FReal,ContainerClass >                     LeafClass;
+        typedef FOctree<FReal, CellClass, ContainerClass , LeafClass >  OctreeClass;
+
+        typedef FFmmAlgorithmTsm<OctreeClass, CellClass, ContainerClass, KernelClass, LeafClass > FmmClass;
+
+        RunTest<FReal, CellClass, ContainerClass, KernelClass, LeafClass, OctreeClass, FmmClass, MatrixKernelClass>();
+    }
+
+    void TestChebyshevThread(){
+        typedef double FReal;
+        typedef FInterpMatrixKernelR<FReal> MatrixKernelClass;
+        typedef FTypedChebCell<FReal,P>    CellClass;
+        typedef FP2PParticleContainerIndexed<FReal>  ContainerClass;
+
+        typedef FChebSymKernel<FReal, CellClass, ContainerClass, MatrixKernelClass, P >          KernelClass;
+
+        typedef FTypedLeaf<FReal,ContainerClass >                     LeafClass;
+        typedef FOctree<FReal, CellClass, ContainerClass , LeafClass >  OctreeClass;
+
+        typedef FFmmAlgorithmThreadTsm<OctreeClass, CellClass, ContainerClass, KernelClass, LeafClass > FmmClass;
+
+        RunTest<FReal, CellClass, ContainerClass, KernelClass, LeafClass, OctreeClass, FmmClass, MatrixKernelClass>();
+    }
+
+    ///////////////////////////////////////////////////////////
+    // Set the tests!
+    ///////////////////////////////////////////////////////////
+
+    /** set test */
+    void SetTests(){
+        AddTest(&TestChebyshevDirectTsm::TestChebyshev,"Test Chebyshev Kernel TSM");
+        AddTest(&TestChebyshevDirectTsm::TestChebyshevThread,"Test Chebyshev Kernel TSM thread");
+    }
+};
+
+
+// You must do this
+TestClass(TestChebyshevDirectTsm)
+
+
+
+
-- 
GitLab