Commit c370ea26 authored by Berenger Bramas's avatar Berenger Bramas

remove FmmApi

parent 89fb25fe
# check if compiling into source directories
STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" insource)
if(insource)
MESSAGE(FATAL_ERROR "${PROJECT_NAME} requires an out of source build. Goto ./Build and tapes cmake ../")
endif(insource)
project(Addons_fmmapi_scalfmm CXX)
ADD_DEFINITIONS( ${ScaLFMM_CXX_FLAGS})
# Active language
# -----------------------
ENABLE_LANGUAGE(CXX )
MESSAGE(STATUS " CXX ${CMAKE_CXX_COMPILER_ID}" )
# Options
OPTION( SCALFMM_ADDON_FMMAPI "Set to ON to build ScaFMM FMM API interface" OFF )
# if ask to build addon
if(SCALFMM_ADDON_FMMAPI)
# first build lib scalfmmapi
set(LIBRARY_OUTPUT_PATH ../lib/${CMAKE_BUILD_TYPE})
# Searching all cpp file
file( GLOB_RECURSE source_lib_files Src/*.cpp )
# Adding cpp files to project
add_library( scalfmmapi ${source_lib_files} )
# Add blas library (even if it is set to off)
target_link_libraries( scalfmmapi scalfmm)
# Adding the entire project dir as an include dir
INCLUDE_DIRECTORIES(
${SCALFMM_BINARY_DIR}/Src
${SCALFMM_SOURCE_DIR}/Src
${SCALFMM_INCLUDES}
)
# Install lib
install( TARGETS scalfmmapi ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
# Install header
SET(my_include_dirs "Src")
file( GLOB hpp_in_dir Src/*.hpp )
INSTALL( FILES ${hpp_in_dir} DESTINATION include/ScalFmm/FmmApi )
file( GLOB_RECURSE source_tests_files Tests/*.cpp )
INCLUDE_DIRECTORIES( ${SCALFMM_BINARY_DIR}/Src )
# Then build test files
foreach(exec ${source_tests_files})
get_filename_component(
execname ${exec}
NAME_WE
)
set(compile_exec "TRUE")
foreach(fuse_key ${FUSE_LIST})
file(STRINGS "${exec}" lines_fuse REGEX "@FUSE_${fuse_key}")
if(lines_fuse)
if( NOT SCALFMM_USE_${fuse_key} )
MESSAGE( STATUS "This needs ${fuse_key} = ${exec}" )
set(compile_exec "FALSE")
endif()
endif()
endforeach()
# Dependency are OK
if( compile_exec )
add_executable( ${execname} ${exec} )
# link to scalfmm and scalfmmapi
target_link_libraries(
${execname}
${scalfmm_lib}
scalfmmapi
${BLAS_LIBRARIES}
${LAPACK_LIBRARIES}
${SCALFMM_LIBRARIES}
)
endif()
endforeach(exec)
endif()
// ===================================================================================
// 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 FMMAPI_H
#define FMMAPI_H
enum FmmApiErrors {
FMMAPI_NO_ERROR,
FMMAPI_SUPPORTED_PARAMETER,
FMMAPI_UNSUPPORTED_PARAMETER,
FMMAPI_UNKNOWN_PARAMETER
};
////////////////////// Opérateurs FMM Core : //////////////////////////
enum FmmApiCoreParameters {
FMMCORE_TREE_HEIGHT, // hombre de niveaux de l'arbre (int)
FMMCORE_ROOT_BOX_WIDTH, // taille de la boîte racine (FReal)
FMMCORE_ROOT_BOX_CENTER, // position du centre de la boîte racine (FReal[3])
FMMCORE_LEAF_BOX_WIDTH, // taille des boîtes feuilles (FReal)
FMMCORE_POINTS_PER_LEAF, // nombre moyen de points par feuille (FReal)
FMMCORE_MPI_COMMUNICATOR, // communicateur MPI (MPI_Comm)
FMMCORE_THREADS_NUMBER, // nombre de threads (int)
FMMCORE_THREAD_ID, // id du thread (int)
FMMCORE_RHS_NUMBER, // nombre de seconds membres (int)
//paramètres en lecture seule :
FMMCORE_HANDLES_P2P // renvoie 0 ou 1 pour dire si le FmmCore gère ou pas le P2P.
};
int FmmCore_init(void **fmmCore) ; /*alloue et initialise le FmmCore*/
int FmmCore_free(void *fmmCore) ; /*libère le FmmCore*/
int FmmCore_isParameterUsed(void */*fmmCore*/, int *name, int *flag);
int FmmCore_setParameter(void *fmmCore, int *name, void*value);
int FmmCore_setParameter(void *fmmCore, int name, void*value);
int FmmCore_getParameter(void *fmmCore, int *name, void*value);
int FmmCore_getParameter(void *fmmCore, int name, void*value);
int FmmCore_getRadius(void*fmmCore, void *boxId, FReal *radius);/*Renvoie le rayon de la boîte*/
int FmmCore_getCentre(void*/*fmmCore*/, void *boxId, FReal **centre); /*Renvoie dans le FReal[3] centre les coordonnées du centre*/
int FmmCore_getLevel(void*/*fmmCore*/, void *boxId, int *level); /*Renvoie dans level le niveau de la boîte boxId dans son arbre*/
int FmmCore_getMultipoleArray(void* /*fmmCore*/, void *boxId, void **F); /*Renvoie dans F l'adresse où stocker l'expansion multipôle associée à la boîte boxId*/
int FmmCore_getLocalArray(void* /*fmmCore*/, void *boxId, void **F); /*Renvoie dans F l'adresse où stocker l'expansion locale associée à la boîte boxId*/
int FmmCore_getCoord(void*/*fmmCore*/, void *boxId, int *coord); /*Renvoie dans coord la position dans l'arbre*/
/* Données potentiel/champ */
int FmmCore_getSource(void* /*fmmCore*/, void *boxId, FReal** position, void** potential, int *number); /* Appelé par P2P et P2M pour obtenir le nombre, la position et le potentiel des sources.
Les différents tableaux sont (éventuellement) alloués par le FmmCore. */
int FmmCore_releaseSource(void*fmmCore, void *boxId, void* potential, FReal* position); /* si le core veut libérer ces tableaux potentiel et position.*/
int FmmCore_getTargetPoints(void* /*fmmCore*/, void *boxId, FReal** position, int *number) ; /* : Appelé par P2P et L2P pour obtenir le nombre et la position des points cibles.*/
int FmmCore_releaseTargetPoints(void*fmmCore, void *boxId, FReal* position); /* si le core veut libérer ce tableau "position".*/
int FmmCore_getTargetField(void* /*fmmCore*/, void *boxId, FReal* F); /* obtient dans un tableau F alloué/libéré par L2P/P2P les valeurs des champs aux points cible
(pour le cas où P2P et L2P doivent sommer leurs résultats).*/
int FmmCore_setTargetField(void* /*fmmCore*/, void *boxId, FReal* F); /* transmets au FmmCore dans F les valeurs des champs aux points cibles mis à jour.*/
/* Entrée/sortie principale */
int FmmCore_setKernelData(void *fmmCore, void *fmmKernel); /* stocke l'identifiant du FmmKernel dans le FmmCore. Cela permet par la suite aux
opérateurs FMM d'accéder au FmmKernel, et donc d'accéder aux données spécifiques au kernel
(p.ex. fréquence dans le cas Helmholtz, …)*/
int FmmCore_getKernelData(void*fmmCore, void **fmmKernel); /* récupère l'identifiant du FmmKernel. */
int FmmCore_setPositions(void *fmmCore, int *nb, FReal *position) ; /* transmet au FmmCore les potentiels associés aux points sources.
Le tableau potential est alloué et libéré par la routine appelant, le FmmCore doit donc en faire une copie.*/
int FmmCore_setPotentials(void *fmmCore, void *potentials); /* transmet au FmmCore les potentiels associés aux points sources.
Le tableau potential est alloué et libéré par la routine appelant, le FmmCore doit donc en faire une copie.*/
int FmmCore_doComputation(void *fmmCore) ; /* réalise le produit multipôle. */
/* !!! Warning use *filed and not **field */
int FmmCore_getField(void *fmmCore, void *fields) ;/* récupère après le produit multipôle la valeur des champs en chaque point.
Le tableau field doit être alloué et libéré par la routine appelante. */
////////////////////// Opérateurs FMM Kernel : //////////////////////////
enum FmmApiKernelParameters {
FMMKERNEL_ACCURACY, // précision demandée à la FMM : 1e-3, 1e-6, ... (FReal)
FMMKERNEL_POTENTIAL_DATA_SIZE, // taille en octet de la donnée "potentiel" pour 1 point source (int)
FMMKERNEL_FIELD_DATA_SIZE, // taille en octet de la donnée "field" pour 1 point cible (int)
//paramètres en lecture seule :
FMMKERNEL_HANDLES_P2P // renvoie 0 ou 1 pour dire si le FmmKernel gère ou pas le P2P.
};
/******* Allocation : ******/
int FmmKernel_init(void *fmmCore, void **fmmKernel);/* : alloue et initialise le FmmKernel */
int FmmKernel_free(void *fmmKernel); /* libére le FmmKernel */
/******* Configuration : ***/
int FmmKernel_isParameterUsed(void * /*fmm*/, int *name, int *flag);
int FmmKernel_setParameter(void *fmmKernel, int *name, void*value);
int FmmKernel_setParameter(void *fmmKernel, int name, void*value);
int FmmKernel_getParameter(void *fmmKernel, int *name, void*value);
int FmmKernel_getParameter(void *fmmKernel, int name, void*value);
/****** Données FMM : *****/
int FmmKernel_getMultipoleArraySize(void *fmmCore, int *size); /* Renvoie dans size la taille (en octets) de l'expansion multipôle associée à la boîte boxId */
int FmmKernel_getLocalArraySize(void *fmmCore, int *size); /* Renvoie dans size la taille (en octets) de l'expansion locale associée à la boîte boxId*/
/******* Opérateurs FMM : **/
int FmmKernel_P2M(void *fmmCore, void* boxId);
int FmmKernel_L2P(void *fmmCore, void* boxId);
int FmmKernel_M2M(void *fmmCore, void *boxIdFather, void *boxIdSon);
int FmmKernel_L2L(void *fmmCore, void *boxIdFather, void *boxIdSon);
int FmmKernel_M2L(void *fmmCore, void *boxIdSrc, void *boxIdDest);
int FmmKernel_P2P_inner(void *fmmCore, void *boxIdSrcDest);
int FmmKernel_P2P(void *fmmCore, void *boxIdSrc, void *boxIdDest); /* pas mutuel, i.e. on fait seulement dans 1 sens. */
#endif // FMMAPI_H
This diff is collapsed.
// ===================================================================================
// 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 "../../Src/Utils/FGlobal.hpp"
#include "../../Src/Utils/FAssert.hpp"
#include "../../Src/Containers/FVector.hpp"
#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Utils/FPoint.hpp"
#include "../../Src/Kernels/Rotation/FRotationCell.hpp"
#include "../../Src/Kernels/Rotation/FRotationKernel.hpp"
#include "../../Src/Kernels/P2P/FP2PParticleContainer.hpp"
#include "FmmApi.h"
////////////////////// Opérateurs FMM Kernel : //////////////////////////
class KernelCell : public FBasicCell {
FComplex<FReal>* multipole;
FComplex<FReal>* local;
public:
KernelCell() : multipole(nullptr), local(nullptr){
}
void attachArrays(FComplex<FReal> inMultipole[], FComplex<FReal> inLocal[]){
multipole = inMultipole;
local = inLocal;
}
const FComplex<FReal>* getMultipole() const{
return multipole;
}
const FComplex<FReal>* getLocal() const{
return local;
}
FComplex<FReal>* getMultipole(){
return multipole;
}
FComplex<FReal>* getLocal(){
return local;
}
};
static const int P = 5;
typedef KernelCell KernelCellClass;
typedef FP2PParticleContainer<FReal> ContainerClass;
typedef FSimpleLeaf<FReal, ContainerClass > LeafClass;
typedef FRotationKernel< KernelCellClass, ContainerClass , P> KernelClass;
struct ScalFmmKernelHandle {
KernelClass** kernel;
int potentialDataSize;
int fieldDataSize;
int nbthread;
};
/******* Allocation : ******/
int FmmKernel_init(void *fmmCore, void **fmmKernel){
ScalFmmKernelHandle* kernelhandle = new ScalFmmKernelHandle;
memset(kernelhandle, 0, sizeof(ScalFmmKernelHandle));
int NbLevels;
FmmCore_getParameter(fmmCore, FMMCORE_TREE_HEIGHT, &NbLevels);
FReal boxWidth;
FmmCore_getParameter(fmmCore, FMMCORE_ROOT_BOX_WIDTH, &boxWidth);
FReal centerOfBox[3];
FmmCore_getParameter(fmmCore, FMMCORE_ROOT_BOX_CENTER, centerOfBox);
FmmCore_getParameter(fmmCore, FMMCORE_THREADS_NUMBER, &kernelhandle->nbthread);
KernelClass original( NbLevels, boxWidth, FPoint<FReal>(centerOfBox) );
kernelhandle->kernel = new KernelClass*[kernelhandle->nbthread];
for(int idxThread = 0 ; idxThread < kernelhandle->nbthread ; ++idxThread){
kernelhandle->kernel[idxThread] = new KernelClass(original);
}
kernelhandle->potentialDataSize = 1;
kernelhandle->fieldDataSize = 4;
*fmmKernel = kernelhandle;
return FMMAPI_NO_ERROR;
}/* : alloue et initialise le FmmKernel */
int FmmKernel_free(void *fmmKernel){
ScalFmmKernelHandle* kernelhandle = (ScalFmmKernelHandle*) fmmKernel;
for(int idxThread = 0 ; idxThread < kernelhandle->nbthread ; ++idxThread){
delete kernelhandle->kernel[idxThread];
}
delete[] kernelhandle->kernel;
delete kernelhandle;
return FMMAPI_NO_ERROR;
} /* libére le FmmKernel */
/******* Configuration : ***/
int FmmKernel_isParameterUsed(void * /*fmm*/, int *name, int *flag){
switch( *name ){
case FMMKERNEL_POTENTIAL_DATA_SIZE:
case FMMKERNEL_FIELD_DATA_SIZE:
case FMMKERNEL_HANDLES_P2P:
*flag = FMMAPI_SUPPORTED_PARAMETER;
break;
case FMMKERNEL_ACCURACY :
*flag = FMMAPI_UNSUPPORTED_PARAMETER;
break;
default:
*flag = FMMAPI_UNKNOWN_PARAMETER;
}
return FMMAPI_NO_ERROR;
}
int FmmKernel_setParameter(void *fmmKernel, int *name, void*value){
/*ScalFmmKernelHandle* kernelhandle = (ScalFmmKernelHandle*) fmmKernel;*/
int flag;
FmmKernel_isParameterUsed(fmmKernel, name, &flag);
if( flag != FMMAPI_SUPPORTED_PARAMETER){
return flag;
}
switch( *name ){
case FMMKERNEL_POTENTIAL_DATA_SIZE :
case FMMKERNEL_FIELD_DATA_SIZE :
return FMMAPI_SUPPORTED_PARAMETER;
default:
return FMMAPI_UNKNOWN_PARAMETER;
}
return FMMAPI_NO_ERROR;
}
int FmmKernel_setParameter(void *fmmKernel, int name, void*value){
return FmmKernel_setParameter( fmmKernel, &name, value);
}
int FmmKernel_getParameter(void *fmmKernel, int *name, void*value){
ScalFmmKernelHandle* kernelhandle = (ScalFmmKernelHandle*) fmmKernel;
int flag;
FmmKernel_isParameterUsed(fmmKernel, name, &flag);
if( flag != FMMAPI_SUPPORTED_PARAMETER){
return flag;
}
switch( *name ){
case FMMKERNEL_POTENTIAL_DATA_SIZE :
*(int*)value = kernelhandle->potentialDataSize*sizeof(FReal);
break;
case FMMKERNEL_FIELD_DATA_SIZE :
*(int*)value = kernelhandle->fieldDataSize*sizeof(FReal);
break;
default:
return FMMAPI_UNKNOWN_PARAMETER;
}
return FMMAPI_NO_ERROR;
}
int FmmKernel_getParameter(void *fmmKernel, int name, void*value){
return FmmKernel_getParameter(fmmKernel, &name, value);
}
/****** Données FMM : *****/
int FmmKernel_getMultipoleArraySize(void */*fmmCore*/, int *size) {
*size = ((P+2)*(P+1))/2 * sizeof(FComplex<FReal>);
return FMMAPI_NO_ERROR;
} /* Renvoie dans size la taille (en octets) de l'expansion multipôle associée à la boîte boxId */
int FmmKernel_getLocalArraySize(void */*fmmCore*/, int *size){
*size = ((P+2)*(P+1))/2 * sizeof(FComplex<FReal>);
return FMMAPI_NO_ERROR;
} /* Renvoie dans size la taille (en octets) de l'expansion locale associée à la boîte boxId*/
/******* Opérateurs FMM : **/
int FmmKernel_P2M(void *fmmCore, void* boxId){
ScalFmmKernelHandle* kernelhandle;
FmmCore_getKernelData(fmmCore, (void**)&kernelhandle);
int threadId;
FmmCore_getParameter(fmmCore, FMMCORE_THREAD_ID, &threadId);
FComplex<FReal>* multipole;
FmmCore_getMultipoleArray(fmmCore, boxId, (void**)&multipole);
KernelCellClass cell;
cell.attachArrays(multipole, nullptr);
int coord[3];
FmmCore_getCoord(fmmCore, boxId, coord);
cell.setCoordinate(coord[0], coord[1], coord[2]);
FReal* positions;
FReal* physicalValues;
int number;
FmmCore_getSource(fmmCore, boxId, &positions, (void**)&physicalValues, &number);
FP2PParticleContainer<FReal> sources;
for(FSize idxPart = 0 ; idxPart < number ; ++idxPart){
sources.push(FPoint<FReal>(positions[idxPart*3],positions[idxPart*3+1],positions[idxPart*3+2]),physicalValues[idxPart]);
}
kernelhandle->kernel[threadId]->P2M(&cell, &sources);
FmmCore_releaseSource(fmmCore, boxId, physicalValues, positions);
return FMMAPI_NO_ERROR;
}
int FmmKernel_L2P(void *fmmCore, void* boxId){
ScalFmmKernelHandle* kernelhandle;
FmmCore_getKernelData(fmmCore, (void**)&kernelhandle);
int threadId;
FmmCore_getParameter(fmmCore, FMMCORE_THREAD_ID, &threadId);
FComplex<FReal>* local;
FmmCore_getLocalArray(fmmCore, boxId, (void**)&local);
KernelCellClass cell;
cell.attachArrays(nullptr,local);
int coord[3];
FmmCore_getCoord(fmmCore, boxId, coord);
cell.setCoordinate(coord[0], coord[1], coord[2]);
FReal* physicalValues;
FReal* positions;
int number;
FmmCore_getSource(fmmCore, boxId, &positions, (void**)&physicalValues, &number);
FReal* fields = new FReal[number*kernelhandle->fieldDataSize];
FmmCore_getTargetField(fmmCore, boxId, fields);
FP2PParticleContainer<FReal> targets;
for(FSize idxPart = 0 ; idxPart < number ; ++idxPart){
targets.push(FPoint<FReal>(&positions[idxPart*3]),physicalValues[idxPart],
fields[idxPart*kernelhandle->fieldDataSize],
fields[idxPart*kernelhandle->fieldDataSize+1],
fields[idxPart*kernelhandle->fieldDataSize+2],
fields[idxPart*kernelhandle->fieldDataSize+3]);
}
kernelhandle->kernel[threadId]->L2P(&cell, &targets);
const FReal*const potentials = targets.getPotentials();
const FReal*const forcesX = targets.getForcesX();
const FReal*const forcesY = targets.getForcesY();
const FReal*const forcesZ = targets.getForcesZ();
for(FSize idxPart = 0 ; idxPart < number ; ++idxPart){
fields[idxPart*kernelhandle->fieldDataSize] += potentials[idxPart];
fields[idxPart*kernelhandle->fieldDataSize+1] += forcesX[idxPart];
fields[idxPart*kernelhandle->fieldDataSize+2] += forcesY[idxPart];
fields[idxPart*kernelhandle->fieldDataSize+3] += forcesZ[idxPart];
}
FmmCore_releaseTargetPoints(fmmCore, boxId, positions);
FmmCore_setTargetField(fmmCore, boxId, fields);
delete[] fields;
return FMMAPI_NO_ERROR;
}
int FmmKernel_M2M(void *fmmCore, void *boxIdFather, void *boxIdSon){
ScalFmmKernelHandle* kernelhandle;
FmmCore_getKernelData(fmmCore, (void**)&kernelhandle);
int threadId;
FmmCore_getParameter(fmmCore, FMMCORE_THREAD_ID, &threadId);
FComplex<FReal>* multipole;
FmmCore_getMultipoleArray(fmmCore, boxIdFather, (void**)&multipole);
KernelCellClass cellFather;
cellFather.attachArrays(multipole, nullptr);
int coordFather[3];
FmmCore_getCoord(fmmCore, boxIdFather, coordFather);
cellFather.setCoordinate(coordFather[0], coordFather[1], coordFather[2]);
FmmCore_getMultipoleArray(fmmCore, boxIdSon, (void**)&multipole);
KernelCellClass cellSon;
cellSon.attachArrays(multipole, nullptr);
int coordChild[3];
FmmCore_getCoord(fmmCore, boxIdSon, coordChild);
cellSon.setCoordinate(coordChild[0], coordChild[1], coordChild[2]);
int level;
FmmCore_getLevel(fmmCore,boxIdFather, &level);
const KernelCellClass* children[8];
memset(children, 0, sizeof(KernelCellClass*)*8);
const int mindex = ((coordChild[0]&1) * 2 + (coordChild[1]&1)) * 2 + (coordChild[2]&1);
children[mindex] = &cellSon;
kernelhandle->kernel[threadId]->M2M(&cellFather, children, level);
return FMMAPI_NO_ERROR;
}
int FmmKernel_L2L(void *fmmCore, void *boxIdFather, void *boxIdSon){
ScalFmmKernelHandle* kernelhandle;
FmmCore_getKernelData(fmmCore, (void**)&kernelhandle);
int threadId;
FmmCore_getParameter(fmmCore, FMMCORE_THREAD_ID, &threadId);
FComplex<FReal>* local;
FmmCore_getLocalArray(fmmCore, boxIdFather, (void**)&local);
KernelCellClass cellFather;
cellFather.attachArrays(nullptr, local);
int coordFather[3];
FmmCore_getCoord(fmmCore, boxIdFather, coordFather);
cellFather.setCoordinate(coordFather[0], coordFather[1], coordFather[2]);
FmmCore_getLocalArray(fmmCore, boxIdSon, (void**)&local);
KernelCellClass cellSon;
cellSon.attachArrays(nullptr, local);
int coordChild[3];
FmmCore_getCoord(fmmCore, boxIdSon, coordChild);
cellSon.setCoordinate(coordChild[0], coordChild[1], coordChild[2]);
int level;
FmmCore_getLevel(fmmCore,boxIdFather, &level);
KernelCellClass* children[8];
memset(children, 0, sizeof(KernelCellClass*)*8);
const int mindex = ((coordChild[0]&1) * 2 + (coordChild[1]&1)) * 2 + (coordChild[2]&1);
children[mindex] = &cellSon;
kernelhandle->kernel[threadId]->L2L(&cellFather, children, level);
return FMMAPI_NO_ERROR;
}
int FmmKernel_M2L(void *fmmCore, void *boxIdSrc, void *boxIdDest){
ScalFmmKernelHandle* kernelhandle;
FmmCore_getKernelData(fmmCore, (void**)&kernelhandle);
int threadId;
FmmCore_getParameter(fmmCore, FMMCORE_THREAD_ID, &threadId);
FComplex<FReal>* multipole;
FmmCore_getMultipoleArray(fmmCore, boxIdSrc, (void**)&multipole);
KernelCellClass cellSrc;
cellSrc.attachArrays(multipole,nullptr);
int coord[3];
FmmCore_getCoord(fmmCore, boxIdSrc, coord);
cellSrc.setCoordinate(coord[0], coord[1], coord[2]);
FComplex<FReal>* local;
FmmCore_getLocalArray(fmmCore, boxIdDest, (void**)&local);
KernelCellClass cellDst;
cellDst.attachArrays(nullptr, local);
FmmCore_getCoord(fmmCore, boxIdDest, coord);
cellDst.setCoordinate(coord[0], coord[1], coord[2]);
int level;
FmmCore_getLevel(fmmCore, boxIdDest, &level);
const int xdiff = cellSrc.getCoordinate().getX() - cellDst.getCoordinate().getX();
const int ydiff = cellSrc.getCoordinate().getY() - cellDst.getCoordinate().getY();
const int zdiff = cellSrc.getCoordinate().getZ() - cellDst.getCoordinate().getZ();
const int index = (((xdiff+3) * 7) + (ydiff+3)) * 7 + zdiff + 3;
const KernelCellClass* inter[343];
memset(inter, 0, sizeof(KernelCellClass*)*343);
inter[index] = &cellSrc;
kernelhandle->kernel[threadId]->M2L(&cellDst, inter, 1, level);
return FMMAPI_NO_ERROR;
}
int FmmKernel_P2P_inner(void *fmmCore, void *boxIdSrcDest){
ScalFmmKernelHandle* kernelhandle;
FmmCore_getKernelData(fmmCore, (void**)&kernelhandle);
int threadId;
FmmCore_getParameter(fmmCore, FMMCORE_THREAD_ID, &thre