Commit b13ecd49 authored by COULAUD Olivier's avatar COULAUD Olivier

Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot/scalfmm/scalfmm

# By bramas (6) and others
# Via bramas
* 'master' of git+ssh://scm.gforge.inria.fr//gitroot/scalfmm/scalfmm:
  Add a word about the c kernel api in the quick start
  Add an extremly basic C API in order to implement a kernel
  Remove some compilation errors on other config
  Remove some warnings, and split P2PR which is P2P only for one over R and P2P which can accept a matrix kernel (which can be one over R or anything else), both approaches support SSE and AVX but have not been tested.
  Fixed M2L timer in FMAlgoThread.
  Update quick start
  Make the M2L non-idle during the communication, but it relies on taks (with chunck size) otherwise nested parallelism will be needed...
  Fixes in changeFmaFormat. No DlPoly available
parents e6d662ab a9139a3e
# 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_ckernelapi_scalfmm CXX C)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ScaLFMM_CXX_FLAGS}")
# Active language
# -----------------------
ENABLE_LANGUAGE(CXX C)
MESSAGE(STATUS " CXX ${CMAKE_CXX_COMPILER_ID}" )
# Options
OPTION( SCALFMM_ADDON_CKERNELAPI "Set to ON to build ScaFMM FMM API interface" OFF )
# if ask to build addon
if(SCALFMM_ADDON_CKERNELAPI)
# first build lib scalfmmckernelapi
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( scalfmmckernelapi STATIC ${source_lib_files} )
# Add blas library (even if it is set to off)
target_link_libraries( scalfmmckernelapi scalfmm)
# Adding the entire project dir as an include dir
INCLUDE_DIRECTORIES(
${CMAKE_BINARY_DIR}/Src
${CMAKE_SOURCE_DIR}/Src
${SCALFMM_INCLUDES}
)
# Install lib
install( TARGETS scalfmmckernelapi ARCHIVE DESTINATION lib )
# Install header
SET(my_include_dirs "Src")
file( GLOB hpp_in_dir Src/*.hpp )
INSTALL( FILES ${hpp_in_dir} DESTINATION include/ScalFmm/CKernelApi )
file( GLOB_RECURSE source_tests_files Tests/*.c )
INCLUDE_DIRECTORIES( ${CMAKE_BINARY_DIR}/Src )
# Then build test files
foreach(exec ${source_tests_files})
get_filename_component(
execname ${exec}
NAME_WE
)
set(compile_exec "TRUE")
# Test Blas dependency
file(STRINGS "${exec}" lines_blas REGEX "@FUSE_BLAS")
if(lines_blas)
if( NOT SCALFMM_USE_BLAS )
MESSAGE( STATUS "This needs BLAS = ${exec}" )
set(compile_exec "FALSE")
endif()
endif()
# Test MPI dependency
file(STRINGS "${exec}" lines_mpi REGEX "@FUSE_MPI")
if(lines_mpi)
if( NOT SCALFMM_USE_MPI )
MESSAGE( STATUS "This needs MPI = ${exec}" )
set(compile_exec "FALSE")
endif()
endif()
# Dependency are OK
if( compile_exec )
add_executable( ${execname} ${exec} )
# link to scalfmm and scalfmmckernelapi
target_link_libraries(
${execname}
${scalfmm_lib}
scalfmmckernelapi
# ${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 CKERNELAPI_H
#define CKERNELAPI_H
/**
* This file defines the API for the USER.
* We briefly comment all the functions.
* The objective of the C Kernel API is to give a quick and easy way
* to anyone (who can program in C) to implement a kernel.
* Using C++ is advised but this is a simple alternative.
*/
///////////////////////////////////////////////////////////////////////////
/// Init part
///////////////////////////////////////////////////////////////////////////
//< For the user an handle is a void*
typedef void* Scalfmm_Handle;
//< Function to init the cells (should be given by the user when calling Scalfmm_init_cell)
//< it gives the level of the cell, its morton index, it position in term of box at that level
//< and the spatial position of its center
typedef void* (*Callback_init_cell)(int level, long long morton_index, int* tree_position, double* spatial_position);
//< Function to destroy what have bee initalized by the user (should be give in Scalfmm_dealloc_handle)
typedef void (*Callback_free_cell)(void*);
//< This function init an handle (and an tree based on the given properties)
Scalfmm_Handle Scalfmm_init_handle(int treeHeight, double boxWidth, double* boxCenter);
//< This function should be used to dealloc our handle
void Scalfmm_dealloc_handle(Scalfmm_Handle handle, Callback_free_cell cellDestroyer);
//< This function should be used to insert an array of particle in the tree
//< The indexes are the one used on the particles operator
//< The posision of the particles should be composed of one triple per particle:
//< xyzxyzxyz...
void Scalfmm_insert_array_of_particles(Scalfmm_Handle handle, int nbParticles, int* particleIndexes, double* particleXYZ);
//< To insert one particle only
void Scalfmm_one_particle(Scalfmm_Handle handle, int particleIndexe, double x, double y, double z);
//< This function should be called to init the cells
//< It must be called after all the particles have been inserted!
void Scalfmm_init_cell(Scalfmm_Handle handle, Callback_init_cell cellInitializer);
///////////////////////////////////////////////////////////////////////////
/// Kernel part
///////////////////////////////////////////////////////////////////////////
//< These function are the callbacks of the FMM operators
typedef void (*Callback_P2M)(void* leafCell, int nbParticles, const int* particleIndexes, void* userData);
typedef void (*Callback_M2M)(int level, void* parentCell, int childPosition, void* childCell, void* userData);
typedef void (*Callback_M2L)(int level, void* targetCell, int sourceCellPosition, void* sourceCell, void* userData);
typedef void (*Callback_L2L)(int level, void* parentCell, int childPosition, void* childCell, void* userData);
typedef void (*Callback_L2P)(void* leafCell, int nbParticles, int* particleIndexes, void* userData);
typedef void (*Callback_P2P)(int nbParticles, const int* particleIndexes, int nbSourceParticles, const int* sourceParticleIndexes, void* userData);
typedef void (*Callback_P2PInner)(int nbParticles, int* particleIndexes, void* userData);
//< This structure should be filled (or filled with null) to call the FMM
struct Scalfmm_Kernel_Descriptor {
Callback_P2M p2m;
Callback_M2M m2m;
Callback_M2L m2l;
Callback_L2L l2l;
Callback_L2P l2p;
Callback_P2P p2p;
Callback_P2PInner p2pinner;
};
//< Execute one FMM using the given kernel, the userData is the one given in all the operators as last
//< parameter.
void Scalfmm_execute_kernel(Scalfmm_Handle handle, struct Scalfmm_Kernel_Descriptor userKernel, void* userData);
///////////////////////////////////////////////////////////////////////////
/// Util functions
///////////////////////////////////////////////////////////////////////////
//< This function fill the childFullPosition[3] with [0;1] to know the position of a child relatively to
//< its position from its parent
inline void Scalfmm_utils_parentChildPosition(int childPosition, int* childFullPosition){
childFullPosition[0] = childPosition%2;
childFullPosition[1] = (childPosition/2)%2;
childFullPosition[2] = (childPosition/4)%2;
}
//< This function fill the childFullPosition[3] with [-3;3] to know the position of a interaction
//< cell relatively to its position from the target
inline void Scalfmm_utils_interactionPosition(int interactionPosition, int* srcPosition){
srcPosition[0] = interactionPosition%7 - 3;
srcPosition[1] = (interactionPosition/7)%7 - 3;
srcPosition[2] = (interactionPosition/49)%7 - 3;
}
#endif // CKERNELAPI_H
// ===================================================================================
// 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/Containers/FOctree.hpp"
#include "../../Src/Containers/FVector.hpp"
#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Components/FBasicCell.hpp"
#include "../../Src/Utils/FPoint.hpp"
#include "../../Src/Core/FFmmAlgorithmThread.hpp"
#include "../../Src/Components/FBasicKernels.hpp"
#include "../../Src/Components/FBasicParticleContainer.hpp"
/** It should be compiled with C export */
extern "C" {
#include "CKernelApi.h"
}
/**
* This file contains the code to have a C Kernel API
* working. It is simply a wrapper with light cell and
* kernel in order to delegate the calls to the API.
*
* The user should allocate the cell data (and deallocate them).
*/
/**
* The core cell is a basic cell + data from the user.
* The cell is not responsible to allocate or deallocate the user data.
*/
class CoreCell : public FBasicCell {
// Mutable in order to work with the API
mutable void* userData;
public:
CoreCell() : userData(nullptr) {
}
~CoreCell(){
}
void setContainer(void* inContainer) const {
userData = inContainer;
}
void* getContainer() const {
return userData;
}
};
/**
* This class simply call the function pointers from Scalfmm_Kernel_Descriptor.
* If not pointer is set the calls are skipped.
* The userData is given at any calls.
*/
template< class CellClass, class ContainerClass>
class CoreKernel : public FAbstractKernels<CellClass,ContainerClass> {
struct Scalfmm_Kernel_Descriptor kernel;
void* userData;
public:
CoreKernel(struct Scalfmm_Kernel_Descriptor inKernel, void* inUserData) : kernel(inKernel) , userData(inUserData){
}
/** Default destructor */
virtual ~CoreKernel(){
}
/** Do nothing */
virtual void P2M(CellClass* const cell, const ContainerClass* const container) {
if(kernel.p2m) kernel.p2m(cell->getContainer(), container->getNbParticles(), container->getAttribute(0), userData);
}
/** Do nothing */
virtual void M2M(CellClass* const FRestrict cell, const CellClass*const FRestrict *const FRestrict children, const int level) {
if(kernel.m2m){
for(int idx = 0 ; idx < 8 ; ++idx){
if( children[idx] ){
kernel.m2m(level, cell->getContainer(), idx, children[idx]->getContainer(), userData);
}
}
}
}
/** Do nothing */
virtual void M2L(CellClass* const FRestrict cell, const CellClass* interactions[], const int , const int level) {
if(kernel.m2l){
for(int idx = 0 ; idx < 343 ; ++idx){
if( interactions[idx] ){
kernel.m2l(level, cell->getContainer(), idx, interactions[idx]->getContainer(), userData);
}
}
}
}
/** Do nothing */
virtual void L2L(const CellClass* const FRestrict cell, CellClass* FRestrict *const FRestrict children, const int level) {
if(kernel.l2l){
for(int idx = 0 ; idx < 8 ; ++idx){
if( children[idx] ){
kernel.l2l(level, cell->getContainer(), idx, children[idx]->getContainer(), userData);
}
}
}
}
/** Do nothing */
virtual void L2P(const CellClass* const cell, ContainerClass* const container){
if(kernel.l2p) kernel.l2p(cell->getContainer(), container->getNbParticles(), container->getAttribute(0), userData);
}
/** Do nothing */
virtual void P2P(const FTreeCoordinate& ,
ContainerClass* const FRestrict targets, const ContainerClass* const FRestrict /*sources*/,
ContainerClass* const neighbors[27], const int ){
if(kernel.p2pinner) kernel.p2pinner(targets->getNbParticles(), targets->getAttribute(0), userData);
if(kernel.p2p){
for(int idx = 0 ; idx < 27 ; ++idx){
if( neighbors[idx] ){
kernel.p2p(targets->getNbParticles(), targets->getAttribute(0),
neighbors[idx]->getNbParticles(), neighbors[idx]->getAttribute(0), userData);
}
}
}
}
/** Do nothing */
virtual void P2PRemote(const FTreeCoordinate& ,
ContainerClass* const FRestrict , const ContainerClass* const FRestrict ,
ContainerClass* const [27], const int ){
}
};
// Here are all the type definition
typedef FBasicParticleContainer<1, int> CoreContainerClass;
typedef FSimpleLeaf<CoreContainerClass > LeafClass;
typedef FOctree<CoreCell, CoreContainerClass , LeafClass > OctreeClass;
typedef CoreKernel<CoreCell, CoreContainerClass> CoreKernelClass;
typedef FFmmAlgorithmThread<OctreeClass, CoreCell, CoreContainerClass, CoreKernelClass, LeafClass > FmmClassThread;
// Our scalfmm handle
struct ScalFmmCoreHandle {
struct ScalFmmCoreConfig {
//paramètres en lecture/écriture :
int treeHeight; // hombre de niveaux de l'arbre (int)
FReal boxWidth; // taille de la boîte racine (FReal)
FPoint boxCenter; // position du centre de la boîte racine (FReal[3])
};
ScalFmmCoreConfig config;
OctreeClass* octree;
};
// Allocate and init the handle
extern "C" Scalfmm_Handle Scalfmm_init_handle(int treeHeight, double boxWidth, double* boxCenter){
ScalFmmCoreHandle* corehandle = new ScalFmmCoreHandle;
memset(corehandle, 0, sizeof(ScalFmmCoreHandle));
corehandle->config.treeHeight = treeHeight;
corehandle->config.boxWidth = boxWidth;
corehandle->config.boxCenter = FPoint(boxCenter[0],boxCenter[1],boxCenter[2]);
corehandle->octree = new OctreeClass(corehandle->config.treeHeight, FMath::Min(3,corehandle->config.treeHeight-1),
corehandle->config.boxWidth, corehandle->config.boxCenter);
return corehandle;
}
// Init the cells (once the particles have been pushed)
extern "C" void Scalfmm_init_cell(Scalfmm_Handle handle, Callback_init_cell cellInitializer){
if(cellInitializer){
ScalFmmCoreHandle* corehandle = (ScalFmmCoreHandle*)handle;
double boxWidth = corehandle->config.boxWidth;
double boxCorner[3];
boxCorner[0] = corehandle->config.boxCenter.getX() - boxWidth/2.0;
boxCorner[1] = corehandle->config.boxCenter.getY() - boxWidth/2.0;
boxCorner[2] = corehandle->config.boxCenter.getZ() - boxWidth/2.0;
corehandle->octree->forEachCellWithLevel([&](CoreCell* cell, int level){
int coord[3] = {cell->getCoordinate().getX(),cell->getCoordinate().getY(),cell->getCoordinate().getZ() };
double position[3];
position[0] = boxCorner[0] + coord[0]*boxWidth/double(1<<level);
position[1] = boxCorner[1] + coord[1]*boxWidth/double(1<<level);
position[2] = boxCorner[2] + coord[2]*boxWidth/double(1<<level);
cell->setContainer(cellInitializer(level, cell->getMortonIndex(), coord, position));
});
}
}
// Dealloc the handle and call the destroy function on the cells if given
extern "C" void Scalfmm_dealloc_handle(Scalfmm_Handle handle, Callback_free_cell cellDestroyer){
ScalFmmCoreHandle* corehandle = (ScalFmmCoreHandle*)handle;
if(cellDestroyer){
corehandle->octree->forEachCell([&](CoreCell* cell){
cellDestroyer(cell->getContainer());
});
}
delete corehandle->octree;
delete corehandle;
}
// Insert a full array of particles. Posisions are xyz.xyz.xyz...
extern "C" void Scalfmm_insert_array_of_particles(Scalfmm_Handle handle, int nbParticles, int* particleIndexes, double* particleXYZ){
ScalFmmCoreHandle* corehandle = (ScalFmmCoreHandle*)handle;
for(int idxPart = 0 ; idxPart < nbParticles ; ++idxPart){
corehandle->octree->insert(FPoint(particleXYZ[idxPart*3],particleXYZ[idxPart*3+1],particleXYZ[idxPart*3+2]),
particleIndexes[idxPart]);
}
}
// Push one particle in the tree
extern "C" void Scalfmm_one_particle(Scalfmm_Handle handle, int particleIndex, double x, double y, double z){
ScalFmmCoreHandle* corehandle = (ScalFmmCoreHandle*)handle;
corehandle->octree->insert(FPoint(x,y,z), particleIndex);
}
// Execute a kernel (by using the user functions callback).
extern "C" void Scalfmm_execute_kernel(Scalfmm_Handle handle, struct Scalfmm_Kernel_Descriptor userKernel, void *userData){
ScalFmmCoreHandle* corehandle = (ScalFmmCoreHandle*)handle;
CoreKernelClass kernel(userKernel, userData);
FmmClassThread algorithm(corehandle->octree,&kernel);
algorithm.execute();
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -254,9 +254,7 @@ private:
if(counter) myThreadkernels->M2L( iterArray[idxCell].getCurrentCell() , neighbors, counter, idxLevel);
}
FLOG(computationCounter.tic());
myThreadkernels->finishedLevelM2L(idxLevel);
FLOG(computationCounter.tac());
}
FLOG(computationCounter.tac());
FLOG( FLog::Controller << "\t\t>> Level " << idxLevel << " = " << counterTimeLevel.tacAndElapsed() << "s\n" );
......
This diff is collapsed.
......@@ -300,7 +300,7 @@ public:
*/
FDlpolyBinLoader(const char* const filename): file(fopen(filename, "rb")) {
// test if open
if(this->file != NULL){
if(this->file != nullptr){
energy = readValue<double>();
double boxDim[3];
boxWidth = readArray<double>(boxDim,3)[0];
......@@ -325,7 +325,7 @@ public:
* @return true if loader can work
*/
bool isOpen() const{
return this->file != NULL;
return this->file != nullptr;
}
// /**
......
......@@ -3,6 +3,7 @@
#include "../P2P/FP2P.hpp"
#include "../P2P/FP2PR.hpp"
template <KERNEL_FUNCTION_IDENTIFIER Identifier, int NVALS>
......@@ -36,7 +37,7 @@ struct DirectInteractionComputer<ONE_OVER_R, 1>
static void P2P( ContainerClass* const FRestrict TargetParticles,
ContainerClass* const NeighborSourceParticles[27],
const MatrixKernelClass *const /*MatrixKernel*/){
FP2P::FullMutual(TargetParticles,NeighborSourceParticles,14);
FP2PR::FullMutual(TargetParticles,NeighborSourceParticles,14);
}
template <typename ContainerClass, typename MatrixKernelClass>
......@@ -44,7 +45,7 @@ struct DirectInteractionComputer<ONE_OVER_R, 1>
ContainerClass* const inNeighbors[27],
const int inSize,
const MatrixKernelClass *const /*MatrixKernel*/){
FP2P::FullRemote(inTargets,inNeighbors,inSize);
FP2PR::FullRemote(inTargets,inNeighbors,inSize);
}
};
......@@ -103,7 +104,7 @@ struct DirectInteractionComputer<ONE_OVER_R, NVALS>
ContainerClass* const NeighborSourceParticles[27],
const MatrixKernelClass *const /*MatrixKernel*/){
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
FP2P::FullMutual(TargetParticles,NeighborSourceParticles,14);
FP2PR::FullMutual(TargetParticles,NeighborSourceParticles,14);
}
}
......@@ -113,7 +114,7 @@ struct DirectInteractionComputer<ONE_OVER_R, NVALS>
const int inSize,
const MatrixKernelClass *const /*MatrixKernel*/){
for(int idxRhs = 0 ; idxRhs < NVALS ; ++idxRhs){
FP2P::FullRemote(inTargets,inNeighbors,inSize);
FP2PR::FullRemote(inTargets,inNeighbors,inSize);
}
}
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef FP2PR_HPP
#define FP2PR_HPP
#include "Utils/FGlobal.hpp"
#include "Utils/FMath.hpp"
/**
* @brief The FP2PR namespace
*/
namespace FP2PR{
inline void MutualParticles(const FReal sourceX,const FReal sourceY,const FReal sourceZ, const FReal sourcePhysicalValue,
FReal* sourceForceX, FReal* sourceForceY, FReal* sourceForceZ, FReal* sourcePotential,
const FReal targetX,const FReal targetY,const FReal targetZ, const FReal targetPhysicalValue,
FReal* targetForceX, FReal* targetForceY, FReal* targetForceZ, FReal* targetPotential
){
FReal dx = sourceX - targetX;
FReal dy = sourceY - targetY;
FReal dz = sourceZ - targetZ;
FReal inv_square_distance = FReal(1.0) / (dx*dx + dy*dy + dz*dz);
FReal inv_distance = FMath::Sqrt(inv_square_distance);
inv_square_distance *= inv_distance;
inv_square_distance *= targetPhysicalValue * sourcePhysicalValue;
dx *= inv_square_distance;
dy *= inv_square_distance;
dz *= inv_square_distance;
*targetForceX += dx;
*targetForceY += dy;
*targetForceZ += dz;
*targetPotential += ( inv_distance * sourcePhysicalValue );
*sourceForceX -= dx;
*sourceForceY -= dy;
*sourceForceZ -= dz;
*sourcePotential += ( inv_distance * targetPhysicalValue );
}
inline void NonMutualParticles(const FReal sourceX,const FReal sourceY,const FReal sourceZ, const FReal sourcePhysicalValue,
const FReal targetX,const FReal targetY,const FReal targetZ, const FReal targetPhysicalValue,
FReal* targetForceX, FReal* targetForceY, FReal* targetForceZ, FReal* targetPotential){
FReal dx = sourceX - targetX;
FReal dy = sourceY - targetY;
FReal dz = sourceZ - targetZ;
FReal inv_square_distance = FReal(1.0) / (dx*dx + dy*dy + dz*dz);
FReal inv_distance = FMath::Sqrt(inv_square_distance);
inv_square_distance *= inv_distance;
inv_square_distance *= targetPhysicalValue * sourcePhysicalValue;
dx *= inv_square_distance;
dy *= inv_square_distance;
dz *= inv_square_distance;
*targetForceX += dx;
*targetForceY += dy;
*targetForceZ += dz;
*targetPotential += ( inv_distance * sourcePhysicalValue );
}
}
#ifdef ScalFMM_USE_SSE
#include "FP2PRSse.hpp"
#elif defined(ScalFMM_USE_AVX)
#include "FP2PRAvx.hpp"
#else
#include "FP2PRClassic.hpp"
#endif //Includes
#endif // FP2PR_HPP
#ifndef FP2PAVX_HPP
#define FP2PAVX_HPP
#ifndef FP2PRAVX_HPP
#define FP2PR