From 2c1cdef1fdb334d89bc45bddc048ba4710b26335 Mon Sep 17 00:00:00 2001
From: piacibel <cyrille.piacibello@inria.fr>
Date: Wed, 6 May 2015 18:33:11 +0200
Subject: [PATCH] Source Target algorithm is now functionnal. An example can be
 found in testSphereElectro.c

---
 Addons/CKernelApi/Src/FInterEngine.hpp      |  18 ++-
 Addons/CKernelApi/Src/FScalfmmApiInit.cpp   |   7 +-
 Addons/CKernelApi/Src/FUserKernelEngine.hpp |   2 +
 Addons/CKernelApi/Tests/Timers.h            |  54 +++++++
 Addons/CKernelApi/Tests/testChebInterface.c |  51 +------
 Addons/CKernelApi/Tests/testSphereElectro.c | 148 ++++++++++++++------
 6 files changed, 183 insertions(+), 97 deletions(-)
 create mode 100644 Addons/CKernelApi/Tests/Timers.h

diff --git a/Addons/CKernelApi/Src/FInterEngine.hpp b/Addons/CKernelApi/Src/FInterEngine.hpp
index b2c75cee0..f0fe11d4d 100644
--- a/Addons/CKernelApi/Src/FInterEngine.hpp
+++ b/Addons/CKernelApi/Src/FInterEngine.hpp
@@ -31,6 +31,7 @@
 #include "Arranger/FArrangerPeriodic.hpp"
 #include "Arranger/FBasicParticleContainerIndexedMover.hpp"
 #include "Arranger/FParticleTypedIndexedMover.hpp"
+#include "Extensions/FExtendCellType.hpp"
 
 #include "Core/FFmmAlgorithmThread.hpp"
 #include "Core/FFmmAlgorithm.hpp"
@@ -38,6 +39,7 @@
 #include "Core/FFmmAlgorithmThreadTsm.hpp"
 
 
+
 /**
  * @class FInterEngine implements API for Interpolations kernels, its
  * templates can be ChebCell/ChebKernel or UnifCell/UnifKernel
@@ -63,6 +65,7 @@ private:
     // ArrangerClass * arranger;
 
 
+
 public:
     /**
      * @brief Constructor : build the tree and the interpolation
@@ -72,9 +75,10 @@ public:
      * @param BoxCenter double[3] coordinate of the center of the
      * simulation box
      */
-    FInterEngine(scalfmm_kernel_type KernelType) :
+    FInterEngine(scalfmm_kernel_type KernelType, scalfmm_algorithm algo) :
         kernel(nullptr), matrix(nullptr), octree(nullptr)/*,arranger(nullptr)*/{
         FScalFMMEngine<FReal>::kernelType = KernelType;
+        FScalFMMEngine<FReal>::Algorithm = algo;
     }
 
     void build_tree(int TreeHeight, FReal BoxWidth , FReal * BoxCenter,User_Scalfmm_Cell_Descriptor notUsedHere){
@@ -760,11 +764,13 @@ public:
             }
         case 3:
             {
-                // typedef FFmmAlgorithmThreadTsm<OctreeClass,InterCell,ContainerClass,InterKernel,LeafClass> AlgoClassTargetSource;
-                // AlgoClassTargetSource* algoTS = new AlgoClassTargetSource(octree,kernel);
-                // algoTS->execute();
-                // FScalFMMEngine<FReal>::algoTimer = algoTS;
-                // break;
+                // class local : public InterCell, public unExtendedCell{
+                // };
+                typedef FFmmAlgorithmThreadTsm<OctreeClass,InterCell,ContainerClass,InterKernel,LeafClass> AlgoClassTargetSource;
+                AlgoClassTargetSource* algoTS = new AlgoClassTargetSource(octree,kernel);
+                algoTS->execute();
+                FScalFMMEngine<FReal>::algoTimer = algoTS;
+                break;
             }
         default :
             std::cout<< "No algorithm found (probably for strange reasons) : "<< FScalFMMEngine<FReal>::Algorithm <<" exiting" << std::endl;
diff --git a/Addons/CKernelApi/Src/FScalfmmApiInit.cpp b/Addons/CKernelApi/Src/FScalfmmApiInit.cpp
index 19cfb08b5..f286a4a7c 100644
--- a/Addons/CKernelApi/Src/FScalfmmApiInit.cpp
+++ b/Addons/CKernelApi/Src/FScalfmmApiInit.cpp
@@ -30,7 +30,7 @@ extern "C" scalfmm_handle scalfmm_init(/*int TreeHeight,double BoxWidth,double*
             typedef FInterpMatrixKernelR<FReal>                                        MatrixKernelClass;
             typedef FChebSymKernel<FReal,ChebCell,ContainerClass,MatrixKernelClass,7>        ChebKernel;
 
-            handle->engine = new FInterEngine<FReal,ChebCell,ChebKernel,LeafClass>(/*TreeHeight,BoxWidth,BoxCenter, */KernelType);
+            handle->engine = new FInterEngine<FReal,ChebCell,ChebKernel,LeafClass>(/*TreeHeight,BoxWidth,BoxCenter, */KernelType,algo);
             break;
             // case 2:
             //     //TODO typedefs
@@ -61,13 +61,14 @@ extern "C" scalfmm_handle scalfmm_init(/*int TreeHeight,double BoxWidth,double*
         case 1:
             //TODO typedefs
             typedef FP2PParticleContainerIndexed<FReal>                                 ContainerClass;
-            typedef FChebCell<FReal,7>                                                   ChebCell;
+            //typedef FChebCell<FReal,7>                                                   ChebCell;
+            typedef FTypedChebCell<FReal,7>                                                   ChebCell;
             typedef FSimpleLeaf<FReal,ContainerClass>                                         LeafClass;
 
             typedef FInterpMatrixKernelR<FReal>                                        MatrixKernelClass;
             typedef FChebSymKernel<FReal,ChebCell,ContainerClass,MatrixKernelClass,7>        ChebKernel;
 
-            handle->engine = new FInterEngine<FReal,ChebCell,ChebKernel,LeafClass>(/*TreeHeight,BoxWidth,BoxCenter, */KernelType);
+            handle->engine = new FInterEngine<FReal,ChebCell,ChebKernel,LeafClass>(/*TreeHeight,BoxWidth,BoxCenter, */KernelType,algo);
             break;
             // case 2:
             //     //TODO typedefs
diff --git a/Addons/CKernelApi/Src/FUserKernelEngine.hpp b/Addons/CKernelApi/Src/FUserKernelEngine.hpp
index 834ee6a40..7004a7fbe 100644
--- a/Addons/CKernelApi/Src/FUserKernelEngine.hpp
+++ b/Addons/CKernelApi/Src/FUserKernelEngine.hpp
@@ -108,6 +108,7 @@ public:
         if(kernel.m2m){
             for(int idx = 0 ; idx < 8 ; ++idx){
                 if( children[idx] ){
+                    printf("lvl : %d\n",level);
                     kernel.m2m(level, cell->getContainer(), idx, children[idx]->getContainer(), userData);
                 }
             }
@@ -253,6 +254,7 @@ public:
 
     void build_tree(int TreeHeight,double BoxWidth,double* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor){
         CoreCell::Init(user_cell_descriptor);
+        printf("Tree Height : %d \n",TreeHeight);
         this->octree = new OctreeClass(TreeHeight,FMath::Min(3,TreeHeight-1),BoxWidth,FPoint<FReal>(BoxCenter));
     }
 
diff --git a/Addons/CKernelApi/Tests/Timers.h b/Addons/CKernelApi/Tests/Timers.h
new file mode 100644
index 000000000..3be381a41
--- /dev/null
+++ b/Addons/CKernelApi/Tests/Timers.h
@@ -0,0 +1,54 @@
+#ifndef TIMERS_H
+#define TIMERS_H
+
+#include <time.h>
+#include <sys/time.h>
+
+
+/**
+ * @brief Wrapper on timeval struct
+ */
+typedef struct timer{
+    struct timeval start;
+    struct timeval end;
+}Timer;
+
+/**
+ * @brief monitoring function (init start)
+ */
+void tic(Timer* inTimer){
+    gettimeofday(&inTimer->start, NULL);
+}
+
+/**
+ * @brief monitoring function (init end)
+ */
+void tac(Timer* inTimer){
+    gettimeofday(&inTimer->end, NULL);
+}
+
+/**
+ * @brief monitoring function (return elapsed time in micro second)
+ */
+long int get_elapsed(Timer* inTimer){
+    return ((inTimer->end.tv_sec * 1000000 + inTimer->end.tv_usec)
+            - (inTimer->start.tv_sec * 1000000 + inTimer->start.tv_usec));
+}
+
+/**
+ * @brief monitoring function (print elapsed)
+ */
+void print_elapsed(Timer* inTimer){
+    long int elapsed = get_elapsed(inTimer);
+    printf("Elapsed : %ld us (or %f seconds)\n",elapsed,elapsed/1000000.0);
+}
+
+/**
+ * @brief monitoring function (print difference :: First-Second)
+ */
+void print_difference_elapsed(Timer* inTimer1,Timer*inTimer2){
+    long int diff = get_elapsed(inTimer1)-get_elapsed(inTimer2);
+    printf("Timer Difference : %ld us (or %f seconds)\n",diff,(double)diff/1000000.0);
+}
+
+#endif
diff --git a/Addons/CKernelApi/Tests/testChebInterface.c b/Addons/CKernelApi/Tests/testChebInterface.c
index 0026a20a4..1198b37cc 100644
--- a/Addons/CKernelApi/Tests/testChebInterface.c
+++ b/Addons/CKernelApi/Tests/testChebInterface.c
@@ -4,8 +4,7 @@
 #include <math.h>
 
 //For timing monitoring
-#include <time.h>
-#include <sys/time.h>
+#include "Timers.h"
 
 #include "../Src/CScalfmmApi.h"
 
@@ -60,52 +59,6 @@ void cheb_resetCell(int level, long long morton_index, int* tree_position, doubl
 }
 
 
-/**
- * @brief Wrapper on timeval struct
- */
-typedef struct timer{
-    struct timeval start;
-    struct timeval end;
-}Timer;
-
-/**
- * @brief monitoring function (init start)
- */
-void tic(Timer* inTimer){
-    gettimeofday(&inTimer->start, NULL);
-}
-
-/**
- * @brief monitoring function (init end)
- */
-void tac(Timer* inTimer){
-    gettimeofday(&inTimer->end, NULL);
-}
-
-/**
- * @brief monitoring function (return elapsed time in micro second)
- */
-long int get_elapsed(Timer* inTimer){
-    return ((inTimer->end.tv_sec * 1000000 + inTimer->end.tv_usec)
-            - (inTimer->start.tv_sec * 1000000 + inTimer->start.tv_usec));
-}
-
-/**
- * @brief monitoring function (print elapsed)
- */
-void print_elapsed(Timer* inTimer){
-    long int elapsed = get_elapsed(inTimer);
-    printf("Elapsed : %ld us (or %f seconds)\n",elapsed,elapsed/1000000.0);
-}
-
-/**
- * @brief monitoring function (print difference :: First-Second)
- */
-void print_difference_elapsed(Timer* inTimer1,Timer*inTimer2){
-    long int diff = get_elapsed(inTimer1)-get_elapsed(inTimer2);
-    printf("Timer Difference : %ld us (or %f seconds)\n",diff,(double)diff/1000000.0);
-}
-
 
 /**
  * @brief Do everything
@@ -253,7 +206,7 @@ int main(int argc, char ** av){
 
     //Set timers
     Timer interface_timer,ref_timer;
-    int ite=0, max_ite=5;
+    int ite=0, max_ite=1;
     while(ite<max_ite){
         //Execute FMM
         tic(&interface_timer);
diff --git a/Addons/CKernelApi/Tests/testSphereElectro.c b/Addons/CKernelApi/Tests/testSphereElectro.c
index 973c4ecc6..2ebb5c1bd 100644
--- a/Addons/CKernelApi/Tests/testSphereElectro.c
+++ b/Addons/CKernelApi/Tests/testSphereElectro.c
@@ -7,8 +7,7 @@
 
 
 //For timing monitoring
-#include <time.h>
-#include <sys/time.h>
+#include "Timers.h"
 
 #include "../Src/CScalfmmApi.h"
 
@@ -79,10 +78,10 @@ void getNormal(double * positions, double * normeToFill){
     for(i=0 ; i<3 ; ++i){
         normeToFill[i] = positions[i]/norme;
     }
-    printf("Tgt Norme %e - %e - %e\n",
-           normeToFill[0],
-           normeToFill[1],
-           normeToFill[2]);
+    /* printf("Tgt Norme %e - %e - %e\n", */
+    /*        normeToFill[0], */
+    /*        normeToFill[1], */
+    /*        normeToFill[2]); */
 }
 
 void computeNormalXForces(int nbPoints, double * forcesToRead, double * positionsToRead, double * arrayToFill){
@@ -98,15 +97,17 @@ void computeNormalXForces(int nbPoints, double * forcesToRead, double * position
 }
 
 int main(int argc, char ** av){
-    printf("Start\n");
-    if(argc<2){
-        printf("Use : %s nb_part(cible) (optionnal : TreeHeight) \nexiting\n",av[0]);
+    omp_set_num_threads(4);
+    printf("Start %s nb_targets nb_sources \n",av[0]);
+    if(argc<3){
+        printf("Use : %s nb_part(cible) nb_part(source) (optionnal : TreeHeight) \nexiting\n",av[0]);
         exit(0);
     }
     int nbPartTarget= atoi(av[1]);
     int treeHeight = 5 ;
-    if(argc>2){
-        int treeHeight = atoi(av[2]);
+    if(argc>3){
+        int treeHeight = atoi(av[3]);
+        printf("Tree Heigth Input %d\n",treeHeight );
     }
 
     double boxWidth = 2.0;
@@ -122,13 +123,14 @@ int main(int argc, char ** av){
     memset(targetsPhiValues,0,sizeof(double)*nbPartTarget);
     //Fill
     for(i=0 ; i<nbPartTarget ; ++i){
-        targetsPhiValues[i] = -1.0;
+        targetsPhiValues[i] = 1.0;
     }
+
     generateSurfacePoints(1.0,boxCenter,nbPartTarget,targetsXYZ);
-    printf("Surface points generated \n");
+    printf("%d Surface points generated : Targets\n",nbPartTarget);
 
     //Allocation of the sources points
-    int nbPartSource = 10;
+    int nbPartSource = atoi(av[2]);
     double * sourceXYZ = malloc(sizeof(double)* 3*nbPartSource);
     double * sourcePhiValues = malloc(sizeof(double)* nbPartSource);
     //Set to Zero
@@ -138,14 +140,18 @@ int main(int argc, char ** av){
     for(i=0 ; i<nbPartSource ; ++i){
         sourcePhiValues[i] = 1.0;
     }
+
     generateInsidePoints(1.0,boxCenter,nbPartSource,sourceXYZ);
     //displayPoints(nbPartTarget,targetsXYZ);
 
-    printf("Inside points generated \n");
+    printf("%d Inside points generated :  Sources\n",nbPartSource);
+
     //displayPoints(nbPartSource,sourceXYZ);
     //Creation of arrays to store forces
-    double * arrayOfForces = malloc(sizeof(double )* 3 * (nbPartSource+nbPartTarget));
+    double * arrayOfForces = malloc(sizeof(double )* 3 * nbPartTarget);
+    double * arrayOfPot    = malloc(sizeof(double ) * (nbPartTarget));
     memset(arrayOfForces,0,sizeof(double)* 3 * (nbPartTarget));
+    memset(arrayOfPot,0,sizeof(double)* (nbPartTarget));
 
     {//Start of computation
 
@@ -157,7 +163,7 @@ int main(int argc, char ** av){
         user_descr.user_init_cell = NULL;
         user_descr.user_free_cell = NULL;
         //Set algorithm to source target
-        //scalfmm_algorithm_config(handle,source_target);
+        scalfmm_algorithm_config(handle,source_target);
         //Build the tree
         scalfmm_build_tree(handle,treeHeight, boxWidth, boxCenter, user_descr);
 
@@ -166,9 +172,8 @@ int main(int argc, char ** av){
         printf("Sources inserted \n");
         scalfmm_tree_insert_particles_xyz(handle,nbPartTarget,targetsXYZ,TARGET);
         printf("Targets inserted \n");
-        //Since we inserted first the sources, then sources will get
-        //indices from 0 to (nbPartSource-1), and targets from
-        //(nbPartSource) to nbPartSource+nbPartTarget-1).
+
+        //        scalfmm_print_everything(handle);
 
         int * arrayofIndicesSource = malloc(sizeof(int)*nbPartSource);
         int * arrayofIndicesTarget = malloc(sizeof(int)*nbPartTarget);
@@ -189,15 +194,25 @@ int main(int argc, char ** av){
 
 
         }
+        Timer fmm_timer;
+        tic(&fmm_timer);
         //Computation
         scalfmm_execute_fmm(handle/*, kernel, &my_data*/);
+        tac(&fmm_timer);
+        print_elapsed(&fmm_timer);
 
         //Get back the forces
         scalfmm_get_forces_xyz(handle,nbPartTarget,arrayOfForces,TARGET);
-        scalfmm_get_forces_xyz(handle,nbPartSource,&arrayOfForces[nbPartTarget],SOURCE);
+        //Get back the potentials, too
+        scalfmm_get_potentials(handle,nbPartTarget,arrayOfPot,TARGET);
+
+        //No need to get Source forces, since it will be 0 anyway
+        //scalfmm_get_forces_xyz(handle,nbPartSource,&arrayOfForces[nbPartTarget],SOURCE);
+
         printf("Forces computed : \n");
-        displayPoints(nbPartTarget+nbPartSource,arrayOfForces);
-        printf("As expected, Source forces are 0\n \n");
+        //Display array of forces ::
+        //displayPoints(nbPartTarget+nbPartSource,arrayOfForces);
+
         //Release memory used :
         free(arrayofIndicesSource);
         free(arrayofIndicesTarget);
@@ -207,19 +222,24 @@ int main(int argc, char ** av){
     }
 
     {//Let's check the result, we computed fr each target part its forces
-        //Storage of reference forces
+        //Storage of reference forces + potential
         double * arrayRefForces = malloc(sizeof(double)*nbPartTarget*3);
         memset(arrayRefForces,0,sizeof(double)*nbPartTarget*3);
+        double * arrayOfRefPot = malloc(sizeof(double)*nbPartTarget);
+        memset(arrayOfRefPot,0,sizeof(double)*nbPartTarget);
 
         int idTgt;
+        Timer check_timer;
+        tic(&check_timer);
         for(idTgt = 0 ; idTgt<nbPartTarget ; ++idTgt){
             int idSrc;
             double dx,dy,dz;
-            for(idSrc = 0 ; idSrc<nbPartTarget ; ++idSrc){
+
+            for(idSrc = 0 ; idSrc<nbPartSource ; ++idSrc){
                 //First compute dist.
-                dx = sourceXYZ[idSrc+0] - targetsXYZ[idTgt+0];
-                dy = sourceXYZ[idSrc+1] - targetsXYZ[idTgt+1];
-                dz = sourceXYZ[idSrc+2] - targetsXYZ[idTgt+2];
+                dx = sourceXYZ[idSrc*3+0] - targetsXYZ[idTgt*3+0];
+                dy = sourceXYZ[idSrc*3+1] - targetsXYZ[idTgt*3+1];
+                dz = sourceXYZ[idSrc*3+2] - targetsXYZ[idTgt*3+2];
 
                 //Secondly, compute coeff
                 double coeffs = targetsPhiValues[idTgt] * sourcePhiValues[idSrc];
@@ -229,24 +249,70 @@ int main(int argc, char ** av){
                 arrayRefForces[idTgt*3+0] += dx*coeffs*one_over_r3;
                 arrayRefForces[idTgt*3+1] += dy*coeffs*one_over_r3;
                 arrayRefForces[idTgt*3+2] += dz*coeffs*one_over_r3;
-
+                arrayOfRefPot[idTgt] += one_over_r * sourcePhiValues[idSrc];
             }
         }
+        tac(&check_timer);
+        print_elapsed(&check_timer);
 
         {//Then, we compare
-            double errorCumul = 0;
+
+            //For L2 norm
+            double errorCumulXSquared = 0,
+                errorCumulYSquared = 0,
+                errorCumulZSquared = 0,
+                errorCumulPotSquared = 0;
+            //For Inf Norm
+            double maxErrorX = 0,
+                maxErrorY = 0,
+                maxErrorZ = 0,
+                maxErrorPot = 0;
             int idArr;
             for(idArr = 0 ; idArr<nbPartTarget ; ++idArr){
-                errorCumul += fabs(arrayRefForces[idArr+0]-arrayOfForces[idArr+0]);
-                errorCumul += fabs(arrayRefForces[idArr+1]-arrayOfForces[idArr+1]);
-                errorCumul += fabs(arrayRefForces[idArr+2]-arrayOfForces[idArr+2]);
-                printf("Directly Computed %e %e %e\n",
-                       arrayRefForces[idArr+0],
-                       arrayRefForces[idArr+1],
-                       arrayRefForces[idArr+2]);
+                double deltaX = fabs(arrayRefForces[idArr*3+0]-arrayOfForces[idArr*3+0]);
+                double deltaY = fabs(arrayRefForces[idArr*3+1]-arrayOfForces[idArr*3+1]);
+                double deltaZ = fabs(arrayRefForces[idArr*3+2]-arrayOfForces[idArr*3+2]);
+                double deltaPot = fabs(arrayOfRefPot[idArr]-arrayOfPot[idArr]);
+
+                errorCumulXSquared += deltaX*deltaX;
+                errorCumulYSquared += deltaY*deltaY;
+                errorCumulZSquared += deltaZ*deltaZ;
+                errorCumulPotSquared += deltaPot*deltaPot;
+
+                if(maxErrorX < deltaX){ maxErrorX = deltaX ;}
+                if(maxErrorY < deltaY){ maxErrorY = deltaY ;}
+                if(maxErrorZ < deltaZ){ maxErrorZ = deltaZ ;}
+                if(maxErrorPot < deltaPot) {maxErrorPot = deltaPot;}
             }
-            printf("Error cumul : %e\n",errorCumul);
+            //Last check aim to verify the difference between energy
+            //total directly computed and energy total FMM's computed
+            double energy = 0,energyFmm =0;
+            for(idArr = 0; idArr<nbPartTarget ; ++idArr){
+                energy += arrayOfRefPot[idArr] * targetsPhiValues[idArr];
+                energyFmm += arrayOfPot[idArr] * targetsPhiValues[idArr];
+            }
+
+
+
+            printf("\n \t\t X error \t Y error \t Z error \t Pot error\n");
+            printf("Norme Sup :\t %e \t %e \t %e \t %e\n",maxErrorX,maxErrorY,maxErrorZ,maxErrorPot);
+            printf("Norme L2  :\t %e \t %e \t %e \t %e\n",
+                   sqrt(errorCumulXSquared),
+                   sqrt(errorCumulYSquared),
+                   sqrt(errorCumulZSquared),
+                   sqrt(errorCumulPotSquared));
+            printf("Norme Rms :\t %e \t %e \t %e \t %e\n",
+                   sqrt(errorCumulXSquared/((double) nbPartTarget)),
+                   sqrt(errorCumulYSquared/((double) nbPartTarget)),
+                   sqrt(errorCumulZSquared/((double) nbPartTarget)),
+                   sqrt(errorCumulPotSquared/((double) nbPartTarget)));
+            printf(" \n Energy Error  : \t %e \n Energy FMM   : \t %e \n Energy DIRECT : \t %e\n",
+                   fabs(energy-energyFmm),
+                   energyFmm,
+                   energy);
         }
+        free(arrayRefForces);
+        free(arrayOfRefPot);
     }
 
 
@@ -260,14 +326,18 @@ int main(int argc, char ** av){
 
     computeNormalXForces(nbPartTarget,targetsForces,targetsXYZ,normeXForces);
     printf("For each target, we display [Normal To Sphere] . [Force product] \n");
-    displayArray(nbPartTarget,normeXForces);
+    //displayArray(nbPartTarget,normeXForces);
 
 
     //Free memory
+    free(normeXForces);
+    free(targetsForces);
     free(sourceXYZ);
     free(sourcePhiValues);
     free(targetsXYZ);
     free(targetsPhiValues);
     free(arrayOfForces);
+    free(arrayOfPot);
+
     return EXIT_SUCCESS;
 }
-- 
GitLab