Commit 370adb44 authored by BLANCHARD Pierre's avatar BLANCHARD Pierre

Introduced the concept of extended bounding box in ChebyshevTensorial kernel...

Introduced the concept of extended bounding box in ChebyshevTensorial kernel (ONLY supported for NON_HOMOGENEOUS kernels yet) and provided corresponding tests for interpolator.
parent 45834df4
......@@ -59,6 +59,9 @@ protected:
const FReal BoxWidth;
/// Width of a leaf cell box
const FReal BoxWidthLeaf;
/// Extension of the box width ( same for all level! )
const FReal BoxWidthExtension;
/// Parameter to pass to matrix kernel (material specific or anything)
const double MatParam;
......@@ -83,13 +86,17 @@ public:
FAbstractChebKernel(const int inTreeHeight,
const FReal inBoxWidth,
const FPoint& inBoxCenter,
const FReal inBoxWidthExtension = 0.0,
const double inMatParam = 0.0)
: Interpolator(new InterpolatorClass()),
: Interpolator(new InterpolatorClass(inTreeHeight,
inBoxWidth,
inBoxWidthExtension)),
MatrixKernel(new MatrixKernelClass(inMatParam)),
TreeHeight(inTreeHeight),
BoxCorner(inBoxCenter - inBoxWidth / FReal(2.)),
BoxWidth(inBoxWidth),
BoxWidthLeaf(BoxWidth / FReal(FMath::pow(2, inTreeHeight - 1))),
BoxWidthExtension(inBoxWidthExtension),
MatParam(inMatParam)
{
/* empty */
......
This diff is collapsed.
......@@ -71,12 +71,14 @@ public:
FChebTensorialKernel(const int inTreeHeight,
const FReal inBoxWidth,
const FPoint& inBoxCenter,
const FReal inBoxWidthExtension,
const FReal Epsilon,
const double inMatParam = 0.0)
: FAbstractChebKernel< CellClass, ContainerClass, MatrixKernelClass, ORDER, NVALS>(inTreeHeight,inBoxWidth,inBoxCenter,inMatParam),
: FAbstractChebKernel< CellClass, ContainerClass, MatrixKernelClass, ORDER, NVALS>(inTreeHeight,inBoxWidth,inBoxCenter,inBoxWidthExtension,inMatParam),
M2LHandler(new M2LHandlerClass(AbstractBaseClass::MatrixKernel.getPtr(),
inTreeHeight,
inBoxWidth,
inBoxWidthExtension,
Epsilon))
{ }
......@@ -85,11 +87,13 @@ public:
const ContainerClass* const SourceParticles)
{
const FPoint LeafCellCenter(AbstractBaseClass::getLeafCellCenter(LeafCell->getCoordinate()));
const FReal ExtendedLeafCellWidth(AbstractBaseClass::BoxWidthLeaf
+ AbstractBaseClass::BoxWidthExtension);
for(int idxV = 0 ; idxV < NVALS ; ++idxV){
// 1) apply Sy
AbstractBaseClass::Interpolator->applyP2M(LeafCellCenter, AbstractBaseClass::BoxWidthLeaf,
AbstractBaseClass::Interpolator->applyP2M(LeafCellCenter, ExtendedLeafCellWidth,
LeafCell->getMultipole(idxV*nRhs), SourceParticles);
for(int idxRhs = 0 ; idxRhs < nRhs ; ++idxRhs){
......@@ -106,7 +110,7 @@ public:
void M2M(CellClass* const FRestrict ParentCell,
const CellClass*const FRestrict *const FRestrict ChildCells,
const int /*TreeLevel*/)
const int TreeLevel)
{
for(int idxV = 0 ; idxV < NVALS ; ++idxV){
for(int idxRhs = 0 ; idxRhs < nRhs ; ++idxRhs){
......@@ -117,8 +121,10 @@ public:
FBlas::scal(AbstractBaseClass::nnodes*2, FReal(0.), ParentCell->getMultipole(idxMul));
for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){
if (ChildCells[ChildIndex]){
AbstractBaseClass::Interpolator->applyM2M(ChildIndex, ChildCells[ChildIndex]->getMultipole(idxMul),
ParentCell->getMultipole(idxMul));
AbstractBaseClass::Interpolator->applyM2M(ChildIndex,
ChildCells[ChildIndex]->getMultipole(idxMul),
ParentCell->getMultipole(idxMul),
TreeLevel/*Cell width extension specific*/);
}
}
......@@ -134,8 +140,10 @@ public:
const int /*NumSourceCells*/,
const int TreeLevel)
{
// scale factor for homogeneous case
const FReal CellWidth(AbstractBaseClass::BoxWidth / FReal(FMath::pow(2, TreeLevel)));
const FReal scale(AbstractBaseClass::MatrixKernel.getPtr()->getScaleFactor(CellWidth));
const FReal ExtendedCellWidth(CellWidth + AbstractBaseClass::BoxWidthExtension);
const FReal scale(AbstractBaseClass::MatrixKernel.getPtr()->getScaleFactor(ExtendedCellWidth));
for(int idxV = 0 ; idxV < NVALS ; ++idxV){
for (int idxLhs=0; idxLhs < nLhs; ++idxLhs){
......@@ -167,7 +175,7 @@ public:
void L2L(const CellClass* const FRestrict ParentCell,
CellClass* FRestrict *const FRestrict ChildCells,
const int /*TreeLevel*/)
const int TreeLevel)
{
for(int idxV = 0 ; idxV < NVALS ; ++idxV){
for(int idxLhs = 0 ; idxLhs < nLhs ; ++idxLhs){
......@@ -179,7 +187,10 @@ public:
// 2) apply Sx
for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){
if (ChildCells[ChildIndex]){
AbstractBaseClass::Interpolator->applyL2L(ChildIndex, ParentCell->getLocal(idxLoc), ChildCells[ChildIndex]->getLocal(idxLoc));
AbstractBaseClass::Interpolator->applyL2L(ChildIndex,
ParentCell->getLocal(idxLoc),
ChildCells[ChildIndex]->getLocal(idxLoc),
TreeLevel/*Cell width extension specific*/);
}
}
}//NLHS
......@@ -191,6 +202,8 @@ public:
ContainerClass* const TargetParticles)
{
const FPoint LeafCellCenter(AbstractBaseClass::getLeafCellCenter(LeafCell->getCoordinate()));
const FReal ExtendedLeafCellWidth(AbstractBaseClass::BoxWidthLeaf
+ AbstractBaseClass::BoxWidthExtension);
for(int idxV = 0 ; idxV < NVALS ; ++idxV){
for(int idxLhs = 0 ; idxLhs < nLhs ; ++idxLhs){
......@@ -213,7 +226,7 @@ public:
// TargetParticles);
// 2.c) apply Sx and Px (grad Sx)
AbstractBaseClass::Interpolator->applyL2PTotal(LeafCellCenter, AbstractBaseClass::BoxWidthLeaf,
AbstractBaseClass::Interpolator->applyL2PTotal(LeafCellCenter, ExtendedLeafCellWidth,
LeafCell->getLocal(idxV*nLhs), TargetParticles);
}
}
......
......@@ -66,15 +66,9 @@ unsigned int ComputeAndCompress(const MatrixKernelClass *const MatrixKernel,
* 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 ?!
* PB: BEWARE! Homogeneous matrix kernels do not support cell width extension
* yet. Is it possible to find a reference width and a scale factor such that
* only 1 set of M2L ops can be used for all levels??
*
* @tparam ORDER interpolation order \f$\ell\f$
*/
......@@ -94,6 +88,8 @@ class FChebTensorialM2LHandler<ORDER,MatrixKernelClass,HOMOGENEOUS> : FNoCopyabl
FReal *U, *B;
FReal** C;
const FReal CellWidthExtension; //<! extension of cells width
const FReal epsilon; //<! accuracy which determines trucation of SVD
unsigned int rank; //<! truncation rank, satisfies @p epsilon
......@@ -109,12 +105,13 @@ class FChebTensorialM2LHandler<ORDER,MatrixKernelClass,HOMOGENEOUS> : FNoCopyabl
public:
FChebTensorialM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int, const FReal, const FReal _epsilon)
: U(nullptr), B(nullptr), epsilon(_epsilon), rank(0)
FChebTensorialM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int, const FReal, const FReal inCellWidthExtension, const FReal _epsilon)
: U(nullptr), B(nullptr), CellWidthExtension(inCellWidthExtension),
epsilon(_epsilon), rank(0)
{
// measure time
FTic time; time.tic();
// check if aready set
// check if already set
if (U||B) throw std::runtime_error("U or B operator already set");
// allocate C
......@@ -126,8 +123,11 @@ public:
if (C[d]) throw std::runtime_error("Compressed M2L operator already set");
// Compute matrix of interactions
// reference cell width is arbitrarly set to 2.
// but it NEEDS to match the numerator of the scale factor in matrix kernel!
// Therefore box width extension is not yet supported for homog kernels
const FReal ReferenceCellWidth = FReal(2.);
rank = ComputeAndCompress<order>(MatrixKernel, ReferenceCellWidth, epsilon, U, C, B);
rank = ComputeAndCompress<order>(MatrixKernel, ReferenceCellWidth, 0., epsilon, U, C, B);
unsigned long sizeM2L = 343*ncmp*rank*rank*sizeof(FReal);
......@@ -210,8 +210,9 @@ class FChebTensorialM2LHandler<ORDER,MatrixKernelClass,NON_HOMOGENEOUS> : FNoCop
FReal **U, **B;
FReal*** C;
const unsigned int TreeHeight;
const FReal RootCellWidth;
const unsigned int TreeHeight; //<! number of levels
const FReal RootCellWidth; //<! width of root cell
const FReal CellWidthExtension; //<! extension of cells width
const FReal epsilon; //<! accuracy which determines trucation of SVD
unsigned int *rank; //<! truncation rank, satisfies @p epsilon
......@@ -228,9 +229,10 @@ class FChebTensorialM2LHandler<ORDER,MatrixKernelClass,NON_HOMOGENEOUS> : FNoCop
public:
FChebTensorialM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int inTreeHeight, const FReal inRootCellWidth, const FReal _epsilon)
FChebTensorialM2LHandler(const MatrixKernelClass *const MatrixKernel, const unsigned int inTreeHeight, const FReal inRootCellWidth, const FReal inCellWidthExtension, const FReal _epsilon)
: TreeHeight(inTreeHeight),
RootCellWidth(inRootCellWidth),
CellWidthExtension(inCellWidthExtension),
epsilon(_epsilon)
{
// measure time
......@@ -265,7 +267,9 @@ public:
CellWidth /= FReal(2.); // at level 2
rank[0]=rank[1]=0;
for (unsigned int l=2; l<TreeHeight; ++l) {
rank[l] = ComputeAndCompress<order>(MatrixKernel, CellWidth, epsilon, U[l], C[l], B[l]);
// compute m2l operator on extended cell
rank[l] = ComputeAndCompress<order>(MatrixKernel, CellWidth, CellWidthExtension, epsilon, U[l], C[l], B[l]);
// update cell width
CellWidth /= FReal(2.); // at level l+1
}
unsigned long sizeM2L = (TreeHeight-2)*343*ncmp*rank[2]*rank[2]*sizeof(FReal);
......@@ -354,6 +358,7 @@ public:
template <int ORDER, class MatrixKernelClass>
unsigned int ComputeAndCompress(const MatrixKernelClass *const MatrixKernel,
const FReal CellWidth,
const FReal CellWidthExtension,
const FReal epsilon,
FReal* &U,
FReal** &C,
......@@ -372,7 +377,8 @@ unsigned int ComputeAndCompress(const MatrixKernelClass *const MatrixKernel,
// interpolation points of source (Y) and target (X) cell
FPoint X[nnodes], Y[nnodes];
// set roots of target cell (X)
FChebTensor<order>::setRoots(FPoint(0.,0.,0.), CellWidth, X);
const FReal ExtendedCellWidth(CellWidth+CellWidthExtension);
FChebTensor<order>::setRoots(FPoint(0.,0.,0.), ExtendedCellWidth, X);
// allocate memory and compute 316 m2l operators
FReal** _C;
......@@ -387,14 +393,13 @@ unsigned int ComputeAndCompress(const MatrixKernelClass *const MatrixKernel,
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));
FChebTensor<order>::setRoots(cy, CellWidth, Y);
FChebTensor<order>::setRoots(cy, ExtendedCellWidth, Y);
// evaluate m2l operator
for (unsigned int n=0; n<nnodes; ++n)
for (unsigned int m=0; m<nnodes; ++m){
// _C[counter*nnodes*nnodes + n*nnodes + m]
// = MatrixKernel.evaluate(X[m], Y[n]);
// Compute current M2L interaction (block matrix)
// Compute current M2L interaction (block matrix)
FReal* block;
block = new FReal[ncmp];
MatrixKernel->evaluateBlock(X[m], Y[n], block);
......
......@@ -52,6 +52,10 @@ enum KERNEL_FUNCTION_TYPE {HOMOGENEOUS, NON_HOMOGENEOUS};
* The table applyTab provides the indices in the reduced storage table
* corresponding to the application scheme depicted ealier.
*
* PB: BEWARE! Homogeneous matrix kernels do not support cell width extension
* yet. Is it possible to find a reference width and a scale factor such that
* only 1 set of M2L ops can be used for all levels??
*
*/
struct FInterpAbstractMatrixKernel : FNoCopyable
{
......
......@@ -128,10 +128,12 @@ public:
*
* @param[in] ChildIndex index of child according to Morton index
* @param[out] center
* @param[in] ExtendedCellRatio ratio between extended child and parent widths
*/
static
void setRelativeChildCenter(const unsigned int ChildIndex,
FPoint& ChildCenter)
FPoint& ChildCenter,
const FReal ExtendedCellRatio=FReal(.5))
{
const int RelativeChildPositions[][3] = { {-1, -1, -1},
{-1, -1, 1},
......@@ -141,9 +143,12 @@ public:
{ 1, -1, 1},
{ 1, 1, -1},
{ 1, 1, 1} };
ChildCenter.setX(FReal(RelativeChildPositions[ChildIndex][0]) / FReal(2.));
ChildCenter.setY(FReal(RelativeChildPositions[ChildIndex][1]) / FReal(2.));
ChildCenter.setZ(FReal(RelativeChildPositions[ChildIndex][2]) / FReal(2.));
// Translate center if cell widths are extended
const FReal frac = (1. - ExtendedCellRatio);
ChildCenter.setX(FReal(RelativeChildPositions[ChildIndex][0]) * frac);
ChildCenter.setY(FReal(RelativeChildPositions[ChildIndex][1]) * frac);
ChildCenter.setZ(FReal(RelativeChildPositions[ChildIndex][2]) * frac);
}
};
......
......@@ -181,6 +181,20 @@ int main(int argc, char* argv[])
// accuracy
const unsigned int ORDER = 5 ;
const FReal epsilon = FReal(1e-5);
// set box width extension
// ... either deduce from element size
const FReal LeafCellWidth = FReal(loader.getBoxWidth()) / FReal(FMath::pow(2.,TreeHeight-1));
const FReal ElementSize = LeafCellWidth / FReal(3.);
const FReal BoxWidthExtension = ElementSize; // depends on type of element
// ... or set to arbitrary value (0. means no extension)
// const FReal BoxWidthExtension = FReal(0.);
std::cout << "LeafCellWidth=" << LeafCellWidth
<< ", BoxWidthExtension=" << BoxWidthExtension <<std::endl;
// stop execution if interactions are homog and box extension is required
if(MatrixKernelClass::Type==HOMOGENEOUS && BoxWidthExtension>0.)
throw std::runtime_error("Extension of box width is not yet supported for homogeneous kernels! Work-around: artificially set Type to NON_HOMOGENEOUS.");
typedef FP2PParticleContainerIndexed<NRHS,NLHS> ContainerClass;
......@@ -226,7 +240,7 @@ int main(int argc, char* argv[])
{ // -----------------------------------------------------
std::cout << "\nChebyshev FMM (ORDER="<< ORDER << ") ... " << std::endl;
time.tic();
KernelClass kernels(TreeHeight, loader.getBoxWidth(), loader.getCenterOfBox(), epsilon,CoreWidth);
KernelClass kernels(TreeHeight, loader.getBoxWidth(), loader.getCenterOfBox(), BoxWidthExtension, epsilon, CoreWidth);
FmmClass algorithm(&tree, &kernels);
algorithm.execute();
time.tac();
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment