diff --git a/Src/Kernels/Rotation/FRotationKernel.hpp b/Src/Kernels/Rotation/FRotationKernel.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0894f8a7e38114d83f27d115736e91d28a8a75aa
--- /dev/null
+++ b/Src/Kernels/Rotation/FRotationKernel.hpp
@@ -0,0 +1,820 @@
+// ===================================================================================
+// Logiciel initial: ScalFmm Version 0.5
+// Co-auteurs : Olivier Coulaud, Bérenger Bramas.
+// Propriétaires : INRIA.
+// Copyright © 2011-2012, diffusé sous les termes et conditions d’une licence propriétaire.
+// Initial software: ScalFmm Version 0.5
+// Co-authors: Olivier Coulaud, Bérenger Bramas.
+// Owners: INRIA.
+// Copyright © 2011-2012, spread under the terms and conditions of a proprietary license.
+// ===================================================================================
+#ifndef FROTATIONKERNEL_HPP
+#define FROTATIONKERNEL_HPP
+
+#include "../../Components/FAbstractSerializable.hpp"
+#include "../../Components/FAbstractSendable.hpp"
+#include "../../Utils/FComplexe.hpp"
+#include "../../Utils/FMemUtils.hpp"
+
+#include "../../Extensions/FExtendCellType.hpp"
+
+#include "../../Components/FBasicCell.hpp"
+
+#include "../../Containers/FBufferWriter.hpp"
+#include "../../Containers/FBufferReader.hpp"
+
+template <int P>
+class FRotationCell : public FBasicCell {
+protected:
+    static const int MultipoleSize = ((P+2)*(P+1))/2; // Artimethique suite (n+1)*n/2
+    static const int LocalSize = ((P+2)*(P+1))/2;     // Artimethique suite (n+1)*n/2
+
+    FComplexe multipole_exp[MultipoleSize]; //< For multipole extenssion
+    FComplexe local_exp[LocalSize];         //< For local extenssion
+
+public:
+    static int GetLocalSize(){
+        return LocalSize;
+    }
+
+    static int GetPoleSize(){
+        return MultipoleSize;
+    }
+
+    /** Default constructor */
+    FRotationCell(){
+    }
+
+    /** Constructor */
+    FRotationCell(const FRotationCell& other){
+        (*this) = other;
+    }
+
+    /** Default destructor */
+    virtual ~FRotationCell(){
+    }
+
+    /** Copy constructor */
+    FRotationCell& operator=(const FRotationCell& other) {
+        FMemUtils::copyall(multipole_exp, other.multipole_exp, MultipoleSize);
+        FMemUtils::copyall(local_exp, other.local_exp, LocalSize);
+        return *this;
+    }
+
+    /** Get Multipole */
+    const FComplexe* getMultipole() const {
+        return multipole_exp;
+    }
+    /** Get Local */
+    const FComplexe* getLocal() const {
+        return local_exp;
+    }
+
+    /** Get Multipole */
+    FComplexe* getMultipole() {
+        return multipole_exp;
+    }
+    /** Get Local */
+    FComplexe* getLocal() {
+        return local_exp;
+    }
+
+    ///////////////////////////////////////////////////////
+    // to extend FAbstractSendable
+    ///////////////////////////////////////////////////////
+    void serializeUp(FBufferWriter& buffer) const{
+        buffer.write(multipole_exp, MultipoleSize);
+    }
+    void deserializeUp(FBufferReader& buffer){
+        buffer.fillArray(multipole_exp, MultipoleSize);
+    }
+
+    void serializeDown(FBufferWriter& buffer) const{
+        buffer.write(local_exp, LocalSize);
+    }
+    void deserializeDown(FBufferReader& buffer){
+        buffer.fillArray(local_exp, LocalSize);
+    }
+
+    ///////////////////////////////////////////////////////
+    // to extend Serializable
+    ///////////////////////////////////////////////////////
+    void save(FBufferWriter& buffer) const{
+        FBasicCell::save(buffer);
+        buffer.write(multipole_exp, MultipoleSize);
+        buffer.write(local_exp, LocalSize);
+    }
+    void restore(FBufferReader& buffer){
+        FBasicCell::restore(buffer);
+        buffer.fillArray(multipole_exp, MultipoleSize);
+        buffer.fillArray(local_exp, LocalSize);
+    }
+};
+
+
+
+#include "../../Components/FAbstractKernels.hpp"
+#include "../../Utils/FSmartPointer.hpp"
+#include "../../Utils/FComplexe.hpp"
+#include "../../Utils/FSpherical.hpp"
+
+/**
+* @author Berenger Bramas (berenger.bramas@inria.fr)
+* @class FRotationKernel
+* @brief
+*
+* This kernels is empty for now and does nothing.
+*/
+template< class ParticleClass, class CellClass, class ContainerClass, int P>
+class FRotationKernel : public FAbstractKernels<ParticleClass,CellClass,ContainerClass> {    
+    static const int SizeArray = ((P+2)*(P+1))/2;
+
+    /** Return position in the array of the l/m couple */
+    int atLm(const int l, const int m){
+        // summation series over l + m => (l*(l+1))/2 + m
+        return ((l*(l+1))>>1) + m;
+    }
+
+    template < class T >
+    T Sgn(const T a){
+        if(a < 0) return T(-1);
+        else if(a > 0) return T(1);
+        return T(0);
+    }
+
+    template < class T >
+    T fact(const T a){
+        if(a<0) printf("Error factorial negative!! a=%d\n",a);
+        int result = 1;
+        for(int i = 1; i<= a ; ++i){
+            result *= i;
+        }
+        return T(result);
+    }
+
+    template < class T >
+    FReal combin(const T& a, const T& b){
+        if(a-b<0) printf("Error combi negative!! a=%d b=%d\n",a,b);
+        return FReal(fact(a)) / FReal(fact(b)*fact(a-b));
+    }
+
+    int Min(const int a , const int b){
+        return (a<b?a:b);
+    }
+
+    int Max(const int a , const int b){
+        return (a>b?a:b);
+    }
+
+    double analytical(const double cosTheta, const double sinTheta, const int l , const int m, const int k){
+        if( l >= 0 && -l <= k && k <= l && FMath::Abs(k) <= m && m <= l ){
+            FReal sum = 0;
+            for(int n = Max(-(m+k),0) ; n <= Min(l-m,l-k) ; ++n){
+                sum += FMath::pow(-1.0, l-m-n) * combin(l-k, n) * combin(l+k, l-m-n) * FMath::pow(1.0+cosTheta,n) * FMath::pow(1.0-cosTheta, l-m-n);
+            }
+            return (1.0/FMath::pow(2.0,l)) * FMath::Sqrt(FReal(fact(l-m)*fact(l+m))/FReal(fact(l-k)*fact(l+k)))
+                    * FMath::pow(1.0 + Sgn(k)*cosTheta, FMath::Abs(k)) * FMath::pow(sinTheta, m - FMath::Abs(k)) * sum;
+        }
+        else if( (l > 0 && -l <= m && m < 0 && FMath::Abs(m) <= k && k <= l)
+                 ||  (l > 0 && 0 <= m && m < l && m < k && k <= l )) {
+            return FMath::pow(-1.0, m+k) * analytical(cosTheta,sinTheta, l, k ,m);
+        }
+        else if( l > 0 && -l <= m && m < l && -l <= k && k < -m ){
+            return FMath::pow(-1.0, m+k) * analytical(cosTheta,sinTheta, l, -m, -k);
+        }
+        else{
+            return -999999.99999;
+        }
+    }
+
+
+
+    /** @todo use pointer */
+    void computeLegendre(FReal legendre[], const FReal inCosTheta, const FReal inSinTheta){
+        const FReal invSinTheta = inSinTheta;
+        legendre[atLm(0,0)] = 1.0;        // P_0,0(1) = 1
+
+        legendre[atLm(1,0)] = inCosTheta;
+        legendre[atLm(1,1)] = invSinTheta;
+
+        for(int l = 2; l <= P ; ++l ){
+            for( int m = 0; m < l - 1 ; ++m ){
+                legendre[atLm(l,m)] = (FReal(2*l-1) * inCosTheta * legendre[atLm(l-1,m)] - FReal( l + m - 1 ) * legendre[atLm(l-2,m)] )
+                                                                    / FReal( l - m );
+            }
+            legendre[atLm(l,l-1)] = FReal(2*l-1) * inCosTheta * legendre[atLm(l-1,l-1)];
+            legendre[atLm(l,l)] = FReal(2*l-1) * invSinTheta * legendre[atLm(l-1,l-1)];
+        }
+    }
+
+
+    FPoint getLeafCenter(const FTreeCoordinate coordinate) const {
+        return FPoint(
+                    FReal(coordinate.getX()) * widthAtLeafLevel + widthAtLeafLevelDiv2 + boxCorner.getX(),
+                    FReal(coordinate.getY()) * widthAtLeafLevel + widthAtLeafLevelDiv2 + boxCorner.getY(),
+                    FReal(coordinate.getZ()) * widthAtLeafLevel + widthAtLeafLevelDiv2 + boxCorner.getZ());
+    }
+
+    void rotateMultipoleFull(FComplexe vec[], const FReal theta, const FReal phi){
+        FComplexe cell_rotate[SizeArray];
+        for(int l = 0 ; l <= P ; ++l){
+            for(int m = 0 ; m <= l ; ++m ){
+                for(int k = -l ; k < 0 ; ++k){
+                    // Equ 25
+                    // Y{l,m} = SUM D{l,m,k} Y{l,k}
+                    // z = p exp(i*O) = p(cos(O) + i sin(O))
+                    const FReal factor = FMath::pow(-1,-k) * FMath::Sqrt(FReal(fact(l-k)*fact(l+k))/FReal(fact(l-m)*fact(l+m)));
+                    const FReal d_lmk = analytical(FMath::Cos(theta),
+                                                   FMath::Sin(theta),l,m,k);
+                    const FReal minus_k = FReal(-k);
+                    const FComplexe Dlmk(factor * d_lmk * FMath::Cos(phi * minus_k),
+                                         factor * d_lmk * FMath::Sin(phi * minus_k));
+                    cell_rotate[atLm(l,m)].addMul( Dlmk , vec[atLm(l,-k)].conjugate());
+                }
+                for(int k = 0 ; k <= l ; ++k){
+                    // Equ 25
+                    // Y{l,m} = SUM D{l,m,k} Y{l,k}
+                    // z = p exp(i*O) = p(cos(O) + i sin(O))
+                    const FReal factor = FMath::Sqrt(FReal(fact(l-k)*fact(l+k))/FReal(fact(l-m)*fact(l+m)));
+                    const FReal d_lmk = analytical(FMath::Cos(theta),
+                                                   FMath::Sin(theta),l,m,k);
+                    const FReal minus_k = FReal(-k);
+                    const FComplexe Dlmk(factor * d_lmk * FMath::Cos(phi * minus_k),
+                                         factor * d_lmk * FMath::Sin(phi * minus_k));
+                    cell_rotate[atLm(l,m)].addMul( Dlmk , vec[atLm(l,k)]);
+                }
+            }
+        }
+        FMemUtils::copyall(vec,cell_rotate,SizeArray);
+    }
+
+    void rotateMultipolePhi(FComplexe vec[], const FReal phi){
+        FComplexe cell_rotate[SizeArray];
+        for(int l = 0 ; l <= P ; ++l){
+            for(int m = 0 ; m <= l ; ++m ){
+                const FReal k = FReal(m);
+                const FComplexe exp_ikphi(FMath::Cos(phi * k), FMath::Sin(phi * k));
+                cell_rotate[atLm(l,m)].equalMul(exp_ikphi , vec[atLm(l,m)]);
+            }
+        }
+        FMemUtils::copyall(vec,cell_rotate,SizeArray);
+    }
+
+    void rotateTaylorPhi(FComplexe vec[], const FReal phi){
+        FComplexe cell_rotate[SizeArray];
+        for(int l = 0 ; l <= P ; ++l){
+            for(int m = 0 ; m <= l ; ++m ){
+                const FReal k = FReal(m);
+                const FComplexe exp_ikphi(FMath::Cos(phi * k), FMath::Sin(phi * k));
+                cell_rotate[atLm(l,m)].equalMul(exp_ikphi , vec[atLm(l,m)]);
+            }
+        }
+        FMemUtils::copyall(vec,cell_rotate,SizeArray);
+    }
+
+    void rotateMultipoleTheta(FComplexe vec[], const FReal theta){
+        FComplexe cell_rotate[SizeArray];
+        for(int l = 0 ; l <= P ; ++l){
+            for(int m = 0 ; m <= l ; ++m ){
+                FReal w_lkm_real = 0.0;
+                FReal w_lkm_imag = 0.0;
+
+                for(int k = -l ; k < 0 ; ++k){
+                    const FReal d_lmk = analytical(FMath::Cos(theta),FMath::Sin(theta),l,m,k);
+                    w_lkm_real += FMath::pow(-1,-k) * d_lmk * vec[atLm(l,-k)].getReal(); // k<0 => Conjugate * -1^k
+                    w_lkm_imag -= FMath::pow(-1,-k) * d_lmk * vec[atLm(l,-k)].getImag(); // k<0 => Conjugate * -1^k
+                    //printf("l%d m%d k%d, dlkm = %f, vec = %f\n", l,m,k,d_lmk,vec[atLm(l,-k)].getReal());
+                }
+                for(int k = 0 ; k <= l ; ++k){
+                    const FReal d_lmk = analytical(FMath::Cos(theta),FMath::Sin(theta),l,m,k);
+                    w_lkm_real += d_lmk * vec[atLm(l,k)].getReal();
+                    w_lkm_imag += d_lmk * vec[atLm(l,k)].getImag();
+                    //printf("l%d m%d k%d, dlkm = %f, vec = %f\n", l,m,k,d_lmk,vec[atLm(l,k)].getReal());
+                }
+                //printf("l%d m%d res = %f\n", l,m,w_lkm_real);
+                cell_rotate[atLm(l,m)].setRealImag(w_lkm_real, w_lkm_imag);
+            }
+        }
+        FMemUtils::copyall(vec,cell_rotate,SizeArray);
+    }
+
+    void rotateMultipole(FComplexe vec[], FReal theta, FReal phi){
+        rotateMultipolePhi(vec,phi);
+        rotateMultipoleTheta(vec,theta);
+    }
+    void deRotateMultipole(FComplexe vec[], const FReal theta, const FReal phi){
+        rotateMultipoleTheta(vec,-theta);
+        rotateMultipolePhi(vec,-phi);
+    }
+
+    void rotateTaylor(FComplexe vec[], const FReal theta, const FReal phi){
+        rotateTaylorPhi(vec,phi);
+        rotateMultipoleTheta(vec,theta);
+    }
+    void deRotateTaylor(FComplexe vec[], const FReal theta, const FReal phi){
+        rotateMultipoleTheta(vec,FMath::FPi*2 - theta);
+        rotateTaylorPhi(vec,FMath::FPi*2 - phi);
+    }
+
+    /*void rotateTaylor(FComplexe vec[], const FReal theta, const FReal phi){
+        FComplexe cell_rotate[SizeArray];
+        for(int l = 0 ; l <= P ; ++l){
+            for(int m = 0 ; m <= l ; ++m ){
+                for(int k = -l ; k < 0 ; ++k){
+                    // Equ 25
+                    // Y{l,m} = SUM D{l,m,k} Y{l,k}
+                    // z = p exp(i*O) = p(cos(O) + i sin(O))
+                    const FReal d_lmk = analytical(FMath::Cos(theta),FMath::Sin(theta),l,m,k);
+                    const FReal factor = FMath::Sqrt( FReal(fact(l-m)*fact(l+m)) / FReal(fact(l-k)*fact(l+k)) );
+                    const FComplexe Dlmk( factor * d_lmk * FMath::Cos(phi * FReal(k)),
+                                          factor * d_lmk * FMath::Sin(phi * FReal(k)));
+                    cell_rotate[atLm(l,m)].addMul( Dlmk , vec[atLm(l,-k)].conjugate() );
+                }
+                for(int k = 0 ; k <= l ; ++k){
+                    // Equ 25
+                    // Y{l,m} = SUM D{l,m,k} Y{l,k}
+                    // z = p exp(i*O) = p(cos(O) + i sin(O))
+                    const FReal d_lmk = analytical(FMath::Cos(theta),FMath::Sin(theta),l,m,k);
+                    const FReal factor = FMath::Sqrt( FReal(fact(l-m)*fact(l+m)) / FReal(fact(l-k)*fact(l+k)) );
+                    const FComplexe Dlmk( factor * d_lmk * FMath::Cos(phi * FReal(k)),
+                                          factor * d_lmk * FMath::Sin(phi * FReal(k)));
+                    cell_rotate[atLm(l,m)].addMul( Dlmk , vec[atLm(l,k)] );
+                }
+            }
+        }
+        FMemUtils::copyall(vec,cell_rotate,SizeArray);
+    }*/
+
+    const FReal boxWidth;       //< the box width at leaf level
+    const int   treeHeight;     //< The height of the tree
+    const FReal widthAtLeafLevel;
+    const FReal widthAtLeafLevelDiv2;
+    const FPoint boxCorner;
+
+    FSmartPointer<FSpherical> childrenPosition;
+    FSmartPointer<FSpherical> interactionsPosition;
+
+    void preComputePosition(){
+        childrenPosition = new FSpherical[8 * (treeHeight-1)];
+        {
+            FReal subBoxWidth = widthAtLeafLevelDiv2;
+            // For each
+            for(int idxLevel = treeHeight-2 ; idxLevel > 0 ; --idxLevel){
+                for(int idxChild = 0 ; idxChild < 8 ; ++idxChild ){
+                    // coord from child to parent
+                    const FReal x = FReal((idxChild&4)? -1.0 : 1.0) * subBoxWidth;
+                    const FReal y = FReal((idxChild&2)? -1.0 : 1.0) * subBoxWidth;
+                    const FReal z = FReal((idxChild&1)? -1.0 : 1.0) * subBoxWidth;
+                    const FPoint relativePosition( x , y , z );
+
+                    childrenPosition[(idxLevel-1)*8 + idxChild] = FSpherical(relativePosition);
+
+                    /*printf("Level %d, child %d (%f,%f,%f), theta %f phi %f \n",
+                           idxLevel, idxChild, x, y, z, childrenPosition[(idxLevel-1)*8 + idxChild].getTheta(),
+                           childrenPosition[(idxLevel-1)*8 + idxChild].getPhi());*/
+                }
+                subBoxWidth *= FReal(2.0);
+            }
+        }
+
+        interactionsPosition = new FSpherical[343 * (treeHeight-1)];
+        {
+            FReal boxWidthAtLevel = widthAtLeafLevel;
+            for(int idxLevel = treeHeight-1 ; idxLevel > 0 ; --idxLevel){
+                for(int idxX = -3 ; idxX <= 3 ; ++idxX ){
+                    for(int idxY = -3 ; idxY <= 3 ; ++idxY ){
+                        for(int idxZ = -3 ; idxZ <= 3 ; ++idxZ ){
+                            if( idxX || idxY || idxZ ){
+                                const FPoint relativePosition( -FReal(idxX)*boxWidthAtLevel, -FReal(idxY)*boxWidthAtLevel, -FReal(idxZ)*boxWidthAtLevel);
+                                const int position = ((( (idxX+3) * 7) + (idxY+3))) * 7 + idxZ + 3;
+                                interactionsPosition[(idxLevel-1)*343 + position] = FSpherical(relativePosition);
+                            }
+                        }
+                    }
+                }
+                boxWidthAtLevel *= FReal(2.0);
+            }
+        }
+    }
+
+    FSpherical getSphericalChild(const int idxLevel, const int position) const {
+        return childrenPosition[(idxLevel-1)*8 + position];
+    }
+
+    FSpherical getSphericalInteraction(const int idxLevel, const int position) const {
+        return interactionsPosition[(idxLevel-1)*343 + position];
+    }
+
+public:
+
+
+    FRotationKernel(const int inDevP, const int inTreeHeight, const FReal inBoxWidth, const FPoint& inBoxCenter) :
+        boxWidth(inBoxWidth),
+        treeHeight(inTreeHeight),
+        widthAtLeafLevel(inBoxWidth/FReal(1 << (inTreeHeight-1))),
+        widthAtLeafLevelDiv2(widthAtLeafLevel/2),
+        boxCorner(inBoxCenter.getX()-(inBoxWidth/2),inBoxCenter.getY()-(inBoxWidth/2),inBoxCenter.getZ()-(inBoxWidth/2))
+        {
+
+        preComputePosition();
+    }
+
+    /** Default destructor */
+    virtual ~FRotationKernel(){
+    }
+
+    /** P2M
+      * From equation 10, fmmparadix.pdf
+      */
+    void P2M(CellClass* const inPole, const ContainerClass* const inParticles ) {
+        //kernel.P2M(inPole, inParticles);
+
+        // w is the multipole moment
+        FComplexe* FRestrict const w = inPole->getMultipole();
+
+        // Copying the position is faster than using cell position
+        const FPoint cellPosition = getLeafCenter(inPole->getCoordinate());
+
+        // We need a legendre array
+        FReal legendre[SizeArray];
+
+        // For all particles in the leaf box
+        typename ContainerClass::ConstBasicIterator iterParticle(*inParticles);
+        while( iterParticle.hasNotFinished()){
+            // P2M
+            const ParticleClass& particle = iterParticle.data();
+            const FSpherical sph(particle.getPosition() - cellPosition);
+
+            // The physical value (charge, mass)
+            const FReal q = particle.getPhysicalValue();
+            // The distance between the SH and the particle
+            const FReal a = sph.getR();
+
+            // Compute the legendre polynomial
+            computeLegendre(legendre, sph.getCosTheta(), sph.getSinTheta());
+
+            // w{l,m} = q a^l/(l+|m|)! P{l,m} exp(-i m Betha)
+            for(int l = 0 ; l <= P ; ++l ){
+                for(int m = 0 ; m <= l ; ++m ){
+                    const FReal magnitude = q * (FMath::pow( a , l )/fact(l+m))
+                            * legendre[atLm(l,m)];
+                    w[atLm(l,m)].setReal(magnitude * FMath::Cos(FReal(-m) * sph.getPhi()));
+                    w[atLm(l,m)].setImag(magnitude * FMath::Sin(FReal(-m) * sph.getPhi()));
+                }
+            }
+            // Goto next particle
+            iterParticle.gotoNext();
+        }
+    }
+
+    /** M2M
+      * Equation 29, from fmm paradix
+      */
+    void M2M(CellClass* const FRestrict inPole, const CellClass*const FRestrict *const FRestrict inChildren, const int inLevel) {
+        // A buffer to copy the source w
+        FComplexe source_w[SizeArray];
+        for(int idxChild = 0 ; idxChild < 8 ; ++idxChild){
+            // if child exists
+            if(inChildren[idxChild]){
+                // Copy the source
+                FMemUtils::copyall(source_w, inChildren[idxChild]->getMultipole(), SizeArray);
+                //delete me
+                printf("----------------- child %d \n", idxChild);
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("0 - [%d][%d] %f i%f\t", l, m, source_w[atLm(l,m)].getReal(), source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                //end delete me
+                // rotate it
+                const FSpherical sph = getSphericalChild(inLevel, idxChild);
+                rotateMultipole(source_w, sph.getTheta(), sph.getPhi());
+                const FReal b = -sph.getR();
+
+                //delete me
+                printf("b %f , theta %f, Phi %f \n", b,  sph.getTheta(), sph.getPhi());
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("1 - [%d][%d] %f i%f\t", l, m, source_w[atLm(l,m)].getReal(), source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                //end delete me
+
+                // Translate it
+                FComplexe target_w[SizeArray];
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        // w{l,m}(a+b) = sum(j=m:l, b^(l-j)/(l-j)! w{j,m}(a)
+                        FReal w_lm_real = 0.0;
+                        FReal w_lm_imag = 0.0;
+                        printf("T %d %d >> ", l , m);
+                        for(int j = m ; j <= l ; ++j ){
+                            const FReal coef = (FMath::pow(b,l-j) / FReal(fact(l-j)));
+                            w_lm_real += coef * source_w[atLm(j,m)].getReal();
+                            w_lm_imag += coef * source_w[atLm(j,m)].getImag();
+                            printf(" \t use : %d %d (l-j %d) coef %f at %d, ",j,m,l-j, coef, atLm(j,m));
+                        }
+                        printf("\n");
+                        target_w[atLm(l,m)].setRealImag(w_lm_real,w_lm_imag);
+                    }
+                }
+
+                //delete me
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("2 - [%d][%d] %f i%f\t", l, m, target_w[atLm(l,m)].getReal(), target_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                //end delete me
+
+                // Rotate it back
+                deRotateMultipole(target_w, sph.getTheta(),sph.getPhi());
+                //delete me
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("3 - [%d][%d] %f i%f\t", l, m, target_w[atLm(l,m)].getReal(), target_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                //end delete me
+                // Sum the result
+                FMemUtils::addall( inPole->getMultipole(), target_w, SizeArray);
+
+            }
+        }
+    }
+
+    /** M2L
+      * Equation 33, from fmmparadix.pdf
+      */
+    void M2L(CellClass* const FRestrict inLocal, const CellClass* inInteractions[], const int /*inSize*/, const int inLevel) {
+        // To copy the multipole data
+        FComplexe source_w[SizeArray];
+        for(int idxNeigh = 0 ; idxNeigh < 343 ; ++idxNeigh){
+            // if interaction exits
+            if(inInteractions[idxNeigh]){
+                // Copy multipole data into buffer
+                FMemUtils::copyall(source_w, inInteractions[idxNeigh]->getMultipole(), SizeArray);
+
+                // delete me
+                source_w[atLm(0,0)].setReal(0.1);
+                source_w[atLm(0,0)].setImag(0.0);
+                source_w[atLm(1,0)].setReal(0.025);
+                source_w[atLm(1,0)].setImag(0.0);
+                source_w[atLm(1,1)].setReal(0.001250);
+                source_w[atLm(1,1)].setImag(-0.001250);
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("0 - [%d][%d] %f %f\t", l, m, source_w[atLm(l,m)].getReal(), source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                // end delete me
+
+                // Rotate
+                const FSpherical sph = getSphericalInteraction(inLevel, idxNeigh);
+                rotateMultipole(source_w, sph.getTheta(), sph.getPhi());
+                //DELETE ME =======================================
+                printf("After a rotation of theta %f phi %f \n", sph.getTheta(), sph.getPhi());
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("1 - [%d][%d] %f %f\t", l, m, source_w[atLm(l,m)].getReal(),
+                               source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+               /* for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        source_w[atLm(l,m)].setRealImag(0.0,0.0);
+                    }
+                }
+                source_w[atLm(0,0)].setReal(1.0);
+                source_w[atLm(0,0)].setImag(0.0);
+                source_w[atLm(1,0)].setReal(3.0);
+                source_w[atLm(1,0)].setImag(0.0);
+                source_w[atLm(1,1)].setReal(5.0);
+                source_w[atLm(1,1)].setImag(6.0);
+                if(P >= 2){
+                    source_w[atLm(2,0)].setReal(7.0);
+                    source_w[atLm(2,0)].setImag(0.0);
+                    source_w[atLm(2,1)].setReal(8.0);
+                    source_w[atLm(2,1)].setImag(9.0);
+                    source_w[atLm(2,2)].setReal(10.0);
+                    source_w[atLm(2,2)].setImag(11.0);
+                }
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("[%d][%d] %f %f\t", l, m, source_w[atLm(l,m)].getReal(), source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                rotateMultipoleFull(source_w, 0, 2);
+                //rotateMultipolePhi(source_w, 2);
+                //rotateMultipoleTheta(source_w, FMath::FPi/2);
+                ///rotateMultipole(source_w, 2.186276, -2.356194);//Phi -2.356194, Betha 2.186276
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("[%d][%d] %f %f\t", l, m, source_w[atLm(l,m)].getReal(), source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                rotateMultipoleFull(source_w,0, -2);
+                //rotateMultipoleTheta(source_w,FMath::FPi*2 - FMath::FPi/2);
+                //rotateMultipolePhi(source_w, -2);
+                ///deRotateMultipole(source_w, 2.186276, -2.356194);
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("[%d][%d] %f %f\t", l, m, source_w[atLm(l,m)].getReal(), source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                } */
+                // end delete me ====================================
+                const FReal b = sph.getR();
+
+                // Transfer to u
+                FComplexe target_u[SizeArray];
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        // u{l,m}(a-b) = sum(j=0:P, (j+l)!/b^(j+l+1) w{j,-m}(a)
+                        FReal u_lm_real = 0.0;
+                        FReal u_lm_imag = 0.0;
+                        for(int j = 0 ; j <= P ; ++j ){
+                            const FReal coef = (fact(j+l)/FMath::pow(b,j+l+1));
+                            // conjugate because {l,-m} => {l,m} with -i
+                            u_lm_real += coef * source_w[atLm(j,m)].getReal();
+                            u_lm_imag -= coef * source_w[atLm(j,m)].getImag();
+                        }
+                        target_u[atLm(l,m)].setRealImag(u_lm_real,u_lm_imag);
+                    }
+                }
+                // delete me
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        printf("2 - [%d][%d] %f %f\t", l, m, source_w[atLm(l,m)].getReal(), source_w[atLm(l,m)].getImag());
+                    }
+                    printf("\n");
+                }
+                // end delete me
+                // Rotate it back
+                deRotateTaylor(target_u, FMath::FPi*2 - sph.getTheta(), FMath::FPi*2 - sph.getPhi());
+                // Sum
+                FMemUtils::addall(inLocal->getLocal(), target_u, SizeArray);
+            }
+        }
+    }
+
+    /** L2L
+      * Equation 37, from fmmparadix.pdf
+      */
+    void L2L(const CellClass* const FRestrict inLocal, CellClass* FRestrict *const FRestrict  inChildren, const int inLevel) {
+        // To copy the source local
+        FComplexe source_u[SizeArray];
+        for(int idxChild = 0 ; idxChild < 8 ; ++idxChild){
+            // if child exists
+            if(inChildren[idxChild]){
+                // Copy the local data into the buffer
+                FMemUtils::copyall(source_u, inLocal->getLocal(), SizeArray);
+                // Rotate
+                const FSpherical sph = getSphericalChild(inLevel, idxChild);
+                rotateTaylor(source_u, FMath::FPi*2 -sph.getTheta(), FMath::FPi*2 - sph.getPhi());
+                const FReal b = sph.getR();
+
+                // Translate
+                FComplexe target_u[SizeArray];
+                for(int l = 0 ; l <= P ; ++l ){
+                    for(int m = 0 ; m <= l ; ++m ){
+                        // u{l,m}(r-b) = sum(j=0:P, b^(j-l)/(j-l)! u{j,m}(r);
+                        FReal u_lm_real = 0.0;
+                        FReal u_lm_imag = 0.0;
+                        for(int j = l ; j <= P ; ++j ){
+                            const FReal coef = (FMath::pow(b,j-l) / fact(j-l));
+                            u_lm_real += coef * source_u[atLm(j,m)].getReal();
+                            u_lm_imag += coef * source_u[atLm(j,m)].getImag();
+                        }
+                        target_u[atLm(l,m)].setRealImag(u_lm_real,u_lm_imag);
+                    }
+                }
+                // Rotate
+                rotateTaylor(target_u, FMath::FPi*2 - sph.getTheta(), FMath::FPi*2 - sph.getPhi());
+                // Sum in child
+                FMemUtils::addall(inChildren[idxChild]->getLocal(), target_u, SizeArray);
+            }
+        }
+    }
+
+    /** L2P
+      * Equation 13/14, from fmmparadix.pdf
+      */
+    void L2P(const CellClass* const inLocal, ContainerClass* const inParticles){
+        // Take the local value from the cell
+        const FComplexe* FRestrict const u = inLocal->getLocal();
+
+        // For all particles in the leaf box
+        typename ContainerClass::BasicIterator iterParticle(*inParticles);
+        while( iterParticle.hasNotFinished()){
+            // L2P
+            ParticleClass& particle = iterParticle.data();
+            FReal magnitude = 0;
+
+            // E = sum( l = 0:P, sum(m = -l:l, u{l,m} ))
+            for(int l = 0 ; l <= P ; ++l ){
+                magnitude += u[atLm(l,0)].getReal();
+                for(int m = 1 ; m <= l ; ++m ){
+                    // we sum u{l,m} + u{l-m} = 2 * u{l,m} since
+                    // for u{l,-m} = u*{l,m}
+                    magnitude += 2 * u[atLm(l,m)].getReal();
+                }
+            }
+            // inc potential
+            particle.incPotential(magnitude);
+            // progress
+            iterParticle.gotoNext();
+        }
+    }
+
+
+    /** Do nothing */
+    void P2P(const FTreeCoordinate& /*inPosition*/,
+                     ContainerClass* const FRestrict inTargets, const ContainerClass* const FRestrict /*inSources*/,
+                     ContainerClass* const inNeighbors[27], const int /*inSize*/){
+
+        {
+            typename ContainerClass::BasicIterator iterTarget(*inTargets);
+            while( iterTarget.hasNotFinished() ){
+                // We copy the target particle to work with a particle in the heap
+                ParticleClass target( iterTarget.data() );
+
+                // For all particles after the current one
+                typename ContainerClass::BasicIterator iterSameBox = iterTarget;
+                iterSameBox.gotoNext();
+                while( iterSameBox.hasNotFinished() ){
+                    particlesMutualInteraction(&target, &iterSameBox.data());
+                    iterSameBox.gotoNext();
+                }
+                // Set data and progress
+                iterTarget.setData(target);
+                iterTarget.gotoNext();
+            }
+        }
+        // For all the neigbors leaves
+        for(int idxDirectNeighbors = 0 ; idxDirectNeighbors <= 13 ; ++idxDirectNeighbors){
+            if( inNeighbors[idxDirectNeighbors] ){
+                // For all particles in current leaf
+                typename ContainerClass::BasicIterator iterTarget(*inTargets);
+                while( iterTarget.hasNotFinished() ){
+                    ParticleClass target( iterTarget.data() );
+                    // For all the particles in the other leaf
+                    typename ContainerClass::BasicIterator iterSource(*inNeighbors[idxDirectNeighbors]);
+                    while( iterSource.hasNotFinished() ){
+                        particlesMutualInteraction(&target, &iterSource.data());
+                        iterSource.gotoNext();
+                    }
+                    // Set data and progress
+                    iterTarget.setData(target);
+                    iterTarget.gotoNext();
+                }
+            }
+        }
+    }
+
+    /** P2P mutual interaction
+      * F = q * q' / r²
+      */
+    void particlesMutualInteraction(ParticleClass*const FRestrict target, ParticleClass*const FRestrict source) const {
+
+        FReal dx = source->getPosition().getX() - target->getPosition().getX();
+        FReal dy = source->getPosition().getY() - target->getPosition().getY();
+        FReal dz = source->getPosition().getZ() - target->getPosition().getZ();
+
+        FReal inv_square_distance = FReal(1.0) / (dx*dx + dy*dy + dz*dz);
+        FReal inv_distance = FMath::Sqrt(inv_square_distance);
+
+        inv_square_distance *= inv_distance;
+        inv_square_distance *= target->getPhysicalValue() * source->getPhysicalValue();
+
+        dx *= inv_square_distance;
+        dy *= inv_square_distance;
+        dz *= inv_square_distance;
+
+        target->incForces( dx, dy, dz);
+        target->incPotential( inv_distance * source->getPhysicalValue() );
+
+        source->incForces( (-dx), (-dy), (-dz));
+        source->incPotential( inv_distance * target->getPhysicalValue() );
+
+    }
+
+    /** Do nothing */
+    void P2PRemote(const FTreeCoordinate& inPosition,
+                   ContainerClass* const FRestrict inTargets, const ContainerClass* const FRestrict inSources,
+                   ContainerClass* const inNeighbors[27], const int inSize){
+        //kernel.P2PRemote(inPosition, inTargets, inSources, inNeighbors,inSize);
+    }
+
+};
+
+
+#endif // FROTATIONKERNEL_HPP
diff --git a/Tests/Kernels/testRotationAlgorithm.cpp b/Tests/Kernels/testRotationAlgorithm.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..05cde0cc7860332034e0295885c170a9177d0e07
--- /dev/null
+++ b/Tests/Kernels/testRotationAlgorithm.cpp
@@ -0,0 +1,205 @@
+// ===================================================================================
+// Logiciel initial: ScalFmm Version 0.5
+// Co-auteurs : Olivier Coulaud, Bérenger Bramas.
+// Propriétaires : INRIA.
+// Copyright © 2011-2012, diffusé sous les termes et conditions d’une licence propriétaire.
+// Initial software: ScalFmm Version 0.5
+// Co-authors: Olivier Coulaud, Bérenger Bramas.
+// Owners: INRIA.
+// Copyright © 2011-2012, spread under the terms and conditions of a proprietary license.
+// ===================================================================================
+
+#include <limits>
+#include <iostream>
+
+
+#include "../../Src/Components/FSimpleLeaf.hpp"
+#include "../../Src/Containers/FVector.hpp"
+
+#include "../../Src/Containers/FOctree.hpp"
+
+#include "../../Src/Core/FFmmAlgorithm.hpp"
+
+#include "../../Src/Kernels/Spherical/FSphericalParticle.hpp"
+
+#include "../../Src/Kernels/Rotation/FRotationKernel.hpp"
+
+#include "../../Src/Utils/FMath.hpp"
+#include "../../Src/Utils/FMemUtils.hpp"
+#include "../../Src/Utils/FParameters.hpp"
+
+#include "../../Src/Core/FFmmAlgorithm.hpp"
+#include "../../Src/Core/FFmmAlgorithmThread.hpp"
+#include "../../Src/Core/FFmmAlgorithmTask.hpp"
+
+#include "../../Src/Files/FFmaLoader.hpp"
+
+
+
+/** We need to know the position of the particle in the array */
+class IndexedParticle : public FSphericalParticle {
+    int index;
+public:
+    IndexedParticle(): index(-1){}
+
+    int getIndex() const{
+        return index;
+    }
+    void setIndex( const int inIndex ){
+        index = inIndex;
+    }
+};
+
+
+int main(int argc, char** argv){
+    static const int P = 1;
+
+    typedef IndexedParticle                ParticleClass;
+    typedef FRotationCell<P>               CellClass;
+    typedef FVector<ParticleClass>         ContainerClass;
+
+    typedef FSimpleLeaf<ParticleClass, ContainerClass >                     LeafClass;
+    typedef FOctree<ParticleClass, CellClass, ContainerClass , LeafClass >  OctreeClass;
+    typedef FRotationKernel<ParticleClass, CellClass, ContainerClass , P>   KernelClass;
+
+    typedef FFmmAlgorithm<OctreeClass, ParticleClass, CellClass, ContainerClass, KernelClass, LeafClass > FmmClass;
+    typedef FFmmAlgorithmThread<OctreeClass, ParticleClass, CellClass, ContainerClass, KernelClass, LeafClass > FmmClassThread;
+    typedef FFmmAlgorithmTask<OctreeClass, ParticleClass, CellClass, ContainerClass, KernelClass, LeafClass > FmmClassTask;
+    ///////////////////////What we do/////////////////////////////
+    std::cout << ">> This executable has to be used to test Spherical algorithm.\n";
+    std::cout << ">> You can pass -sequential or -task (thread by default).\n";
+    //////////////////////////////////////////////////////////////
+    const int NbLevels = FParameters::getValue(argc,argv,"-h", 5);
+    const int SizeSubLevels = FParameters::getValue(argc,argv,"-sh", 3);
+    FTic counter;
+    const char* const filename = FParameters::getStr(argc,argv,"-f", "../Data/test20k.fma");
+
+    std::cout << "Opening : " << filename << "\n";
+
+    FFmaLoader<ParticleClass> loader(filename);
+    if(!loader.isOpen()){
+        std::cout << "Loader Error, " << filename << " is missing\n";
+        return 1;
+    }
+
+    // -----------------------------------------------------
+
+    OctreeClass tree(NbLevels, SizeSubLevels, loader.getBoxWidth(), loader.getCenterOfBox());
+
+    // -----------------------------------------------------
+
+    std::cout << "Creating & Inserting " << loader.getNumberOfParticles() << " particles ..." << std::endl;
+    std::cout << "\tHeight : " << NbLevels << " \t sub-height : " << SizeSubLevels << std::endl;
+    counter.tic();
+
+    //loader.fillTree(tree);
+    ParticleClass* const particles = new ParticleClass[loader.getNumberOfParticles()];
+    for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
+        loader.fillParticle(particles[idxPart]);
+        particles[idxPart].setIndex( idxPart );
+        tree.insert(particles[idxPart]);
+    }
+
+    counter.tac();
+    std::cout << "Done  " << "(@Creating and Inserting Particles = " << counter.elapsed() << "s)." << std::endl;
+
+    // -----------------------------------------------------
+
+    std::cout << "Create kernel ..." << std::endl;
+    counter.tic();
+
+    KernelClass kernels(P, NbLevels, loader.getBoxWidth(), loader.getCenterOfBox());
+
+    counter.tac();
+    std::cout << "Done  " << " in " << counter.elapsed() << "s)." << std::endl;
+
+    // -----------------------------------------------------
+
+    std::cout << "Working on particles ..." << std::endl;
+
+    if( FParameters::findParameter(argc,argv,"-sequential") != FParameters::NotFound){
+        FmmClass algo(&tree,&kernels);
+        counter.tic();
+        algo.execute();
+    }
+    else if( FParameters::findParameter(argc,argv,"-task") != FParameters::NotFound){
+        FmmClassTask algo(&tree,&kernels);
+        counter.tic();
+        algo.execute();
+    }
+    else {
+        FmmClassThread algo(&tree,&kernels);
+        counter.tic();
+        algo.execute();
+    }
+
+    counter.tac();
+    std::cout << "Done  " << "(@Algorithm = " << counter.elapsed() << "s)." << std::endl;
+
+    { // get sum forces&potential
+        FReal potential = 0;
+        FPoint forces;
+        OctreeClass::Iterator octreeIterator(&tree);
+        octreeIterator.gotoBottomLeft();
+        do{
+            ContainerClass::ConstBasicIterator iter(*octreeIterator.getCurrentListTargets());
+            while( iter.hasNotFinished() ){
+                potential += iter.data().getPotential() * iter.data().getPhysicalValue();
+                forces += iter.data().getForces();
+
+                iter.gotoNext();
+            }
+        } while(octreeIterator.moveRight());
+
+        std::cout << "Foces Sum  x = " << forces.getX() << " y = " << forces.getY() << " z = " << forces.getZ() << std::endl;
+        std::cout << "Potential = " << potential << std::endl;
+    }
+
+    // -----------------------------------------------------
+
+    {
+        std::cout << "Compute direct interaction for all\n";
+        for(int idxTarget = 0 ; idxTarget < loader.getNumberOfParticles() ; ++idxTarget){
+            for(int idxOther = idxTarget + 1 ; idxOther < loader.getNumberOfParticles() ; ++idxOther){
+                kernels.particlesMutualInteraction(&particles[idxTarget], &particles[idxOther]);
+            }
+        }
+
+        std::cout << "Compute Diff...\n";
+        FMath::FAccurater potentialDiff;
+        FMath::FAccurater fx, fy, fz;
+        { // Check that each particle has been summed with all other
+            typename OctreeClass::Iterator octreeIterator(&tree);
+            octreeIterator.gotoBottomLeft();
+
+            do{
+                typename ContainerClass::BasicIterator leafIter(*octreeIterator.getCurrentListTargets());
+
+                while( leafIter.hasNotFinished() ){
+                    const ParticleClass& other = particles[leafIter.data().getIndex()];
+
+                    potentialDiff.add(other.getPotential(),leafIter.data().getPotential());
+std::cout << "Direct Potential = " << other.getPotential() << " Fmm Potential = " << leafIter.data().getPotential() << std::endl; // Remove Me
+                    fx.add(other.getForces().getX(),leafIter.data().getForces().getX());
+
+                    fy.add(other.getForces().getY(),leafIter.data().getForces().getY());
+
+                    fz.add(other.getForces().getZ(),leafIter.data().getForces().getZ());
+
+                    leafIter.gotoNext();
+                }
+            } while(octreeIterator.moveRight());
+        }
+
+        // Print for information
+        std::cout << "Potential diff is = " << potentialDiff.getL2Norm() << " " << potentialDiff.getInfNorm() << std::endl;
+        std::cout << "Fx diff is = " << fx.getL2Norm() << " " << fx.getInfNorm() << std::endl;
+        std::cout << "Fy diff is = " << fy.getL2Norm() << " " << fy.getInfNorm() << std::endl;
+        std::cout << "Fz diff is = " << fz.getL2Norm() << " " << fz.getInfNorm() << std::endl;
+    }
+
+    delete[] particles;
+
+    return 0;
+}
+
diff --git a/Tests/Kernels/testRotationMatrix.cpp b/Tests/Kernels/testRotationMatrix.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ca58186714cbfeafddecc78067806c94bcfd5b8
--- /dev/null
+++ b/Tests/Kernels/testRotationMatrix.cpp
@@ -0,0 +1,482 @@
+// ===================================================================================
+// Logiciel initial: ScalFmm Version 0.5
+// Co-auteurs : Olivier Coulaud, Bérenger Bramas.
+// Propriétaires : INRIA.
+// Copyright © 2011-2012, diffusé sous les termes et conditions d’une licence propriétaire.
+// Initial software: ScalFmm Version 0.5
+// Co-authors: Olivier Coulaud, Bérenger Bramas.
+// Owners: INRIA.
+// Copyright © 2011-2012, spread under the terms and conditions of a proprietary license.
+// ===================================================================================
+
+#include <limits>
+#include <iostream>
+
+#include "../../Src/Kernels/Spherical/FSphericalCell.hpp"
+#include "../../Src/Kernels/Spherical/FSphericalParticle.hpp"
+#include "../../Src/Kernels/Spherical/FSphericalRotationKernel.hpp"
+#include "../../Src/Components/FSimpleLeaf.hpp"
+#include "../../Src/Containers/FVector.hpp"
+
+#include "../../Src/Containers/FOctree.hpp"
+
+#include "../../Src/Core/FFmmAlgorithm.hpp"
+
+#include "../../Src/Kernels/Spherical/FSphericalParticle.hpp"
+
+#include "../../Src/Kernels/Rotation/FRotationKernel.hpp"
+
+#include "../../Src/Utils/FMath.hpp"
+#include "../../Src/Utils/FMemUtils.hpp"
+
+
+int atLm(const int l, const int m){
+        return (l*(l+1))/2 + m;
+}
+
+template < class T >
+T Sgn(const T a){
+    if(a < 0) return T(-1);
+    else if(a > 0) return T(1);
+    return T(0);
+}
+
+template < class T >
+T fact(const T a){
+    if(a<0) printf("Error factorial negative!! a=%d\n",a);
+    int result = 1;
+    for(int i = 1; i<= a ; ++i){
+        result *= i;
+    }
+    return T(result);
+}
+
+template < class T >
+FReal combin(const T& a, const T& b){
+    if(a-b<0) printf("Error combi negative!! a=%d b=%d\n",a,b);
+    return FReal(fact(a)) / FReal(fact(b)*fact(a-b));
+}
+
+int Min(const int a , const int b){
+    return (a<b?a:b);
+}
+
+int Max(const int a , const int b){
+    return (a>b?a:b);
+}
+
+
+FReal analytical(const FReal cosTheta, const FReal sinTheta, const int l , const int m, const int k){
+    if( l >= 0 && -l <= k && k <= l && FMath::Abs(k) <= m && m <= l ){
+        FReal sum = 0;
+        for(int n = Max(-(m+k),0) ; n <= Min(l-m,l-k) ; ++n){
+            sum += FMath::pow(-1.0, l-m-n) * combin(l-k, n) * combin(l+k, l-m-n) * FMath::pow(1.0+cosTheta,n) * FMath::pow(1.0-cosTheta, l-m-n);
+        }
+        return (1.0/FMath::pow(2.0,l)) * FMath::Sqrt(FReal(fact(l-m)*fact(l+m))/FReal(fact(l-k)*fact(l+k)))
+                * FMath::pow(1.0 + Sgn(k)*cosTheta, FMath::Abs(k)) * FMath::pow(sinTheta, m - FMath::Abs(k)) * sum;
+    }
+    else if( (l > 0 && -l <= m && m < 0 && FMath::Abs(m) <= k && k <= l)
+             ||  (l > 0 && 0 <= m && m < l && m < k && k <= l )) {
+        return FMath::pow(-1.0, m+k) * analytical(cosTheta,sinTheta, l, k ,m);
+    }
+    else if( l > 0 && -l <= m && m < l && -l <= k && k < -m ){
+        return FMath::pow(-1.0, m+k) * analytical(cosTheta,sinTheta, l, -m, -k);
+    }
+    else{
+        return -999999.99999;
+    }
+}
+
+FReal analyticalDachsel(const FReal cosTheta, const FReal sinTheta, const int l , const int m, const int k){
+    /*if(l >= 0 && -l <= m && m <= l && FMath::Abs(m) <= k && k <= l) {
+        return FMath::pow(-1.0, k+m) * analyticalDachsel(cosTheta,sinTheta, l, k ,m);
+    }
+    else if( l > 0 && -l <= m && m <= l-1 && -l <= k && k <= -(m+1) ){
+        return FMath::pow(-1.0, m+k) * analyticalDachsel(cosTheta,sinTheta, l, -m, -k);
+    }*/
+    if( m < k ){
+        return FMath::pow(-1.0, k+m) * analyticalDachsel(cosTheta,sinTheta, l, k ,m);
+    }
+    else if( m < -k ){
+        return FMath::pow(-1.0, m+k) * analyticalDachsel(cosTheta,sinTheta, l, -m, -k);
+    }
+    else {
+        FReal sum = 0;
+        for(int n = 0 ; n <= l-m ; ++n){
+            sum += FMath::pow(-1.0, l-m-n) * combin(l-k, n) * combin(l+k, l-m-n) * FMath::pow(1.0+cosTheta,n) * FMath::pow(1.0-cosTheta, l-m-n);
+        }
+        return (1.0/FMath::pow(2.0,l)) * FMath::Sqrt(FReal(fact(l-m)*fact(l+m))/FReal(fact(l-k)*fact(l+k)))
+                * FMath::pow(1.0 + Sgn(k)*cosTheta, FMath::Abs(k)) * FMath::pow(sinTheta, m - FMath::Abs(k)) * sum;
+    }
+}
+
+
+
+int main(){
+    static const int P = 2;
+    static const int SizeArray = (P+1)*(P+1);
+
+    //const FReal cosTheta = FMath::Cos(FMath::FPiDiv2/FReal(2.0));
+    //const FReal sinTheta = FMath::Sin(FMath::FPiDiv2/FReal(2.0));
+    const FPoint relativPos(FReal(0.1),FReal(0.1),FReal(0.1));
+    const FSpherical relativPosSphere(relativPos);
+    const FReal Betha = 2.186276;//FMath::FPi/2; //2*FMath::FPi-FMath::FPi/2
+    const FReal cosTheta = FMath::Cos(Betha); // relativPosSphere.getCosTheta();
+    const FReal sinTheta = FMath::Sin(Betha); // relativPosSphere.getSinTheta();
+
+    std::cout << "cosTheta = " << cosTheta << "\n";
+    std::cout << "sinTheta = " << sinTheta << "\n";
+
+    // Rotation matrix d[l][m][k]
+    FReal d[P+1][2*P+1][2*P+1];
+    FMemUtils::setall((FReal*)d, FReal(std::numeric_limits<FReal>::quiet_NaN()), (P+1)*(2*P+1)*(2*P+1));
+
+    /////////////////////////////////////////////////////////////
+    // First method, Page 3,4
+    // Fast and accurate determination of Wigner rotation matrices
+    // in FMM
+    /////////////////////////////////////////////////////////////
+
+    FReal legendre_f[SizeArray];
+    { // init legendre-f values
+        // Equ 24
+        // P~{0,0} = 1
+        legendre_f[0] = 1.0;
+
+        { // P~{l,l} = sqrt(2l-1 / 2l) sin(theta) P~{l-1,l-1} , For l > 0
+            for(int l = 1; l <= P ; ++l ){
+                legendre_f[atLm(l,l)] = FMath::Sqrt(FReal((2.0*l-1) / (2.0*l))) * sinTheta * legendre_f[atLm(l-1,l-1)];
+            }
+        }
+        { // P~{l,l-1} = sqrt(2l-1) cos(theta) P~{l-1,l-1} , For l > 0
+            for(int l = 1; l <= P ; ++l ){
+                legendre_f[atLm(l,l-1)] = FMath::Sqrt(FReal(2*l-1)) * cosTheta * legendre_f[atLm(l-1,l-1)];
+            }
+        }
+        {
+            // For l > 1, 0 <= k < l-1
+            // P~{l,k} = (2l-1) cos(theta) P{l-1,k} - sqrt((l-k-1)(l+k-1) P~{l-2,k}
+            //          / sqrt((l-k)(l+k))
+            for(int l = 2; l <= P ; ++l ){
+                for( int k = 0 ; k < l - 1 ; ++k ){
+                    legendre_f[atLm(l,k)] =
+                            (FReal(2*l - 1 ) * cosTheta * legendre_f[atLm(l-1,k)] - FMath::Sqrt(FReal((l-k-1)*(l+k-1))) * legendre_f[atLm(l-2,k)])
+                                                          / FMath::Sqrt(FReal((l-k)*(l+k)));
+                }
+            }
+        }
+    }
+
+    { // Initial condition
+        // Equ 21
+        // For l > 0,
+        // & -l <= k < 0, d{l,0,k} = sqrt((l+k)!/(l-k)!) P{l,-k} = P~{l,-k}
+        // & k = 0, d{l,0,k} = P{l,0}
+        // & 0 < k <= l, d{l,0,k} = -1^k sqrt((l-k)!/(l+k)!) P{l,k} = -1^k P~{l,k}
+        for(int l = 0 ; l <= P ; ++l){
+            // k < 0
+            for(int k = -l ; k < 0 ; ++k){
+                d[l][P+0][P+k] = legendre_f[atLm(l,-k)];
+            }
+            // k == 0
+            d[l][P+0][P+0] = legendre_f[atLm(l,0)];
+            // 0 < k
+            for(int k = 1 ; k <= l ; ++k){
+                d[l][P+0][P+k] = FMath::pow(FReal(-1),k) * legendre_f[atLm(l,k)];
+            }
+        }
+    }
+    {
+        for(int l = 1 ; l <= P ; ++l){
+            for(int m = 0 ; m < l ; ++m){
+                // Equ 18
+                // For l > 0, 0 <= m < l, -l < k <= l, cos(theta) >= 0
+                // d{l,m+1,k} = sqrt( l(l+1) - k(k-1) / l(l+1) - m(m+1)) d{l,m,k-1}
+                //            - (m+k) sin(theta) d{l,m,k} / sqrt(l(l+1) - m(m+1)) (1+cos(theta))
+                for(int k = -l+1 ; k <= l ; ++k){
+                    d[l][P+m+1][P+k] =
+                            FMath::Sqrt(FReal(l*(l+1)-k*(k-1))/FReal(l*(l+1)-m*(m+1))) * d[l][P+m][P+k-1]
+                            - FReal(m+k)*sinTheta*d[l][P+m][P+k]/(FMath::Sqrt(FReal(l*(l+1)-m*(m+1)))*(1+cosTheta));
+                }
+                // Equ 19
+                // For l > 0, 0 <= m < l, cos(theta) >= 0
+                // d{l,m+1,-l} = (l-m) sin(theta) d{l,m,-l}
+                //             / sqrt(l(l+1)-m(m+1)) (1+cos(theta))
+                d[l][P+m+1][P-l] = FReal(l-m)*sinTheta*d[l][P+m][P-l]/(FMath::Sqrt(FReal(l*(l+1)-m*(m+1)))*(1+cosTheta));
+            }
+            // Equ 20
+            // d{l,m,k} = -1^(m+k) d{l,-m,-k}  , For l > 0, -l <= m < 0, -l <= k <= l
+            for(int m = -l ; m < 0 ; ++m){
+                for(int k = -l ; k <= l ; ++k){
+                    d[l][P+m][P+k] = FMath::pow( FReal(-1.0), m+k) * d[l][P-m][P-k];
+                }
+            }
+        }
+    }
+
+    // Print
+    std::cout << "Print result\n";
+    for(int l = 0 ; l <= P ; ++l){
+        for(int m = -l ; m <= l ; ++m ){
+            for(int k = -l ; k <= l ; ++k ){
+                std::cout << d[l][P+m][P+k] << "\t";
+            }
+            std::cout << "\n";
+        }
+        std::cout << "\n";
+    }
+    FMemUtils::setall((FReal*)d, FReal(std::numeric_limits<FReal>::quiet_NaN()), (P+1)*(2*P+1)*(2*P+1));
+
+    /////////////////////////////////////////////////////////////
+    // Second method, Page 4
+    // Fast and accurate determination of Wigner rotation matrices
+    // in FMM
+    /////////////////////////////////////////////////////////////
+
+    FReal g[SizeArray];
+    {// Equ 29
+        // g{0,0} = 1
+        g[0] = 1;
+
+        // g{l,0} = sqrt( (2l - 1) / 2l) g{l-1,0}  for l > 0
+        for(int l = 1; l <= P ; ++l ){
+            g[atLm(l,0)] = FMath::Sqrt(FReal((l*2.0-1.0)/(l*2.0))) * g[atLm(l-1,0)];
+        }
+
+        // g{l,m} = sqrt( (l - m + 1) / (l+m)) g{l,m-1}  for l > 0, 0 < m <= l
+        for(int l = 1; l <= P ; ++l ){
+            for(int m = 1; m <= l ; ++m ){
+                g[atLm(l,m)] = FMath::Sqrt(FReal((l-m+1))/FReal((l+m))) * g[atLm(l,m-1)];
+            }
+        }
+    }
+    { // initial
+        // Equ 28
+        // d{l,m,l} = -1^(l+m) g{l,m} (1+cos(theta))^m sin(theta)^(l-m) , For l > 0, 0 <= m <= l
+        for(int l = 0 ; l <= P ; ++l){
+            for(int m = 0 ; m <= l ; ++m){
+                d[l][P+m][P+l] = FMath::pow( FReal(-1.0), l+m) * g[atLm(l,m)] * FMath::pow( FReal(1) + cosTheta, m) * FMath::pow(sinTheta, l-m);
+            }
+        }
+    }
+    {
+        for(int l = 1 ; l <= P ; ++l){
+            for(int k = l ; k > -l ; --k){
+                // Equ 25
+                // For l > 0, 0 <= m < l, -l < k <= l, cos(theta) >= 0
+                // d{l,m,k-1} = sqrt( l(l+1) - m(m+1) / l(l+1) - k(k-1)) d{l,m+1,k}
+                //            + (m+k) sin(theta) d{l,m,k} / sqrt(l(l+1) - k(k-1)) (1+cos(theta))
+                for(int m = 0 ; m < l ; ++m){
+                    d[l][P+m][P+k-1] =
+                            (FMath::Sqrt(FReal(l*(l+1)-m*(m+1))/FReal(l*(l+1)-k*(k-1))) * d[l][P+m+1][P+k])
+                            + (FReal(m+k)*sinTheta*d[l][P+m][P+k]/(FMath::Sqrt(FReal(l*(l+1)-k*(k-1)))*(1+cosTheta)));
+                }
+                // Equ 26
+                // For l > 0, -l < k <= l, cos(theta) >= 0
+                // d{l,l,k-1} = (l+k) sin(theta) d{l,l,k}
+                //             / sqrt(l(l+1)-k(k-1)) (1+cos(theta))
+                d[l][P+l][P+k-1] = FReal(l+k)*sinTheta*d[l][P+l][P+k]/(FMath::Sqrt(FReal(l*(l+1)-k*(k-1)))*(1+cosTheta));
+            }
+            // Equ 27
+            // d{l,m,k} = -1^(m+k) d{l,-m,-k}  , For l > 0, -l <= m < 0, -l <= k <= l
+            for(int m = -l ; m < 0 ; ++m){
+                for(int k = -l ; k <= l ; ++k){
+                    d[l][P+m][P+k] = FMath::pow( FReal(-1), m+k) * d[l][P-m][P-k];
+                }
+            }
+        }
+    }
+
+    // Print
+    std::cout << "Print result\n";
+    for(int l = 0 ; l <= P ; ++l){
+        for(int m = -l ; m <= l ; ++m ){
+            for(int k = -l ; k <= l ; ++k ){
+                std::cout << d[l][P+m][P+k] << "\t";
+            }
+            std::cout << "\n";
+        }
+        std::cout << "\n";
+    }
+    FMemUtils::setall((FReal*)d, FReal(std::numeric_limits<FReal>::quiet_NaN()), (P+1)*(2*P+1)*(2*P+1));
+
+
+    /////////////////////////////////////////////////////////////
+    // Analatycall values
+    /////////////////////////////////////////////////////////////
+    std::cout << "Print result analytical\n";
+    for(int l = 0 ; l <= P ; ++l){
+        for(int m = -l ; m <= l ; ++m ){
+            for(int k = -l ; k <= l ; ++k ){
+                std::cout << analytical(cosTheta,sinTheta,l,m,k) << "\t";
+            }
+            std::cout << "\n";
+        }
+        std::cout << "\n";
+    }
+
+    /////////////////////////////////////////////////////////////
+    // Analatycall values V2
+    /////////////////////////////////////////////////////////////
+    std::cout << "Print result analytical V2\n";
+    for(int l = 0 ; l <= P ; ++l){
+        for(int m = -l ; m <= l ; ++m ){
+            for(int k = -l ; k <= l ; ++k ){
+                std::cout << analyticalDachsel(cosTheta,sinTheta,l,m,k) << "\t";
+            }
+            std::cout << "\n";
+        }
+        std::cout << "\n";
+    }
+
+    /////////////////////////////////////////////////////////////
+    // correct result for l=1
+    /////////////////////////////////////////////////////////////
+    std::cout << "Print L=1\n";
+    {
+        FReal resL[9];
+        resL[0] = FMath::pow(FMath::Cos(Betha/2.0),2);
+        resL[1] = -FMath::Sin(Betha)/FMath::Sqrt(2.0);
+        resL[2] = FMath::pow(FMath::Sin(Betha/2.0),2);
+        resL[3] = FMath::Sin(Betha)/FMath::Sqrt(2.0);;
+        resL[4] = FMath::Cos(Betha);
+        resL[5] = -FMath::Sin(Betha)/FMath::Sqrt(2.0);;
+        resL[6] = FMath::pow(FMath::Sin(Betha/2.0),2);
+        resL[7] = FMath::Sin(Betha)/FMath::Sqrt(2.0);
+        resL[8] = FMath::pow(FMath::Cos(Betha/2.0),2);
+
+        for(int m = 0 ; m < 3 ; ++m ){
+            for(int k = 0 ; k < 3 ; ++k ){
+                std::cout << resL[m*3 + k] << "\t";
+            }
+            std::cout << "\n";
+        }
+    }
+    /////////////////////////////////////////////////////////////
+    // correct result for l=2
+    /////////////////////////////////////////////////////////////
+    std::cout << "Print L=2\n";
+    {
+        FReal resL[25];
+        resL[0] = FMath::pow(FMath::Cos(Betha/2.0),4);
+        resL[1] = (-FMath::pow(FMath::Cos(Betha/2.0),2))*FMath::Sin(Betha);
+        resL[2] = (1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::pow(FMath::Sin(Betha),2);
+        resL[3] = (-FMath::pow(FMath::Sin(Betha/2.0),2))*FMath::Sin(Betha);
+        resL[4] = FMath::pow(FMath::Sin(Betha/2.0),4);
+
+        resL[5] = FMath::pow(FMath::Cos(Betha/2.0),2)*FMath::Sin(Betha);
+        resL[6] = FMath::pow(FMath::Cos(Betha),2)- FMath::pow(FMath::Sin(Betha/2),2);
+        resL[7] = (-1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::Sin(2*Betha);
+        resL[8] = FMath::pow(FMath::Cos(Betha/2),2)- FMath::pow(FMath::Cos(Betha),2);
+        resL[9] = (-FMath::pow(FMath::Sin(Betha/2.0),2))*FMath::Sin(Betha);
+
+        resL[10] = (1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::pow(FMath::Sin(Betha),2);
+        resL[11] = (1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::Sin(Betha*2);
+        resL[12] = (1.0/2.0)*(-1+3*FMath::pow(FMath::Cos(Betha),2));
+        resL[13] = (-1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::Sin(Betha*2);
+        resL[14] = (1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::pow(FMath::Sin(Betha),2);
+
+        resL[15] = FMath::pow(FMath::Sin(Betha/2.0),2)*FMath::Sin(Betha);
+        resL[16] = FMath::pow(FMath::Cos(Betha/2),2)- FMath::pow(FMath::Cos(Betha),2);
+        resL[17] = (1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::Sin(2*Betha);
+        resL[18] = FMath::pow(FMath::Cos(Betha),2)- FMath::pow(FMath::Sin(Betha/2),2);
+        resL[19] = (-FMath::pow(FMath::Cos(Betha/2.0),2))*FMath::Sin(Betha);
+
+        resL[20] = FMath::pow(FMath::Sin(Betha/2.0),4);
+        resL[21] = FMath::pow(FMath::Sin(Betha/2.0),2)*FMath::Sin(Betha);
+        resL[22] = (1.0/2.0)*FMath::Sqrt(3.0/2.0)*FMath::pow(FMath::Sin(Betha),2);
+        resL[23] = FMath::pow(FMath::Cos(Betha/2.0),2)*FMath::Sin(Betha);
+        resL[24] = FMath::pow(FMath::Cos(Betha/2.0),4);
+
+
+        for(int m = 0 ; m < 5 ; ++m ){
+            for(int k = 0 ; k < 5 ; ++k ){
+                std::cout << resL[m*5 + k] << "\t";
+            }
+            std::cout << "\n";
+        }
+    }
+    /////////////////////////////////////////////////////////////
+    // Third method, Page 5 (+105)
+    // Rotating around the quartic angular momentum barrier in fast multipole
+    /////////////////////////////////////////////////////////////
+
+//    FReal legendre[SizeArray];
+//    {
+//        const FReal x = cosTheta;
+//        const FReal minus_sqrt_1_minus_x_pow_2 = -sinTheta;
+
+//        legendre[0] = 1.0;        // P_0,0(cosTheta) = 1
+//        legendre[1] = x;          // P_1,0(cosTheta) = cosTheta
+//        legendre[2] = minus_sqrt_1_minus_x_pow_2;// P_1,1(cosTheta) = -sinTheta = -sqrt(1-x^2)
+
+//        FReal fact = 3.0;
+
+//        for(int l = 2; l <= P ; ++l ){
+//            const FReal x_l2_minus_1 = x * FReal( 2 * l - 1 );
+//            // m from 0 to l - 2
+//            for( int m = 0; m <= l - 2 ; ++m ){
+//                //         cosTheta x (2 x l - 1) x P_l-1_m - (l + m - 1) x P_l-2_m
+//                // P_l_m = --------------------------------------------------------
+//                //                               l - m
+//                legendre[atLm(l,m)] = (x_l2_minus_1 * legendre[atLm(l-1,m)] - FReal( l + m - 1 ) * legendre[atLm(l-2,m)] )
+//                                                                    / FReal( l - m );
+//            }
+//            // Compute P_l,{l-1}
+//            legendre[atLm(l,l-1)] = x_l2_minus_1 * legendre[atLm(l,l-1)];
+
+//            // Compute P_l,l
+//            legendre[atLm(l,l)] = fact * minus_sqrt_1_minus_x_pow_2 * legendre[atLm(l,l-1)];
+
+//            fact += FReal(2.0);
+//        }
+//    }
+//    { // initial
+//        // Equ A8
+//        // d{l,0,m} = -1^(m) P{l,m} , For l >= 0, -l <= m <= l
+//        for(int l = 0 ; l <= P ; ++l){
+//            for(int m = -l ; m <= l ; ++m){
+//                d[l][P+0][P+m] = FMath::pow( FReal(-1.0), m) * legendre[atLm(l,m)];
+//            }
+//        }
+//    }
+//    {
+//        // Equ A4
+//        // For l > 0, l < m <= l, -l <= k < l, cos(theta) >= 0
+//        // d{l,k+1,m} = -(m+k) sin(theta) d{l,k,m} / sqrt(l(l+1) - k(k+1)) (1+cos(theta))
+//        //              + sqrt( l(l+1) - m(m+1) / l(l+1) - k(k+1)) d{l,k,m-1}
+//        //
+//        for(int l = 1 ; l <= P ; ++l){
+//            for(int k = 0 ; k < l ; ++k){
+//                for(int m = -l+1 ; m <= l ; ++m){
+//                    d[l][P+k+1][P+m] =
+//                            -FReal(m+k)*sinTheta*d[l][P+k][P+m]/(FMath::Sqrt(FReal(l*(l+1)-k*(k+1)))*(1+cosTheta))
+//                            + FMath::Sqrt(FReal(l*(l+1)-m*(m+1))/FReal(l*(l+1)-k*(k+1))) * d[l][P+k][P+m-1];
+//                }
+//                d[l][P+k+1][P-l] = -FReal(k-l)*sinTheta*d[l][P+k][P-l]/(FMath::Sqrt(FReal(l*(l+1)-k*(k+1)))*(1+cosTheta));
+//            }
+//            // Sym
+//            for(int k = -1 ; k >= -l ; --k){
+//                for(int m = -l ; m <= l ; ++m){
+//                    d[l][P+k][P+m] = FMath::pow( FReal(-1), m+k) * d[l][P-k][P-m];
+//                }
+//            }
+//        }
+//    }
+
+//    // Print
+//    std::cout << "Print result\n";
+//    for(int l = 0 ; l <= P ; ++l){
+//        for(int m = -l ; m <= l ; ++m ){
+//            for(int k = -l ; k <= l ; ++k ){
+//                std::cout << d[l][P+m][P+k] << "\t";
+//            }
+//            std::cout << "\n";
+//        }
+//        std::cout << "\n";
+//    }
+//    FMemUtils::setall((FReal*)d, FReal(std::numeric_limits<FReal>::quiet_NaN()), (P+1)*(2*P+1)*(2*P+1));
+
+    return 0;
+}
+