Commit bd46ede9 authored by BRAMAS Berenger's avatar BRAMAS Berenger
parents d407ea90 ce4ebe2b
......@@ -117,7 +117,7 @@ public:
/**
*@brief Set the buffer capacity
*@param incapacity to change the capacity
*@param inCapacity to change the capacity
* If capacity given is lower than size elements after capacity are removed
*/
void setCapacity(const int inCapacity) {
......
......@@ -29,6 +29,7 @@ class FTreeCsvSaver {
public:
/** Constructor
* @param inBasefile is the output file name, you must put %d in it
* @param inIncludeHeader tells if header must be included
*/
FTreeCsvSaver(const char inBasefile[], const bool inIncludeHeader = false)
: includeHeader(inIncludeHeader), nbFrames(0) {
......
......@@ -27,9 +27,11 @@ class FTreeMpiCsvSaver {
static const int SizeOfLine = 56;
public:
/** Constructor
* @param inBasefile is the output file name, you must put %d in it
*/
/** Constructor
* @param inBasefile is the output file name, you must put %d in it
* @param communicator Mpi communicator
* @param inIncludeHeader tells if header must be included
*/
FTreeMpiCsvSaver(const char inBasefile[], const FMpi::FComm& communicator, const bool inIncludeHeader = false)
: comm(communicator.getComm()), includeHeader(inIncludeHeader), nbFrames(0) {
strcpy(basefile, inBasefile);
......
......@@ -11,13 +11,12 @@
#include "./FChebInterpolator.hpp"
class FTreeCoordinate;
template <KERNEL_FUNCCTION_IDENTIFIER Identifier> struct DirectInteactionComputer;
/**
* @author Matthias Messner(matthias.messner@inria.fr)
* @class FAbstractChebKernel
* @brief
* Please read the license
*
* This kernels implement the Chebyshev interpolation based FMM operators. It
* implements all interfaces (P2P, P2M, M2M, M2L, L2L, L2P) which are required by
* the FFmmAlgorithm and FFmmAlgorithmThread.
......@@ -127,7 +126,7 @@ public:
while (iSources.hasNotFinished()) {
const ParticleClass& Source = iSources.data();
// only if target and source are not identical
this->directInteraction(Target, Source);
DirectInteactionComputer<MatrixKernelClass::Identifier>::compute(Target, Source);
// progress sources
iSources.gotoNext();
}
......@@ -140,7 +139,7 @@ public:
while (iSources.hasNotFinished()) {
const ParticleClass& Source = iSources.data();
// target and source cannot be identical
this->directInteraction(Target, Source);
DirectInteactionComputer<MatrixKernelClass::Identifier>::compute(Target, Source);
// progress sources
iSources.gotoNext();
}
......@@ -163,7 +162,7 @@ public:
while (iSources.hasNotFinished()) {
ParticleClass& Source = iSources.data();
// only if target and source are not identical
this->directInteractionMutual(Target, Source);
DirectInteactionComputer<MatrixKernelClass::Identifier>::computeMutual(Target, Source);
// progress sources
iSources.gotoNext();
}
......@@ -176,7 +175,7 @@ public:
while (iSources.hasNotFinished()) {
ParticleClass& Source = iSources.data();
// target and source cannot be identical
this->directInteractionMutual(Target, Source);
DirectInteactionComputer<MatrixKernelClass::Identifier>::computeMutual(Target, Source);
// progress sources
iSources.gotoNext();
}
......@@ -192,10 +191,15 @@ public:
}
};
private:
void directInteraction(ParticleClass& Target, const ParticleClass& Source) const // 34 overall flops
/*! Specialization for Laplace potential */
template <>
struct DirectInteactionComputer<ONE_OVER_R>
{
template <typename ParticleClass>
static void compute(ParticleClass& Target, const ParticleClass& Source) // 34 overall flops
{
FPoint xy(Source.getPosition() - Target.getPosition()); // 3 flops
const FReal one_over_r = FReal(1.) / FMath::Sqrt(xy.getX()*xy.getX() +
......@@ -203,14 +207,17 @@ private:
xy.getZ()*xy.getZ()); // 1 + 15 + 5 = 21 flops
const FReal wt = Target.getPhysicalValue();
const FReal ws = Source.getPhysicalValue();
// potential
// laplace potential
Target.incPotential(one_over_r * ws); // 2 flops
// force
xy *= ((ws*wt) * (one_over_r*one_over_r*one_over_r)); // 5 flops
Target.incForces(xy.getX(), xy.getY(), xy.getZ()); // 3 flops
}
void directInteractionMutual(ParticleClass& Target, ParticleClass& Source) const // 39 overall flops
template <typename ParticleClass>
static void computeMutual(ParticleClass& Target, ParticleClass& Source) // 39 overall flops
{
FPoint xy(Source.getPosition() - Target.getPosition()); // 3 flops
const FReal one_over_r = FReal(1.) / FMath::Sqrt(xy.getX()*xy.getX() +
......@@ -218,18 +225,70 @@ private:
xy.getZ()*xy.getZ()); // 1 + 15 + 5 = 21 flops
const FReal wt = Target.getPhysicalValue();
const FReal ws = Source.getPhysicalValue();
// potential
// laplace potential
Target.incPotential(one_over_r * ws); // 2 flops
Source.incPotential(one_over_r * wt); // 2 flops
// force
xy *= ((ws*wt) * (one_over_r*one_over_r*one_over_r)); // 5 flops
Target.incForces( xy.getX(), xy.getY(), xy.getZ()); // 3 flops
Source.incForces((-xy.getX()), (-xy.getY()), (-xy.getZ())); // 3 flops
}
};
/*! Specialization for Leonard-Jones potential */
template <>
struct DirectInteactionComputer<LEONARD_JONES_POTENTIAL>
{
template <typename ParticleClass>
static void compute(ParticleClass& Target, const ParticleClass& Source) // 39 overall flops
{
FPoint xy(Source.getPosition() - Target.getPosition()); // 3 flops
const FReal one_over_r = FReal(1.) / FMath::Sqrt(xy.getX()*xy.getX() +
xy.getY()*xy.getY() +
xy.getZ()*xy.getZ()); // 1 + 15 + 5 = 21 flops
const FReal wt = Target.getPhysicalValue();
const FReal ws = Source.getPhysicalValue();
// lenard-jones potential
const FReal one_over_r3 = one_over_r * one_over_r * one_over_r;
const FReal one_over_r6 = one_over_r3 * one_over_r3;
Target.incPotential((one_over_r6*one_over_r6 - one_over_r6) * ws); // 2 flops
// force
const FReal one_over_r4 = one_over_r3 * one_over_r; // 1 flop
xy *= ((ws*wt) * (FReal(12.)*one_over_r6*one_over_r4*one_over_r4 - FReal(6.)*one_over_r4*one_over_r4)); // 9 flops
Target.incForces(xy.getX(), xy.getY(), xy.getZ()); // 3 flops
}
template <typename ParticleClass>
static void computeMutual(ParticleClass& Target, ParticleClass& Source) // 44 overall flops
{
FPoint xy(Source.getPosition() - Target.getPosition()); // 3 flops
const FReal one_over_r = FReal(1.) / FMath::Sqrt(xy.getX()*xy.getX() +
xy.getY()*xy.getY() +
xy.getZ()*xy.getZ()); // 1 + 15 + 5 = 21 flops
const FReal wt = Target.getPhysicalValue();
const FReal ws = Source.getPhysicalValue();
// lenard-jones potential
const FReal one_over_r3 = one_over_r * one_over_r * one_over_r;
const FReal one_over_r6 = one_over_r3 * one_over_r3;
Target.incPotential((one_over_r6*one_over_r6 - one_over_r6) * ws); // 2 flops
Source.incPotential((one_over_r6*one_over_r6 - one_over_r6) * wt); // 2 flops
// force
const FReal one_over_r4 = one_over_r3 * one_over_r; // 1 flop
xy *= ((ws*wt) * (FReal(12.)*one_over_r6*one_over_r4*one_over_r4 - FReal(6.)*one_over_r4*one_over_r4)); // 9 flops
Target.incForces( xy.getX(), xy.getY(), xy.getZ()); // 3 flops
Source.incForces((-xy.getX()), (-xy.getY()), (-xy.getZ())); // 3 flops
}
};
#endif //FCHEBKERNELS_HPP
// [--END--]
......@@ -5,10 +5,16 @@
#include "../../Utils/FPoint.hpp"
#include "../../Utils/FNoCopyable.hpp"
#include "../../Utils/FMath.hpp"
#include "../../Utils/FBlas.hpp"
enum {ONE_OVER_R = 1,
ONE_OVER_R_SQUARED = 2};
// extendable
enum KERNEL_FUNCCTION_IDENTIFIER {ONE_OVER_R,
ONE_OVER_R_SQUARED,
LEONARD_JONES_POTENTIAL};
// probably not extedable :)
enum KERNEL_FUNCTION_TYPE {HOMOGENEOUS, NON_HOMOGENEOUS};
/**
......@@ -19,14 +25,21 @@ enum {ONE_OVER_R = 1,
struct FChebAbstractMatrixKernel : FNoCopyable
{
virtual FReal evaluate(const FPoint&, const FPoint&) const = 0;
virtual FReal getScaleFactor(FReal) const = 0;
// I need both functions because required arguments are not always given
virtual FReal getScaleFactor(const FReal, const int) const = 0;
virtual FReal getScaleFactor(const FReal) const = 0;
};
/// One over r
struct FChebMatrixKernelR : FChebAbstractMatrixKernel
{
enum {Identifier = ONE_OVER_R};
static const KERNEL_FUNCTION_TYPE Type = HOMOGENEOUS;
static const KERNEL_FUNCCTION_IDENTIFIER Identifier = ONE_OVER_R;
FChebMatrixKernelR() {}
FReal evaluate(const FPoint& x, const FPoint& y) const
{
const FPoint xy(x-y);
......@@ -35,15 +48,28 @@ struct FChebMatrixKernelR : FChebAbstractMatrixKernel
xy.getZ()*xy.getZ());
}
FReal getScaleFactor(FReal CellWidth) const
{ return FReal(2.) / CellWidth; }
FReal getScaleFactor(const FReal RootCellWidth, const int TreeLevel) const
{
const FReal CellWidth(RootCellWidth / FReal(FMath::pow(2, TreeLevel)));
return getScaleFactor(CellWidth);
}
FReal getScaleFactor(const FReal CellWidth) const
{
return FReal(2.) / CellWidth;
}
};
/// One over r^2
struct FChebMatrixKernelRR : FChebAbstractMatrixKernel
{
enum {Identifier = ONE_OVER_R_SQUARED};
static const KERNEL_FUNCTION_TYPE Type = HOMOGENEOUS;
static const KERNEL_FUNCCTION_IDENTIFIER Identifier = ONE_OVER_R_SQUARED;
FChebMatrixKernelRR() {}
FReal evaluate(const FPoint& x, const FPoint& y) const
{
const FPoint xy(x-y);
......@@ -52,11 +78,123 @@ struct FChebMatrixKernelRR : FChebAbstractMatrixKernel
xy.getZ()*xy.getZ());
}
FReal getScaleFactor(FReal CellWidth) const
{ return FReal(4.) / (CellWidth*CellWidth); }
FReal getScaleFactor(const FReal RootCellWidth, const int TreeLevel) const
{
const FReal CellWidth(RootCellWidth / FReal(FMath::pow(2, TreeLevel)));
return getScaleFactor(CellWidth);
}
FReal getScaleFactor(const FReal CellWidth) const
{
return FReal(4.) / CellWidth;
}
};
/// One over r^12 - One over r^6
struct FChebMatrixKernelLJ : FChebAbstractMatrixKernel
{
static const KERNEL_FUNCTION_TYPE Type = NON_HOMOGENEOUS;
static const KERNEL_FUNCCTION_IDENTIFIER Identifier = LEONARD_JONES_POTENTIAL;
FChebMatrixKernelLJ() {}
FReal evaluate(const FPoint& x, const FPoint& y) const
{
const FPoint xy(x-y);
const FReal r = xy.norm();
const FReal r3 = r*r*r;
const FReal one_over_r6 = FReal(1.) / (r3*r3);
//return one_over_r6 * one_over_r6;
//return one_over_r6;
return one_over_r6 * one_over_r6 - one_over_r6;
}
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.);
}
};
/*! Functor which provides the interface to assemble a matrix based on the
number of rows and cols and on the coordinates x and y and the type of the
generating matrix-kernel function.
*/
template <typename MatrixKernel>
class EntryComputer
{
const MatrixKernel Kernel;
const unsigned int nx, ny;
const FPoint *const px, *const py;
const FReal *const weights;
public:
explicit EntryComputer(const unsigned int _nx, const FPoint *const _px,
const unsigned int _ny, const FPoint *const _py,
const FReal *const _weights = NULL)
: Kernel(), nx(_nx), ny(_ny), px(_px), py(_py), weights(_weights) {}
// template <typename Point>
// void operator()(const unsigned int nx, const Point *const px,
// const unsigned int ny, const Point *const py,
// FReal *const data) const
// {
// for (unsigned int j=0; j<ny; ++j)
// for (unsigned int i=0; i<nx; ++i)
// data[j*nx + i] = Kernel.evaluate(px[i], py[j]);
// }
void operator()(const unsigned int xbeg, const unsigned int xend,
const unsigned int ybeg, const unsigned int yend,
FReal *const data) const
{
unsigned int idx = 0;
if (weights) {
for (unsigned int j=ybeg; j<yend; ++j)
for (unsigned int i=xbeg; i<xend; ++i)
data[idx++] = weights[i] * weights[j] * Kernel.evaluate(px[i], py[j]);
} else {
for (unsigned int j=ybeg; j<yend; ++j)
for (unsigned int i=xbeg; i<xend; ++i)
data[idx++] = Kernel.evaluate(px[i], py[j]);
}
/*
// apply weighting matrices
if (weights) {
if ((xend-xbeg) == (yend-ybeg) && (xend-xbeg) == nx)
for (unsigned int n=0; n<nx; ++n) {
FBlas::scal(nx, weights[n], data + n, nx); // scale rows
FBlas::scal(nx, weights[n], data + n * nx); // scale cols
}
else if ((xend-xbeg) == 1 && (yend-ybeg) == ny)
for (unsigned int j=0; j<ny; ++j) data[j] *= weights[j];
else if ((yend-ybeg) == 1 && (xend-xbeg) == nx)
for (unsigned int i=0; i<nx; ++i) data[i] *= weights[i];
}
*/
}
};
#endif // FCHEBMATRIXKERNEL_HPP
// [--END--]
......@@ -13,6 +13,9 @@
class FTreeCoordinate;
/// for verbosity only!!!
//#define COUNT_BLOCKED_INTERACTIONS
/**
* @author Matthias Messner(matthias.messner@inria.fr)
......@@ -36,7 +39,7 @@ class FChebSymKernel
: public FAbstractChebKernel<ParticleClass, CellClass, ContainerClass, MatrixKernelClass, ORDER>
{
typedef FAbstractChebKernel<ParticleClass, CellClass, ContainerClass, MatrixKernelClass, ORDER> AbstractBaseClass;
typedef SymmetryHandler<ORDER> SymmetryHandlerClass;
typedef SymmetryHandler<ORDER, MatrixKernelClass::Type> SymmetryHandlerClass;
enum {nnodes = AbstractBaseClass::nnodes};
/// Needed for handling all symmetries
......@@ -88,7 +91,7 @@ public:
const FReal inBoxWidth,
const FReal Epsilon)
: AbstractBaseClass(inTreeHeight, inBoxCenter, inBoxWidth),
SymHandler(new SymmetryHandlerClass(AbstractBaseClass::MatrixKernel.getPtr(), Epsilon)),
SymHandler(new SymmetryHandlerClass(AbstractBaseClass::MatrixKernel.getPtr(), Epsilon, inBoxWidth, inTreeHeight)),
Loc(NULL), Mul(NULL), countExp(NULL)
{
this->allocateMemoryForPermutedExpansions();
......@@ -153,7 +156,6 @@ public:
void M2L(CellClass* const FRestrict TargetCell,
const CellClass* SourceCells[343],
const int NumSourceCells,
......@@ -173,20 +175,38 @@ public:
}
}
#ifdef COUNT_BLOCKED_INTERACTIONS ////////////////////////////////////
unsigned int count_lidx = 0;
unsigned int count_interactions = 0;
for (unsigned int idx=0; idx<343; ++idx)
count_interactions += countExp[idx];
if (count_interactions==189) {
for (unsigned int idx=0; idx<343; ++idx) {
if (countExp[idx])
std::cout << "gidx = " << idx << " gives lidx = " << count_lidx++ << " and has "
<< countExp[idx] << " interactions" << std::endl;
}
std::cout << std::endl;
}
#endif ///////////////////////////////////////////////////////////////
// multiply (mat-mat-mul)
FReal Compressed [nnodes * 24];
const FReal CellWidth(AbstractBaseClass::BoxWidth / FReal(FMath::pow(2, TreeLevel)));
const FReal scale(AbstractBaseClass::MatrixKernel->getScaleFactor(CellWidth));
const FReal scale = AbstractBaseClass::MatrixKernel->getScaleFactor(AbstractBaseClass::BoxWidth, TreeLevel);
for (unsigned int pidx=0; pidx<343; ++pidx) {
const unsigned int count = countExp[pidx];
if (count) {
const unsigned int rank = SymHandler->LowRank[pidx];
const unsigned int rank = SymHandler->getLowRank(TreeLevel, pidx);
// rank * count * (2*nnodes-1) flops
FBlas::gemtm(nnodes, rank, count, FReal(1.),
SymHandler->K[pidx]+rank*nnodes, nnodes, Mul[pidx], nnodes, Compressed, rank);
const_cast<FReal*>(SymHandler->getK(TreeLevel, pidx))+rank*nnodes,
nnodes, Mul[pidx], nnodes, Compressed, rank);
// nnodes *count * (2*rank-1) flops
FBlas::gemm( nnodes, rank, count, scale,
SymHandler->K[pidx], nnodes, Compressed, rank, Loc[pidx], nnodes);
const_cast<FReal*>(SymHandler->getK(TreeLevel, pidx)),
nnodes, Compressed, rank, Loc[pidx], nnodes);
}
}
......@@ -207,6 +227,8 @@ public:
}
/*
void M2L(CellClass* const FRestrict TargetCell,
const CellClass* SourceCells[343],
......@@ -345,19 +367,6 @@ public:
#endif //FCHEBSYMKERNELS_HPP
......
......@@ -38,10 +38,11 @@ protected:
* @param inMessage a message - from any type - to print
* @param inLinePosition line number
* @param inFilePosition file name
* @param inExitCode an exit code
*
* @code
* fassert(toto == titi, "problem : toto is not equal titi!", __LINE__, __FILE__);
* @endcode
* @code
* fassert(toto == titi, "problem : toto is not equal titi!", __LINE__, __FILE__);
* @endcode
* To prevent use from multiple thread we use a ostringstream before printing
*/
template <class Tmess, class Tline, class Tfile>
......
......@@ -20,24 +20,25 @@
*/
namespace FParameters{
/** If it is not found */
const static int NotFound = -1;
/**
* This function gives a parameter in a standart type
* @parameter inArg parameter position has to be strictly less than argc/userParemetersCount
* @return argv[inArg] in the template VariableType form
* @warning VariableType need to work with istream >> operator
* <code> const int argInt = userParemetersAt<int>(1,-1); </code>
*/
template <class VariableType>
const VariableType StrToOther(const char* const str, const VariableType& defaultValue = VariableType()){
std::istringstream iss(str,std::istringstream::in);
VariableType value;
iss >> value;
if( /*iss.tellg()*/ iss.eof() ) return value;
return defaultValue;
}
/** If it is not found */
const static int NotFound = -1;
/**
* This function gives a parameter in a standart type
* @param str string of chars to be converted from
* @param defaultValue the value to be converted to
* @return argv[inArg] in the template VariableType form
* @warning VariableType need to work with istream >> operator
* <code> const int argInt = userParemetersAt<int>(1,-1); </code>
*/
template <class VariableType>
const VariableType StrToOther(const char* const str, const VariableType& defaultValue = VariableType()){
std::istringstream iss(str,std::istringstream::in);
VariableType value;
iss >> value;
if( /*iss.tellg()*/ iss.eof() ) return value;
return defaultValue;
}
/** To put a char into lower format
*
*/
......
......@@ -80,12 +80,8 @@ int main(int argc, char* argv[])
const unsigned int SubTreeHeight = FParameters::getValue(argc, argv, "-sh", 2);
const unsigned int NbThreads = FParameters::getValue(argc, argv, "-t", 1);
const unsigned int ORDER = 7;
const FReal epsilon = FReal(1e-7);
//// set threads
//omp_set_num_threads(NbThreads);
//std::cout << "Using " << omp_get_max_threads() << " threads." << std::endl;
const unsigned int ORDER = 9;
const FReal epsilon = FReal(1e-9);
// init timer
FTic time;
......@@ -95,6 +91,7 @@ int main(int argc, char* argv[])
typedef FChebParticle ParticleClass;
typedef FVector<FChebParticle> ContainerClass;
typedef FChebLeaf<ParticleClass,ContainerClass> LeafClass;
//typedef FChebMatrixKernelLJ MatrixKernelClass;
typedef FChebMatrixKernelR MatrixKernelClass;
typedef FChebCell<ORDER> CellClass;
typedef FOctree<ParticleClass,CellClass,ContainerClass,LeafClass> OctreeClass;
......@@ -171,7 +168,7 @@ int main(int argc, char* argv[])
{
omp_set_num_threads(NbThreads);
std::cout << "\nChebyshev FMM using" << omp_get_max_threads() << " threads ..." << std::endl;
std::cout << "\nChebyshev FMM using " << omp_get_max_threads() << " threads ..." << std::endl;
KernelClass kernels(TreeHeight, loader.getCenterOfBox(), loader.getBoxWidth(), epsilon);
FmmClass algorithm(&tree, &kernels);
time.tic();
......@@ -235,17 +232,31 @@ int main(int argc, char* argv[])
ContainerClass::ConstBasicIterator iSource(*Sources);
while(iSource.hasNotFinished()) {
if (&iTarget.data() != &iSource.data()) {
const FReal one_over_r = MatrixKernel.evaluate(iTarget.data().getPosition(),
const FReal potential_value = MatrixKernel.evaluate(iTarget.data().getPosition(),
iSource.data().getPosition());
const FReal ws = iSource.data().getPhysicalValue();
// potential
Potential[counter] += one_over_r * ws;
Potential[counter] += potential_value * ws;
// force
FPoint force(iSource.data().getPosition() - iTarget.data().getPosition());
force *= ((ws*wt) * (one_over_r*one_over_r*one_over_r));
Force[counter*3 + 0] += force.getX();
Force[counter*3 + 1] += force.getY();
Force[counter*3 + 2] += force.getZ();
if (MatrixKernelClass::Identifier == ONE_OVER_R) { // laplace force
FPoint force(iSource.data().getPosition() - iTarget.data().getPosition());
force *= ((ws*wt) * (potential_value*potential_value*potential_value));
Force[counter*3 + 0] += force.getX();
Force[counter*3 + 1] += force.getY();
Force[counter*3 + 2] += force.getZ();
} else if (MatrixKernelClass::Identifier == LEONARD_JONES_POTENTIAL) { // lenard-jones force
FPoint force(iSource.data().getPosition() - iTarget.data().getPosition());
const FReal one_over_r = FReal(1.) / FMath::Sqrt(force.getX()*force.getX() +
force.getY()*force.getY() +
force.getZ()*force.getZ()); // 1 + 15 + 5 = 21 flops
const FReal one_over_r3 = one_over_r * one_over_r * one_over_r;
const FReal one_over_r6 = one_over_r3 * one_over_r3;
const FReal one_over_r4 = one_over_r3 * one_over_r;
force *= ((ws*wt) * (FReal(12.)*one_over_r6*one_over_r4*one_over_r4 - FReal(6.)*one_over_r4*one_over_r4));
Force[counter*3 + 0] += force.getX();
Force[counter*3 + 1] += force.getY();
Force[counter*3 + 2] += force.getZ();
}
}
iSource.gotoNext();
}
......
// ===================================================================================
// Ce LOGICIEL "ScalFmm" est couvert par le copyright Inria 20xx-2012.
// Inria détient tous les droits de propriété sur le LOGICIEL, et souhaite que
// la communauté scientifique l'utilise afin de le tester et de l'évaluer.
// Inria donne gracieusement le droit d'utiliser ce LOGICIEL. Toute utilisation
// dans un but lucratif ou à des fins commerciales est interdite sauf autorisation
// expresse et préalable d'Inria.
// Toute utilisation hors des limites précisées ci-dessus et réalisée sans l'accord
// expresse préalable d'Inria constituerait donc le délit de contrefaçon.
// Le LOGICIEL étant un produit en cours de développement, Inria ne saurait assurer
// aucune responsabilité et notamment en aucune manière et en aucun cas, être tenu
// de répondre d'éventuels dommages directs ou indirects subits par l'utilisateur.
// Tout utilisateur du LOGICIEL s'engage à communiquer à Inria ses remarques
// relatives à l'usage du LOGICIEL
// ===================================================================================
// ==== CMAKE =====
// @FUSE_BLAS
// ================
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "../../Src/Utils/FTic.hpp"
#include "../../Src/Utils/FMath.hpp"
#include "../../Src/Utils/FPoint.hpp"
#include "../../Src/Kernels/Chebyshev/FChebMatrixKernel.hpp"
#include "../../Src/Kernels/Chebyshev/FChebRoots.hpp"
#include "../../Src/Kernels/Chebyshev/FChebTensor.hpp"
#include "../../Src/Kernels/Chebyshev/FChebSymM2LHandler.hpp"