Commit a78cc320 authored by BLANCHARD Pierre's avatar BLANCHARD Pierre
Browse files

Fixed handling of non homogeneous kernels of interactions (aka matrix kernel)...

Fixed handling of non homogeneous kernels of interactions (aka matrix kernel) in Uniform kernel (TODO Fix in Chebyshev if relevant), Introduced blockwise evaluation of tensorial matrix kernel (+redesign precomputation), added input parameter in AbstractUnifKernel (for OptiDis non singular Ra_{ijk} or any matrix kernel requiring an extra parameter), +divers test fixing.
parent ca0bf8b8
......@@ -51,6 +51,16 @@ unsigned int Compress(const FReal epsilon, const unsigned int ninteractions,
* size \f$\ell^3\times r\f$, and \f$316\f$ \f$C_t\f$, each of size \f$r\times
* r\f$.
*
* PB: FChebM2LHandler does not seem to support non_homogeneous kernels!
* In fact nothing appears to handle this here (i.e. adapt scaling and storage
* to MatrixKernelClass::Type). Given the relatively important cost of the
* Chebyshev variant, it is probably a choice not to have implemented this
* feature here but instead in the ChebyshevSym variant. But what if the
* kernel is non homogeneous and non symmetric (e.g. Dislocations)...
*
* TODO Specialize class (see UnifM2LHandler) OR prevent from using this
* class with non homogeneous kernels ?!
*
* @tparam ORDER interpolation order \f$\ell\f$
*/
template <int ORDER, class MatrixKernelClass>
......
......@@ -55,7 +55,7 @@ enum KERNEL_FUNCTION_TYPE {HOMOGENEOUS, NON_HOMOGENEOUS};
*
*/
struct FInterpAbstractMatrixKernel : FNoCopyable
{
{
virtual ~FInterpAbstractMatrixKernel(){} // to remove warning
virtual FReal evaluate(const FPoint&, const FPoint&) const = 0;
// I need both functions because required arguments are not always given
......@@ -68,13 +68,14 @@ struct FInterpAbstractMatrixKernel : FNoCopyable
/// One over r
struct FInterpMatrixKernelR : FInterpAbstractMatrixKernel
{
static const KERNEL_FUNCTION_TYPE Type = HOMOGENEOUS;
static const KERNEL_FUNCTION_TYPE Type = /*NON_*/HOMOGENEOUS;
static const KERNEL_FUNCTION_IDENTIFIER Identifier = ONE_OVER_R;
static const unsigned int DIM = 1; //PB: dimension of kernel
static const unsigned int NIDX = 1; //PB: number of indices
static const unsigned int NRHS = 1;
static const unsigned int NLHS = 1;
FInterpMatrixKernelR(const unsigned int = 0) {}
FInterpMatrixKernelR(const double = 0.0, const unsigned int = 0) {}
// returns position in reduced storage
int getPosition(const unsigned int) const
......@@ -98,6 +99,19 @@ struct FInterpMatrixKernelR : FInterpAbstractMatrixKernel
{
return FReal(2.) / CellWidth;
}
// FReal getScaleFactor(const FReal, const int) const
// {
// // return 1 because non homogeneous kernel functions cannot be scaled!!!
// return FReal(1.);
// }
//
// FReal getScaleFactor(const FReal) const
// {
// // return 1 because non homogeneous kernel functions cannot be scaled!!!
// return FReal(1.);
// }
};
......@@ -108,10 +122,11 @@ struct FInterpMatrixKernelRR : FInterpAbstractMatrixKernel
static const KERNEL_FUNCTION_TYPE Type = HOMOGENEOUS;
static const KERNEL_FUNCTION_IDENTIFIER Identifier = ONE_OVER_R_SQUARED;
static const unsigned int DIM = 1; //PB: dimension of kernel
static const unsigned int NIDX = 1; //PB: number of indices
static const unsigned int NRHS = 1;
static const unsigned int NLHS = 1;
FInterpMatrixKernelRR(const unsigned int = 0) {}
FInterpMatrixKernelRR(const double = 0.0, const unsigned int = 0) {}
// returns position in reduced storage
int getPosition(const unsigned int) const
......@@ -145,10 +160,11 @@ struct FInterpMatrixKernelLJ : FInterpAbstractMatrixKernel
static const KERNEL_FUNCTION_TYPE Type = NON_HOMOGENEOUS;
static const KERNEL_FUNCTION_IDENTIFIER Identifier = LENNARD_JONES_POTENTIAL;
static const unsigned int DIM = 1; //PB: dimension of kernel
static const unsigned int NIDX = 1; //PB: number of indices
static const unsigned int NRHS = 1;
static const unsigned int NLHS = 1;
FInterpMatrixKernelLJ(const unsigned int = 0) {}
FInterpMatrixKernelLJ(const double = 0.0, const unsigned int = 0) {}
// returns position in reduced storage
int getPosition(const unsigned int) const
......@@ -193,7 +209,8 @@ struct FInterpMatrixKernel_IOR : FInterpAbstractMatrixKernel
static const KERNEL_FUNCTION_TYPE Type = HOMOGENEOUS;
static const KERNEL_FUNCTION_IDENTIFIER Identifier = ID_OVER_R;
static const unsigned int DIM = 6; //PB: dimension of kernel
const unsigned int indexTab[12]={0,0,0,1,1,2,
static const unsigned int NIDX = 2; //PB: number of indices
static constexpr unsigned int indexTab[12]={0,0,0,1,1,2,
0,1,2,1,2,2};
static const unsigned int NRHS = 3;
static const unsigned int NLHS = 3;
......@@ -205,7 +222,7 @@ struct FInterpMatrixKernel_IOR : FInterpAbstractMatrixKernel
const unsigned int _i,_j;
FInterpMatrixKernel_IOR(const unsigned int d = 0)
FInterpMatrixKernel_IOR(const double = 0.0, const unsigned int d = 0)
: _i(indexTab[d]), _j(indexTab[d+DIM])
{}
......@@ -225,6 +242,22 @@ struct FInterpMatrixKernel_IOR : FInterpAbstractMatrixKernel
}
void evaluateBlock(const FPoint& x, const FPoint& y, FReal* block) const
{
const FPoint xy(x-y);
const FReal one_over_r = FReal(1.)/xy.norm();
for(unsigned int d=0;d<DIM;++d){
// unsigned int i = indexTab[d];
// unsigned int j = indexTab[d+DIM];
// if(i==j)
block[d] = one_over_r;
// else
// block[d] = 0.0;
}
}
FReal getScaleFactor(const FReal RootCellWidth, const int TreeLevel) const
{
const FReal CellWidth(RootCellWidth / FReal(FMath::pow(2, TreeLevel)));
......@@ -246,19 +279,20 @@ struct FInterpMatrixKernel_R_IJ : FInterpAbstractMatrixKernel
static const KERNEL_FUNCTION_TYPE Type = HOMOGENEOUS;
static const KERNEL_FUNCTION_IDENTIFIER Identifier = R_IJ;
static const unsigned int DIM = 6; //PB: dimension of kernel
const unsigned int indexTab[12]={0,0,0,1,1,2,
0,1,2,1,2,2};
static const unsigned int NIDX = 2; //PB: number of indices
static constexpr unsigned int indexTab[DIM*NIDX]={0,0,0,1,1,2,
0,1,2,1,2,2};
static const unsigned int NRHS = 3;
static const unsigned int NLHS = 3;
// store positions in sym tensor
// store positions in sym tensor (when looping over NRHSxNLHS)
const unsigned int applyTab[9]={0,1,2,
1,3,4,
2,4,5};
const unsigned int _i,_j;
FInterpMatrixKernel_R_IJ(const unsigned int d = 0)
FInterpMatrixKernel_R_IJ(const double = 0.0, const unsigned int d = 0)
: _i(indexTab[d]), _j(indexTab[d+DIM])
{}
......@@ -283,8 +317,6 @@ struct FInterpMatrixKernel_R_IJ : FInterpAbstractMatrixKernel
else if(_j==2) rj=xy.getZ();
else throw std::runtime_error("Update j!");
// return xy.getX() * xy.getX() * one_over_r3; //PB: test r0^2/R^3
if(_i==_j)
return one_over_r - ri * ri * one_over_r3;
else
......@@ -292,6 +324,24 @@ struct FInterpMatrixKernel_R_IJ : FInterpAbstractMatrixKernel
}
void evaluateBlock(const FPoint& x, const FPoint& y, FReal* block) const
{
const FPoint xy(x-y);
const FReal one_over_r = FReal(1.)/xy.norm();
const FReal one_over_r3 = one_over_r*one_over_r*one_over_r;
const double r[3] = {xy.getX(),xy.getY(),xy.getZ()};
for(unsigned int d=0;d<DIM;++d){
unsigned int i = indexTab[d];
unsigned int j = indexTab[d+DIM];
if(i==j)
block[d] = one_over_r - r[i] * r[i] * one_over_r3;
else
block[d] = - r[i] * r[j] * one_over_r3;
}
}
FReal getScaleFactor(const FReal RootCellWidth, const int TreeLevel) const
{
const FReal CellWidth(RootCellWidth / FReal(FMath::pow(2, TreeLevel)));
......@@ -307,27 +357,27 @@ struct FInterpMatrixKernel_R_IJ : FInterpAbstractMatrixKernel
};
/// R_{,ijk}
struct FInterpMatrixKernel_R_IJK : FInterpAbstractMatrixKernel
{
static const KERNEL_FUNCTION_TYPE Type = HOMOGENEOUS;
static const KERNEL_FUNCTION_IDENTIFIER Identifier = R_IJK;
static const unsigned int DIM = 10; //PB: dimension of kernel
const unsigned int indexTab[30]={0,0,0,1,1,1,2,2,2,0,
0,1,2,0,1,2,0,1,2,1,
0,1,2,0,1,2,0,1,2,2};
static const unsigned int NIDX = 3; //PB: number of indices
static constexpr unsigned int indexTab[DIM*NIDX]={0,0,0,1,1,1,2,2,2,0,
0,1,2,0,1,2,0,1,2,1,
0,1,2,0,1,2,0,1,2,2};
static const unsigned int NRHS = 3;
static const unsigned int NLHS = 3;
// store positions in sym tensor
// store positions in sym tensor (when looping over NRHSxNLHS)
const unsigned int applyTab[27]={0,3,6,3,1,9,6,9,2,
3,1,9,1,4,7,9,7,5,
6,9,2,9,7,5,2,5,8};
const unsigned int _i,_j,_k;
FInterpMatrixKernel_R_IJK(const unsigned int d = 0)
FInterpMatrixKernel_R_IJK(const double = 0.0, const unsigned int d = 0)
: _i(indexTab[d]), _j(indexTab[d+DIM]), _k(indexTab[d+2*DIM])
{}
......
......@@ -59,6 +59,8 @@ protected:
const FReal BoxWidth;
/// Width of a leaf cell box
const FReal BoxWidthLeaf;
/// Parameter to pass to matrix kernel (material specific or anything)
const double MatParam;
/**
* Compute center of leaf cell from its tree coordinate.
......@@ -79,14 +81,16 @@ public:
* runtime_error is thrown if the required file is not valid).
*/
FAbstractUnifKernel(const int inTreeHeight,
const FReal inBoxWidth,
const FPoint& inBoxCenter)
const FReal inBoxWidth,
const FPoint& inBoxCenter,
const double inMatParam = 0.0)
: Interpolator(new InterpolatorClass()),
MatrixKernel(new MatrixKernelClass()),
MatrixKernel(new MatrixKernelClass(inMatParam)),
TreeHeight(inTreeHeight),
BoxCorner(inBoxCenter - inBoxWidth / FReal(2.)),
BoxWidth(inBoxWidth),
BoxWidthLeaf(BoxWidth / FReal(FMath::pow(2, inTreeHeight - 1)))
BoxWidthLeaf(BoxWidth / FReal(FMath::pow(2, inTreeHeight - 1))),
MatParam(inMatParam)
{
/* empty */
}
......
......@@ -45,7 +45,7 @@ class FUnifKernel
: public FAbstractUnifKernel< CellClass, ContainerClass, MatrixKernelClass, ORDER, NVALS>
{
// private types
typedef FUnifM2LHandler<ORDER,MatrixKernelClass> M2LHandlerClass;
typedef FUnifM2LHandler<ORDER,MatrixKernelClass::Type> M2LHandlerClass;
// using from
typedef FAbstractUnifKernel< CellClass, ContainerClass, MatrixKernelClass, ORDER, NVALS>
......@@ -61,17 +61,13 @@ public:
* runtime_error is thrown if the required file is not valid).
*/
FUnifKernel(const int inTreeHeight,
const FReal inBoxWidth,
const FPoint& inBoxCenter)
: FAbstractUnifKernel< CellClass, ContainerClass, MatrixKernelClass, ORDER, NVALS>(inTreeHeight,
inBoxWidth,
inBoxCenter),
M2LHandler(new M2LHandlerClass())
{
// read precomputed compressed m2l operators from binary file
//M2LHandler->ReadFromBinaryFileAndSet(); // PB: TODO?
M2LHandler->ComputeAndSet();
}
const FReal inBoxWidth,
const FPoint& inBoxCenter)
: FAbstractUnifKernel< CellClass, ContainerClass, MatrixKernelClass, ORDER, NVALS>(inTreeHeight,inBoxWidth,inBoxCenter),
M2LHandler(new M2LHandlerClass(AbstractBaseClass::MatrixKernel.getPtr(),
inTreeHeight,
inBoxWidth))// PB: for non homogeneous case
{ }
void P2M(CellClass* const LeafCell,
......@@ -133,16 +129,17 @@ public:
const int /*NumSourceCells*/,
const int TreeLevel)
{
const FReal CellWidth(AbstractBaseClass::BoxWidth / FReal(FMath::pow(2, TreeLevel)));
const FReal scale(AbstractBaseClass::MatrixKernel.getPtr()->getScaleFactor(CellWidth));
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
FComplexe *const TransformedLocalExpansion = TargetCell->getTransformedLocal(idxRhs);
const FReal CellWidth(AbstractBaseClass::BoxWidth / FReal(FMath::pow(2, TreeLevel)));
for (int idx=0; idx<343; ++idx){
if (SourceCells[idx]){
M2LHandler->applyFC(idx, CellWidth, SourceCells[idx]->getTransformedMultipole(idxRhs),
M2LHandler->applyFC(idx, TreeLevel, scale,
SourceCells[idx]->getTransformedMultipole(idxRhs),
TransformedLocalExpansion);
}
}
}
......
......@@ -32,6 +32,120 @@
#include "./FUnifTensor.hpp"
/*! Precomputation of the 316 interactions by evaluation of the matrix kernel on the uniform grid and transformation into Fourier space.
PB: Compute() does not belong to the M2LHandler like it does in the Chebyshev kernel. This allows much nicer specialization of the M2LHandler class with respect to the homogeneity of the kernel of interaction like in the ChebyshevSym kernel.*/
template <int ORDER, typename MatrixKernelClass>
static void Compute(const MatrixKernelClass *const MatrixKernel, const FReal CellWidth, FComplexe* &FC)
{
// allocate memory and store compressed M2L operators
if (FC) throw std::runtime_error("M2L operators are already set");
// PB: need to redefine some constant since not function from m2lhandler class
const unsigned int order = ORDER;
const unsigned int nnodes = TensorTraits<ORDER>::nnodes;
const unsigned int ninteractions = 316;
typedef FUnifTensor<ORDER> TensorType;
// interpolation points of source (Y) and target (X) cell
FPoint X[nnodes], Y[nnodes];
// set roots of target cell (X)
TensorType::setRoots(FPoint(0.,0.,0.), CellWidth, X);
// allocate memory and compute 316 m2l operators
FReal *_C;
FComplexe *_FC;
// reduce storage from nnodes^2=order^6 to (2order-1)^3
const unsigned int rc = (2*order-1)*(2*order-1)*(2*order-1);
_C = new FReal [rc];
_FC = new FComplexe [rc * ninteractions];
// initialize root node ids pairs
unsigned int node_ids_pairs[rc][2];
TensorType::setNodeIdsPairs(node_ids_pairs);
// init Discrete Fourier Transformator
// FDft Dft(rc);
FFft<1> Dft(rc);
// get first column of K via permutation
unsigned int perm[rc];
TensorType::setStoragePermutation(perm);
unsigned int counter = 0;
for (int i=-3; i<=3; ++i) {
for (int j=-3; j<=3; ++j) {
for (int k=-3; k<=3; ++k) {
if (abs(i)>1 || abs(j)>1 || abs(k)>1) {
// set roots of source cell (Y)
const FPoint cy(CellWidth*FReal(i), CellWidth*FReal(j), CellWidth*FReal(k));
FUnifTensor<order>::setRoots(cy, CellWidth, Y);
// evaluate m2l operator
unsigned int ido=0;
for(unsigned int l=0; l<2*order-1; ++l)
for(unsigned int m=0; m<2*order-1; ++m)
for(unsigned int n=0; n<2*order-1; ++n){
// store value at current position in C
// use permutation if DFT is used because
// the storage of the first column is required
// i.e. C[0] C[rc-1] C[rc-2] .. C[1] < WRONG!
// i.e. C[rc-1] C[0] C[1] .. C[rc-2] < RIGHT!
// _C[counter*rc + ido]
_C[perm[ido]]
= MatrixKernel->evaluate(X[node_ids_pairs[ido][0]],
Y[node_ids_pairs[ido][1]]);
ido++;
}
// Apply Discrete Fourier Transformation
Dft.applyDFT(_C,_FC+counter*rc);
// increment interaction counter
counter++;
}
}
}
}
if (counter != ninteractions)
throw std::runtime_error("Number of interactions must correspond to 316");
// Free _C
delete [] _C;
// store FC
counter = 0;
// reduce storage if real valued kernel
const unsigned int opt_rc = rc/2+1;
// allocate M2L
FC = new FComplexe[343 * opt_rc];
for (int i=-3; i<=3; ++i)
for (int j=-3; j<=3; ++j)
for (int k=-3; k<=3; ++k) {
const unsigned int idx = (i+3)*7*7 + (j+3)*7 + (k+3);
if (abs(i)>1 || abs(j)>1 || abs(k)>1) {
FBlas::c_copy(opt_rc, reinterpret_cast<FReal*>(_FC + counter*rc),
reinterpret_cast<FReal*>(FC + idx*opt_rc));
// for (unsigned int n=0; n<rc; ++n){
// FC[idx*rc+n]=_FC[counter*rc+n];
// }
counter++;
} else{
FBlas::c_setzero(opt_rc, reinterpret_cast<FReal*>(FC + idx*opt_rc));
// for (unsigned int n=0; n<rc; ++n){
// FC[idx*rc+n]=FComplexe(0.0,0.0);
// }
}
}
if (counter != ninteractions)
throw std::runtime_error("Number of interactions must correspond to 316");
delete [] _FC;
}
/**
......@@ -49,15 +163,17 @@
*
* @tparam ORDER interpolation order \f$\ell\f$
*/
template <int ORDER, class MatrixKernelClass>
class FUnifM2LHandler : FNoCopyable
template <int ORDER, KERNEL_FUNCTION_TYPE TYPE> class FUnifM2LHandler;
/*! Specialization for homogeneous kernel functions */
template <int ORDER>
class FUnifM2LHandler<ORDER,HOMOGENEOUS> : FNoCopyable
{
enum {order = ORDER,
nnodes = TensorTraits<ORDER>::nnodes,
ninteractions = 316, // 7^3 - 3^3 (max num cells in far-field)
rc = (2*ORDER-1)*(2*ORDER-1)*(2*ORDER-1)};
const MatrixKernelClass MatrixKernel;
FComplexe *FC;
......@@ -75,20 +191,25 @@ class FUnifM2LHandler : FNoCopyable
{
const char precision_type = (typeid(FReal)==typeid(double) ? 'd' : 'f');
std::stringstream stream;
stream << "m2l_k"<< MatrixKernelClass::Identifier << "_" << precision_type
stream << "m2l_k"/*<< MatrixKernelClass::Identifier*/ << "_" << precision_type
<< "_o" << order << ".bin";
return stream.str();
}
public:
FUnifM2LHandler()
: MatrixKernel(), FC(NULL),
template <typename MatrixKernelClass>
FUnifM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int, const FReal)
: FC(NULL),
opt_rc(rc/2+1),
Dft(rc) // initialize Discrete Fourier Transformator
{
// initialize root node ids
TensorType::setNodeIdsDiff(node_diff);
// Compute and Set M2L Operators
ComputeAndSet(MatrixKernel);
}
~FUnifM2LHandler()
......@@ -99,14 +220,16 @@ public:
/**
* Computes and sets the matrix \f$C_t\f$
*/
void ComputeAndSet()
template <typename MatrixKernelClass>
void ComputeAndSet(const MatrixKernelClass *const MatrixKernel)
{
// measure time
FTic time; time.tic();
// check if aready set
if (FC) throw std::runtime_error("M2L operator already set");
if (FC) throw std::runtime_error("M2L operator already set");
// Compute matrix of interactions
Compute(FC);
const FReal ReferenceCellWidth = FReal(2.);
Compute<order>(MatrixKernel,ReferenceCellWidth,FC);
// Compute memory usage
unsigned long sizeM2L = 343*opt_rc*sizeof(FComplexe);
......@@ -116,33 +239,6 @@ public:
std::cout << "Compute and Set M2L operators ("<< long(sizeM2L/**1e-6*/) <<" Bytes) in "
<< time.tacAndElapsed() << "sec." << std::endl;
}
/**
* Computes, writes to binary file, reads it and sets the matrices \f$Y, C_t, B\f$
*/
void ComputeAndStoreInBinaryFileAndReadFromFileAndSet()
{
FUnifM2LHandler<ORDER,MatrixKernelClass>::ComputeAndStoreInBinaryFile();
this->ReadFromBinaryFileAndSet();
}
/**
* Computes all \f$K_t\f$.
*
* @param[out] C matrix of size \f$r\times 316 r\f$ storing \f$[C_1,\dots,C_{316}]\f$
*/
static void Compute(FComplexe* &FC);
/**
* Computes and stores the matrix \f$C_t\f$ in a binary
* file
*/
static void ComputeAndStoreInBinaryFile();
/**
* Reads the matrices \f$Y, C_t, B\f$ from the respective binary file
*/
void ReadFromBinaryFileAndSet();
/**
......@@ -178,10 +274,9 @@ public:
* @param[out] FX transformed local expansion
* @param[in] CellWidth needed for the scaling of the compressed M2L operators which are based on a homogeneous matrix kernel computed for the reference cell width \f$w=2\f$, ie in \f$[-1,1]^3\f$.
*/
void applyFC(const unsigned int idx, FReal CellWidth,
const FComplexe *const FY, FComplexe *const FX) const
void applyFC(const unsigned int idx, const unsigned int, const FReal scale,
const FComplexe *const FY, FComplexe *const FX) const
{
const FReal scale(MatrixKernel.getScaleFactor(CellWidth));
FComplexe tmpFX;
......@@ -232,225 +327,181 @@ public:
};
/*! Specialization for non-homogeneous kernel functions */
template <int ORDER>
class FUnifM2LHandler<ORDER,NON_HOMOGENEOUS> : FNoCopyable
{
enum {order = ORDER,
nnodes = TensorTraits<ORDER>::nnodes,
ninteractions = 316, // 7^3 - 3^3 (max num cells in far-field)
rc = (2*ORDER-1)*(2*ORDER-1)*(2*ORDER-1)};
// Homogeneity specific
FComplexe** FC;
const unsigned int TreeHeight;
const FReal RootCellWidth;
// for real valued kernel only n/2+1 complex values are stored
// after performing the DFT (the rest is deduced by conjugation)
unsigned int opt_rc;
//////////////////////////////////////////////////////////////////////
// definition ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
typedef FUnifTensor<ORDER> TensorType;
unsigned int node_diff[nnodes*nnodes];
// FDft Dft; // Direct Discrete Fourier Transformator
FFft<1> Dft; // Fast Discrete Fourier Transformator
template <int ORDER, class MatrixKernelClass>
void
FUnifM2LHandler<ORDER, MatrixKernelClass>::Compute(FComplexe* &FC)
{
// allocate memory and store compressed M2L operators
if (FC) throw std::runtime_error("M2L operators are already set");
static const std::string getFileName()
{
const char precision_type = (typeid(FReal)==typeid(double) ? 'd' : 'f');
std::stringstream stream;
stream << "m2l_k"/*<< MatrixKernelClass::Identifier*/ << "_" << precision_type
<< "_o" << order << ".bin";
return stream.str();
}
// interpolation points of source (Y) and target (X) cell
FPoint X[nnodes], Y[nnodes];
// set roots of target cell (X)
FUnifTensor<order>::setRoots(FPoint(0.,0.,0.), FReal(2.), X);
// init matrix kernel
const MatrixKernelClass MatrixKernel;