Commit b26fd3c1 authored by Quentin Khan's avatar Quentin Khan

Update Chebyshev kernel interface to use the new data organisation

 - Remove virtual FMM operators overloads from the abstract base class.

 - Divide the FChebCell inner data layout into two sub-types:
   multipole_t and local_expansion_t. Two class attribute are accessible
   through the `getMultipoledata` and `getLocalExpansionData` methods.

 - Even out files indentation.

 - Change FMM operators signature to take advantage of the new
   layout. The operators only take as parameters the data they may need
   instead of the whole cell. For instance (simplified):

   void M2M(CellClass* parent, CellClass** children);

   becomes

   void M2M(multipole_t*  parent_m,    symbolic_data_t* parent_s,
            multipole_t** children_ms, symbolic_data_t* children_ss);
parent d0ba4c57
...@@ -122,50 +122,6 @@ public: ...@@ -122,50 +122,6 @@ public:
const InterpolatorClass * getPtrToInterpolator() const const InterpolatorClass * getPtrToInterpolator() const
{ return Interpolator.getPtr(); } { return Interpolator.getPtr(); }
virtual void P2M(CellClass* const LeafCell,
const ContainerClass* const SourceParticles) = 0;
virtual void M2M(CellClass* const FRestrict ParentCell,
const CellClass*const FRestrict *const FRestrict ChildCells,
const int TreeLevel) = 0;
virtual void M2L(CellClass* const FRestrict TargetCell,
const CellClass* SourceCells[],
const int SourcePositions[],
const int NumSourceCells,
const int TreeLevel) = 0;
virtual void L2L(const CellClass* const FRestrict ParentCell,
CellClass* FRestrict *const FRestrict ChildCells,
const int TreeLevel) = 0;
virtual void L2P(const CellClass* const LeafCell,
ContainerClass* const TargetParticles) = 0;
virtual void P2P(const FTreeCoordinate& /* LeafCellCoordinate */, // needed for periodic boundary conditions
ContainerClass* const FRestrict TargetParticles,
const ContainerClass* const FRestrict /*SourceParticles*/,
ContainerClass* const NeighborSourceParticles[],
const int SourcePositions[],
const int /* size */) = 0;
virtual void P2POuter(const FTreeCoordinate& inLeafPosition,
ContainerClass* const FRestrict targets,
ContainerClass* const directNeighborsParticles[], const int neighborPositions[],
const int size) = 0;
virtual void P2PRemote(const FTreeCoordinate& /*inPosition*/,
ContainerClass* const FRestrict inTargets, const ContainerClass* const FRestrict /*inSources*/,
const ContainerClass* const inNeighbors[], const int SourcePositions[], const int /*inSize*/) = 0;
}; };
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
// This software is a computer program whose purpose is to compute the FMM. // This software is a computer program whose purpose is to compute the FMM.
// //
// This software is governed by the CeCILL-C and LGPL licenses and // This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software. // abiding by the rules of distribution of free software.
// //
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public and CeCILL-C Licenses for more details. // GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info". // "http://www.cecill.info".
// "http://www.gnu.org/licenses". // "http://www.gnu.org/licenses".
// =================================================================================== // ===================================================================================
#ifndef FCHEBCELL_HPP #ifndef FCHEBCELL_HPP
...@@ -37,35 +37,89 @@ class FChebCell : public FBasicCell, public FAbstractSendable ...@@ -37,35 +37,89 @@ class FChebCell : public FBasicCell, public FAbstractSendable
// we multiply by 2 because we store the Multipole expansion end the compressed one. // we multiply by 2 because we store the Multipole expansion end the compressed one.
static const int VectorSize = TensorTraits<ORDER>::nnodes * 2; static const int VectorSize = TensorTraits<ORDER>::nnodes * 2;
FReal multipole_exp[NRHS * NVALS * VectorSize]; //< Multipole expansion
FReal local_exp[NLHS * NVALS * VectorSize]; //< Local expansion
public: public:
FChebCell(){
memset(multipole_exp, 0, sizeof(FReal) * NRHS * NVALS * VectorSize); struct multipole_t {
memset(local_exp, 0, sizeof(FReal) * NLHS * NVALS * VectorSize); FReal multipole_exp[NRHS * NVALS * VectorSize]; //< Multipole expansion
const FReal* getMultipole(const int inRhs) const
{ return this->multipole_exp + inRhs*VectorSize; }
FReal* getMultipole(const int inRhs)
{ return this->multipole_exp + inRhs*VectorSize; }
constexpr int getVectorSize() const {
return VectorSize;
}
// to extend FAbstractSendable
template <class BufferWriterClass>
void serialize(BufferWriterClass& buffer) const{
buffer.write(this->multipole_exp, VectorSize*NVALS*NRHS);
}
template <class BufferReaderClass>
void deserialize(BufferReaderClass& buffer){
buffer.fillArray(this->multipole_exp, VectorSize*NVALS*NRHS);
}
void reset() {
memset(multipole_exp, 0, sizeof(FReal) * NRHS * NVALS * VectorSize);
}
};
struct local_expansion_t {
FReal local_exp[NLHS * NVALS * VectorSize]; //< Local expansion
const FReal* getLocal(const int inRhs) const
{ return this->local_exp + inRhs*VectorSize; }
FReal* getLocal(const int inRhs)
{ return this->local_exp + inRhs*VectorSize; }
constexpr int getVectorSize() const {
return VectorSize;
}
// to extend FAbstractSendable
template <class BufferWriterClass>
void serialize(BufferWriterClass& buffer) const{
buffer.write(this->local_exp, VectorSize*NVALS*NLHS);
}
template <class BufferReaderClass>
void deserialize(BufferReaderClass& buffer){
buffer.fillArray(this->local_exp, VectorSize*NVALS*NLHS);
}
void reset() {
memset(local_exp, 0, sizeof(FReal) * NLHS * NVALS * VectorSize);
}
};
multipole_t m_data {};
local_expansion_t l_data {};
bool hasMultipoleData() const noexcept {
return true;
}
bool hasLocalExpansionData() const noexcept {
return true;
} }
~FChebCell() {}
/** Get Multipole */ multipole_t& getMultipoleData() noexcept {
const FReal* getMultipole(const int inRhs) const return m_data;
{ return this->multipole_exp + inRhs*VectorSize;
} }
/** Get Local */ const multipole_t& getMultipoleData() const noexcept {
const FReal* getLocal(const int inRhs) const{ return m_data;
return this->local_exp + inRhs*VectorSize;
} }
/** Get Multipole */ local_expansion_t& getLocalExpansionData() noexcept {
FReal* getMultipole(const int inRhs){ return l_data;
return this->multipole_exp + inRhs*VectorSize;
} }
/** Get Local */ const local_expansion_t& getLocalExpansionData() const noexcept {
FReal* getLocal(const int inRhs){ return l_data;
return this->local_exp + inRhs*VectorSize;
} }
/** To get the leading dim of a vec */ /** To get the leading dim of a vec */
int getVectorSize() const{ int getVectorSize() const{
return VectorSize; return VectorSize;
...@@ -73,8 +127,8 @@ public: ...@@ -73,8 +127,8 @@ public:
/** Make it like the begining */ /** Make it like the begining */
void resetToInitialState(){ void resetToInitialState(){
memset(multipole_exp, 0, sizeof(FReal) * NRHS * NVALS * VectorSize); m_data.reset();
memset(local_exp, 0, sizeof(FReal) * NLHS * NVALS * VectorSize); l_data.reset();
} }
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
...@@ -82,20 +136,20 @@ public: ...@@ -82,20 +136,20 @@ public:
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
template <class BufferWriterClass> template <class BufferWriterClass>
void serializeUp(BufferWriterClass& buffer) const{ void serializeUp(BufferWriterClass& buffer) const{
buffer.write(multipole_exp, VectorSize*NVALS*NRHS); m_data.serialize(buffer);
} }
template <class BufferReaderClass> template <class BufferReaderClass>
void deserializeUp(BufferReaderClass& buffer){ void deserializeUp(BufferReaderClass& buffer){
buffer.fillArray(multipole_exp, VectorSize*NVALS*NRHS); m_data.deserialize(buffer);
} }
template <class BufferWriterClass> template <class BufferWriterClass>
void serializeDown(BufferWriterClass& buffer) const{ void serializeDown(BufferWriterClass& buffer) const{
buffer.write(local_exp, VectorSize*NVALS*NLHS); l_data.serialize(buffer);
} }
template <class BufferReaderClass> template <class BufferReaderClass>
void deserializeDown(BufferReaderClass& buffer){ void deserializeDown(BufferReaderClass& buffer){
buffer.fillArray(local_exp, VectorSize*NVALS*NLHS); l_data.deserialize(buffer);
} }
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
...@@ -104,14 +158,14 @@ public: ...@@ -104,14 +158,14 @@ public:
template <class BufferWriterClass> template <class BufferWriterClass>
void save(BufferWriterClass& buffer) const{ void save(BufferWriterClass& buffer) const{
FBasicCell::save(buffer); FBasicCell::save(buffer);
buffer.write(multipole_exp, VectorSize*NVALS*NRHS); m_data.serialize(buffer);
buffer.write(local_exp, VectorSize*NVALS*NLHS); l_data.serialize(buffer);
} }
template <class BufferReaderClass> template <class BufferReaderClass>
void restore(BufferReaderClass& buffer){ void restore(BufferReaderClass& buffer){
FBasicCell::restore(buffer); FBasicCell::restore(buffer);
buffer.fillArray(multipole_exp, VectorSize*NVALS*NRHS); m_data.deserialize(buffer);
buffer.fillArray(local_exp, VectorSize*NVALS*NLHS); l_data.deserialize(buffer);
} }
FSize getSavedSize() const { FSize getSavedSize() const {
...@@ -172,5 +226,3 @@ public: ...@@ -172,5 +226,3 @@ public:
}; };
#endif //FCHEBCELL_HPP #endif //FCHEBCELL_HPP
...@@ -83,38 +83,48 @@ public: ...@@ -83,38 +83,48 @@ public:
} }
void P2M(CellClass* const LeafCell, template<class SymbolicData>
void P2M(typename CellClass::multipole_t* const LeafMultipole,
const SymbolicData* const LeafSymbData,
const ContainerClass* const SourceParticles) const ContainerClass* const SourceParticles)
override
{ {
const FPoint<FReal> LeafCellCenter(AbstractBaseClass::getLeafCellCenter(LeafCell->getCoordinate())); int leafLevel = static_cast<int>(LeafSymbData->getLevel());
FReal leafBoxWidth = AbstractBaseClass::BoxWidth / FReal(1 << leafLevel);
const FPoint<FReal> LeafCellCenter(
AbstractBaseClass::getCellCenter(LeafSymbData->getCoordinate(),
leafLevel));
// 1) apply Sy // 1) apply Sy
AbstractBaseClass::Interpolator->applyP2M(LeafCellCenter, AbstractBaseClass::BoxWidthLeaf, AbstractBaseClass::Interpolator->applyP2M(LeafCellCenter, leafBoxWidth,
LeafCell->getMultipole(0), SourceParticles); LeafMultipole->getMultipole(0), SourceParticles);
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){ for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
// 2) apply B // 2) apply B
M2LHandler->applyB(LeafCell->getMultipole(idxRhs), LeafCell->getMultipole(idxRhs) + AbstractBaseClass::nnodes); M2LHandler->applyB(LeafMultipole->getMultipole(idxRhs),
LeafMultipole->getMultipole(idxRhs) + AbstractBaseClass::nnodes);
} }
} }
void M2M(CellClass* const FRestrict ParentCell, template<class SymbolicData>
const CellClass*const FRestrict *const FRestrict ChildCells, void M2M(typename CellClass::multipole_t * const FRestrict ParentMultipole,
const int /*TreeLevel*/) const SymbolicData* const /*ParentSymb*/,
override const typename CellClass::multipole_t * const FRestrict * const FRestrict ChildMultipoles,
const SymbolicData* const /*ChildSymbs*/[])
{ {
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){ for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
// 1) apply Sy // 1) apply Sy
for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){ for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){
if (ChildCells[ChildIndex]){ if (ChildMultipoles[ChildIndex]){
AbstractBaseClass::Interpolator->applyM2M(ChildIndex, ChildCells[ChildIndex]->getMultipole(idxRhs), AbstractBaseClass::Interpolator->applyM2M(
ParentCell->getMultipole(idxRhs)); ChildIndex, ChildMultipoles[ChildIndex]->getMultipole(idxRhs),
ParentMultipole->getMultipole(idxRhs));
} }
} }
// 2) apply B // 2) apply B
M2LHandler->applyB(ParentCell->getMultipole(idxRhs), ParentCell->getMultipole(idxRhs) + AbstractBaseClass::nnodes); M2LHandler->applyB(ParentMultipole->getMultipole(idxRhs),
ParentMultipole->getMultipole(idxRhs) + AbstractBaseClass::nnodes);
} }
} }
...@@ -137,16 +147,22 @@ public: ...@@ -137,16 +147,22 @@ public:
// } // }
// } // }
void M2L(CellClass* const FRestrict TargetCell, const CellClass* SourceCells[], template<class SymbolicData>
const int neighborPositions[], const int inSize, const int TreeLevel) void M2L(typename CellClass::local_expansion_t * const FRestrict TargetExpansion,
override const SymbolicData* const TargetSymb,
const typename CellClass::multipole_t * const FRestrict SourceMultipoles[],
const SymbolicData* const FRestrict /*SourceSymbs*/[],
const int neighborPositions[],
const int inSize)
{ {
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){ for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
FReal *const CompressedLocalExpansion = TargetCell->getLocal(idxRhs) + AbstractBaseClass::nnodes; FReal *const CompressedLocalExpansion = TargetExpansion->getLocal(idxRhs) + AbstractBaseClass::nnodes;
const FReal CellWidth(AbstractBaseClass::BoxWidth / FReal(FMath::pow(2, TreeLevel))); const FReal CellWidth(AbstractBaseClass::BoxWidth / FReal(1 << TargetSymb->getLevel()));
for(int idxExistingNeigh = 0 ; idxExistingNeigh < inSize ; ++idxExistingNeigh){ for(int idxExistingNeigh = 0 ; idxExistingNeigh < inSize ; ++idxExistingNeigh){
const int idx = neighborPositions[idxExistingNeigh]; const int idx = neighborPositions[idxExistingNeigh];
M2LHandler->applyC(idx, CellWidth, SourceCells[idxExistingNeigh]->getMultipole(idxRhs) + AbstractBaseClass::nnodes, M2LHandler->applyC(idx, CellWidth,
SourceMultipoles[idxExistingNeigh]->getMultipole(idxRhs)
+ AbstractBaseClass::nnodes,
CompressedLocalExpansion); CompressedLocalExpansion);
} }
} }
...@@ -166,33 +182,44 @@ public: ...@@ -166,33 +182,44 @@ public:
// } // }
void L2L(const CellClass* const FRestrict ParentCell, template<class SymbolicData>
CellClass* FRestrict *const FRestrict ChildCells, void L2L(const typename CellClass::local_expansion_t * const FRestrict ParentExpansion,
const int /*TreeLevel*/) const SymbolicData* const /*ParentSymb*/,
override typename CellClass::local_expansion_t * FRestrict *const FRestrict ChildExpansions,
const SymbolicData* const /*ChildSymbs*/[])
{ {
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){ for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
// 1) apply U // 1) apply U
M2LHandler->applyU(ParentCell->getLocal(idxRhs) + AbstractBaseClass::nnodes, M2LHandler->applyU(ParentExpansion->getLocal(idxRhs) + AbstractBaseClass::nnodes,
const_cast<CellClass*>(ParentCell)->getLocal(idxRhs)); const_cast<typename CellClass::local_expansion_t*>(ParentExpansion)->getLocal(idxRhs));
// 2) apply Sx // 2) apply Sx
for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){ for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){
if (ChildCells[ChildIndex]){ if (ChildExpansions[ChildIndex]){
AbstractBaseClass::Interpolator->applyL2L(ChildIndex, ParentCell->getLocal(idxRhs), ChildCells[ChildIndex]->getLocal(idxRhs)); AbstractBaseClass::Interpolator->applyL2L(
ChildIndex,
ParentExpansion->getLocal(idxRhs),
ChildExpansions[ChildIndex]->getLocal(idxRhs));
} }
} }
} }
} }
void L2P(const CellClass* const LeafCell, template<class SymbolicData>
void L2P(const typename CellClass::local_expansion_t* const LeafExpansion,
const SymbolicData* const LeafSymb,
ContainerClass* const TargetParticles) ContainerClass* const TargetParticles)
override
{ {
const FPoint<FReal> LeafCellCenter(AbstractBaseClass::getLeafCellCenter(LeafCell->getCoordinate())); int leafLevel = static_cast<int>(LeafSymb->getLevel());
FReal leafBoxWidth = AbstractBaseClass::BoxWidth / FReal(1 << leafLevel);
const FPoint<FReal> LeafCellCenter(
AbstractBaseClass::getCellCenter(LeafSymb->getCoordinate(),
leafLevel));
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){ for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
// 1) apply U // 1) apply U
M2LHandler->applyU(LeafCell->getLocal(idxRhs) + AbstractBaseClass::nnodes, const_cast<CellClass*>(LeafCell)->getLocal(idxRhs)); M2LHandler->applyU(LeafExpansion->getLocal(idxRhs) + AbstractBaseClass::nnodes,
const_cast<typename CellClass::local_expansion_t*>(LeafExpansion)->getLocal(idxRhs));
} }
//// 2.a) apply Sx //// 2.a) apply Sx
...@@ -207,8 +234,8 @@ public: ...@@ -207,8 +234,8 @@ public:
// TargetParticles); // TargetParticles);
// 2.c) apply Sx and Px (grad Sx) // 2.c) apply Sx and Px (grad Sx)
AbstractBaseClass::Interpolator->applyL2PTotal(LeafCellCenter, AbstractBaseClass::BoxWidthLeaf, AbstractBaseClass::Interpolator->applyL2PTotal(LeafCellCenter, leafBoxWidth,
LeafCell->getLocal(0), TargetParticles); LeafExpansion->getLocal(0), TargetParticles);
} }
......
...@@ -95,6 +95,8 @@ protected: ...@@ -95,6 +95,8 @@ protected:
assert(Mul[idx]==nullptr || Loc[idx]==nullptr); assert(Mul[idx]==nullptr || Loc[idx]==nullptr);
Mul[idx] = new FReal [24 * nnodes]; Mul[idx] = new FReal [24 * nnodes];
Loc[idx] = new FReal [24 * nnodes]; Loc[idx] = new FReal [24 * nnodes];
memset(Mul[idx], 0, 24 * nnodes * sizeof(FReal));
memset(Loc[idx], 0, 24 * nnodes * sizeof(FReal));
} }
} }
...@@ -178,30 +180,37 @@ public: ...@@ -178,30 +180,37 @@ public:
void P2M(CellClass* const LeafCell, template<class SymbolicData>
const ContainerClass* const SourceParticles/*, const int level = AbstractBaseClass::TreeHeight*/) void P2M(typename CellClass::multipole_t* const LeafCell,
override const SymbolicData* const LeafSymbData,
const ContainerClass* const SourceParticles)
{ {
// apply Sy // apply Sy
const FPoint<FReal> LeafCellCenter(AbstractBaseClass::getLeafCellCenter(LeafCell->getCoordinate())); const FPoint<FReal> LeafCellCenter =
AbstractBaseClass::Interpolator->applyP2M(LeafCellCenter, AbstractBaseClass::BoxWidthLeaf, AbstractBaseClass::getLeafCellCenter(LeafSymbData->getCoordinate());
FReal leafBoxWidth = AbstractBaseClass::BoxWidth / FReal(1 << LeafSymbData->getLevel());
AbstractBaseClass::Interpolator->applyP2M(LeafCellCenter, leafBoxWidth,
LeafCell->getMultipole(0), SourceParticles); LeafCell->getMultipole(0), SourceParticles);
} }
void M2M(CellClass* const FRestrict ParentCell, template<class SymbolicData>
const CellClass*const FRestrict *const FRestrict ChildCells, void M2M(typename CellClass::multipole_t * const FRestrict ParentMultipole,
const int /*TreeLevel*/) const SymbolicData* const /*ParentSymb*/,
override const typename CellClass::multipole_t * const FRestrict * const FRestrict ChildMultipoles,
const SymbolicData* const /*ChildSymbs*/[])
{ {
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){ for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
// Reset the Parent expansion to zero // Reset the Parent expansion to zero
// FBlas::scal(nnodes*2, FReal(0.), ParentCell->getMultipole(idxRhs)); // FBlas::scal(nnodes*2, FReal(0.), ParentMultipole->getMultipole(idxRhs));
for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){ for (unsigned int ChildIndex=0; ChildIndex < 8; ++ChildIndex){
// apply Sy // apply Sy
if (ChildCells[ChildIndex]){ if (ChildMultipoles[ChildIndex]){
AbstractBaseClass::Interpolator->applyM2M(ChildIndex, ChildCells[ChildIndex]->getMultipole(idxRhs), ParentCell->getMultipole(idxRhs)); AbstractBaseClass::Interpolator->applyM2M(
ChildIndex, ChildMultipoles[ChildIndex]->getMultipole(idxRhs),
ParentMultipole->getMultipole(idxRhs));
} }
} }
} }
...@@ -209,8 +218,14 @@ public: ...@@ -209,8 +218,14 @@ public:
void M2L(CellClass* const FRestrict TargetCell, const CellClass* SourceCells[], template<class SymbolicData>
const int neighborPositions[], const int inSize, const int TreeLevel) override { void M2L(typename CellClass::local_expansion_t * const FRestrict TargetExpansion,
const SymbolicData* const TargetSymb,
const typename CellClass::multipole_t * const FRestrict SourceMultipoles[],
const SymbolicData* const FRestrict /*SourceSymbs*/[],
const int neighborPositions[],
const int inSize)
{
#ifdef LOG_TIMINGS #ifdef LOG_TIMINGS
time.tic(); time.tic();
#endif #endif
...@@ -223,7 +238,7 @@ public: ...@@ -223,7 +238,7 @@ public:
const unsigned int count = (countExp[pidx])++; const unsigned int count = (countExp[pidx])++;
FReal *const mul = Mul[pidx] + count*nnodes; FReal *const mul = Mul[pidx] + count*nnodes;
const unsigned int *const pvec = SymHandler->pvectors[idx]; const unsigned int *const pvec = SymHandler->pvectors[idx];
const FReal *const MultiExp = SourceCells[idxExistingNeigh]->getMultipole(idxRhs); const FReal *const MultiExp = SourceMultipoles[idxExistingNeigh]->getMultipole(idxRhs);