Commit e7c65570 authored by PIACIBELLO Cyrille's avatar PIACIBELLO Cyrille

Old API deleted

parent dc8ecaff
// ===================================================================================
// Copyright ScalFmm 2014 I
// 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
// abiding by the rules of distribution of free software.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
//
#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<FReal, 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 {
// Read/Write parameter
int treeHeight; // Number of level in the octree
FReal boxWidth; // Simulation box size (root level)
FPoint<FReal> boxCenter; // Center position of the box simulation(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<FReal>(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, FSize nbParticles, int* particleIndexes, double* particleXYZ){
ScalFmmCoreHandle* corehandle = (ScalFmmCoreHandle*)handle;
for(FSize idxPart = 0 ; idxPart < nbParticles ; ++idxPart){
corehandle->octree->insert(FPoint<FReal>(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<FReal>(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 function fill the childFullPosition[3] with [-1;1] to know the position of a child relatively to
//< its position from its parent
extern "C" void Scalfmm_utils_parentChildPosition(int childPosition, int* childFullPosition){
childFullPosition[2] = (childPosition%2 ? 1 : -1);
childFullPosition[1] = ((childPosition/2)%2 ? 1 : -1);
childFullPosition[0] = ((childPosition/4)%2 ? 1 : -1);
}
//< This function fill the childFullPosition[3] with [-3;3] to know the position of a interaction
//< cell relatively to its position from the target
extern "C" void Scalfmm_utils_interactionPosition(int interactionPosition, int* srcPosition){
srcPosition[2] = interactionPosition%7 - 3;
srcPosition[1] = (interactionPosition/7)%7 - 3;
srcPosition[0] = (interactionPosition/49)%7 - 3;
}
// ===================================================================================
// 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* In this file we implement a example kernel which is simply printing information
* about the cells and particles.
* It is recommanded to compile and execute this code in order to understand the behavior
* of the application.
* We mark some part with "JUST-PUT-HERE:" to give instruction to user to create its own kernel.
**/
// Include the FMM API (should be in a different folder for you)
#include "../Src/CKernelApi.h"
// Uncomment the next line to avoid the print in the kernel and verbosity
// #define NOT_TOO_MUCH_VERBOSE
#ifdef NOT_TOO_MUCH_VERBOSE
#define VerbosePrint(X...)
#else
#define VerbosePrint(X...) printf(X)
#endif
///////////////////////////////////////////////////////////////////////////
/// Cell struct and functions
///////////////////////////////////////////////////////////////////////////
// This represent a cell
struct MyCellDescriptor{
int level;
long long mortonIndex;
int coord[3];
double position[3];
// JUST-PUT-HERE:
// You local and multipole arrays
};
// This is our function that init a cell (struct MyCellDescriptor)
void* my_Callback_init_cell(int level, long long mortonIndex, int* coord, double* position){
VerbosePrint("\tAllocating cell for level %d, morton index %lld, coord %d/%d/%d\n", level, mortonIndex, coord[0], coord[1], coord[2]);
struct MyCellDescriptor* cellData = (struct MyCellDescriptor*)malloc(sizeof(struct MyCellDescriptor));
memset(cellData, 0, sizeof(struct MyCellDescriptor));
cellData->level = level;
cellData->mortonIndex = mortonIndex;
memcpy(cellData->coord, coord, sizeof(int)*3);
memcpy(cellData->position, position, sizeof(double)*3);
// JUST-PUT-HERE:
// Fill your structure
return cellData;
}
// To dealloc a cell
void my_Callback_free_cell(void* cellData){
free(cellData);
}
///////////////////////////////////////////////////////////////////////////
/// Kernel struct and functions
///////////////////////////////////////////////////////////////////////////
// This is the data passed to our kernel
struct MyData {
// We simply strore the number of call the and particle indexes
double* insertedPositions;
int countP2M;
int countM2M;
int countM2L;
int countL2L;
int countL2P;
int countP2PInner;
int countP2P;
// JUST-PUT-HERE:
// everything your kernel will need for its computation
// pre-computed matrices, etc....
};
// Our P2M
void my_Callback_P2M(void* cellData, FSize nbParticlesInLeaf, const int* particleIndexes, void* userData){
struct MyData* my_data = (struct MyData*)userData;
my_data->countP2M += 1;
struct MyCellDescriptor* my_cell = (struct MyCellDescriptor*) cellData;
VerbosePrint("Cell morton %lld is doing P2M with %d particles :\n", my_cell->mortonIndex, nbParticlesInLeaf);
FSize idxPart;
for(idxPart = 0 ; idxPart < nbParticlesInLeaf ; ++idxPart){
double* position = &my_data->insertedPositions[particleIndexes[idxPart]*3];
VerbosePrint("\t particle idx %d position %e/%e%e\n", particleIndexes[idxPart],
position[0], position[1], position[2]);
// JUST-PUT-HERE:
// Your real P2M computation
}
}
void my_Callback_M2M(int level, void* cellData, int childPosition, void* childData, void* userData){
struct MyData* my_data = (struct MyData*)userData;
my_data->countM2M += 1;
struct MyCellDescriptor* my_cell = (struct MyCellDescriptor*) cellData;
struct MyCellDescriptor* my_child = (struct MyCellDescriptor*) childData;
int childFullPosition[3];
Scalfmm_utils_parentChildPosition(childPosition, childFullPosition);
VerbosePrint("Doing a M2M at level %d, between cells %lld and %lld (position %d/%d/%d)\n",
level, my_cell->mortonIndex, my_child->mortonIndex,
childFullPosition[0], childFullPosition[1], childFullPosition[2]);
// JUST-PUT-HERE: your real M2M computation
}
void my_Callback_M2L(int level, void* cellData, int srcPosition, void* srcData, void* userData){
struct MyData* my_data = (struct MyData*)userData;
my_data->countM2L += 1;
struct MyCellDescriptor* my_cell = (struct MyCellDescriptor*) cellData;
struct MyCellDescriptor* my_src_cell = (struct MyCellDescriptor*) srcData;
int interactionFullPosition[3];
Scalfmm_utils_interactionPosition(srcPosition, interactionFullPosition);
VerbosePrint("Doing a M2L at level %d, between cells %lld and %lld (position %d/%d/%d)\n",
level, my_cell->mortonIndex, my_src_cell->mortonIndex,
interactionFullPosition[0], interactionFullPosition[1], interactionFullPosition[2]);
// JUST-PUT-HERE: Your M2L
}
void my_Callback_L2L(int level, void* cellData, int childPosition, void* childData, void* userData){
struct MyData* my_data = (struct MyData*)userData;
my_data->countL2L += 1;
struct MyCellDescriptor* my_cell = (struct MyCellDescriptor*) cellData;
struct MyCellDescriptor* my_child = (struct MyCellDescriptor*) childData;
int childFullPosition[3];
Scalfmm_utils_parentChildPosition(childPosition, childFullPosition);
VerbosePrint("Doing a L2L at level %d, between cells %lld and %lld (position %d/%d/%d)\n",
level, my_cell->mortonIndex, my_child->mortonIndex,
childFullPosition[0], childFullPosition[1], childFullPosition[2]);
// JUST-PUT-HERE: Your L2L
}
void my_Callback_L2P(void* cellData, FSize nbParticlesInLeaf, int* particleIndexes, void* userData){
struct MyData* my_data = (struct MyData*)userData;
my_data->countL2P += 1;
struct MyCellDescriptor* my_cell = (struct MyCellDescriptor*) cellData;
VerbosePrint("Cell morton %lld is doing L2P with %d particles :\n", my_cell->mortonIndex, nbParticlesInLeaf);
FSize idxPart;
for(idxPart = 0 ; idxPart < nbParticlesInLeaf ; ++idxPart){
double* position = &my_data->insertedPositions[particleIndexes[idxPart]*3];
VerbosePrint("\t particle idx %d position %e/%e%e\n", particleIndexes[idxPart],
position[0], position[1], position[2]);
// JUST-PUT-HERE: Your L2P
}
}
void my_Callback_P2P(FSize nbParticlesInLeaf, const int* particleIndexes, FSize nbParticlesInSrc, const int* particleIndexesSrc, void* userData){
struct MyData* my_data = (struct MyData*)userData;
my_data->countP2P += 1;
VerbosePrint("Doing P2P between two leaves of %d particles and %d particles :\n", nbParticlesInLeaf, nbParticlesInSrc);
FSize idxPart;
for(idxPart = 0 ; idxPart < nbParticlesInLeaf ; ++idxPart){
double* position = &my_data->insertedPositions[particleIndexes[idxPart]*3];
VerbosePrint("\t Target >> particle idx %d position %e/%e%e\n", particleIndexes[idxPart],
position[0], position[1], position[2]);
}
for(idxPart = 0 ; idxPart < nbParticlesInSrc ; ++idxPart){
double* position = &my_data->insertedPositions[particleIndexesSrc[idxPart]*3];
VerbosePrint("\t Target >> Src idx %d position %e/%e%e\n", particleIndexesSrc[idxPart],
position[0], position[1], position[2]);
}
// JUST-PUT-HERE:
// Put one loop into the other to make all particles from source
// interacting with the target particles
}
void my_Callback_P2PInner(FSize nbParticlesInLeaf, int* particleIndexes, void* userData){
struct MyData* my_data = (struct MyData*)userData;
my_data->countP2PInner += 1;
VerbosePrint("Doing P2P inside a leaf of %d particles :\n", nbParticlesInLeaf);
FSize idxPart;
for(idxPart = 0 ; idxPart < nbParticlesInLeaf ; ++idxPart){
double* position = &my_data->insertedPositions[particleIndexes[idxPart]*3];
VerbosePrint("\t particle idx %d position %e/%e%e\n", particleIndexes[idxPart],
position[0], position[1], position[2]);
// JUST-PUT-HERE: another loop to have all particles interacting with
// the other from the same leaf
}
}
///////////////////////////////////////////////////////////////////////////
/// Main
///////////////////////////////////////////////////////////////////////////
// Simply create particles and try the kernels
int main(int argc, char ** argv){
// The properties of our tree
int treeHeight = 4;
double boxWidth = 1.0;
double boxCenter[3];
boxCenter[0] = boxCenter[1] = boxCenter[2] = 0.0;
// Create random particles
FSize nbParticles = 10;
int particleIndexes[nbParticles];
double particleXYZ[nbParticles*3];
{
printf("Creating Particles:\n");
FSize idxPart;
for(idxPart = 0 ; idxPart < nbParticles ; ++idxPart){
particleIndexes[idxPart] = idxPart;
particleXYZ[idxPart*3] = (random()/(double)(RAND_MAX))*boxWidth - boxWidth/2 + boxCenter[0];
particleXYZ[idxPart*3+1] = (random()/(double)(RAND_MAX))*boxWidth - boxWidth/2 + boxCenter[1];
particleXYZ[idxPart*3+2] = (random()/(double)(RAND_MAX))*boxWidth - boxWidth/2 + boxCenter[2];
VerbosePrint("\t %d] %e/%e/%e\n", idxPart, particleXYZ[idxPart*3], particleXYZ[idxPart*3+1], particleXYZ[idxPart*3+2]);
}
}
// Init the handle
Scalfmm_Handle handle = Scalfmm_init_handle(treeHeight, boxWidth, boxCenter);
// Insert particles
printf("Inserting particles...\n");
Scalfmm_insert_array_of_particles(handle, nbParticles, particleIndexes, particleXYZ);
// Init cell
printf("Initizalizing the cells:\n");
Scalfmm_init_cell(handle, my_Callback_init_cell);
// Init our callback struct
struct Scalfmm_Kernel_Descriptor kernel;
kernel.p2m = my_Callback_P2M;
kernel.m2m = my_Callback_M2M;
kernel.m2l = my_Callback_M2L;
kernel.l2l = my_Callback_L2L;
kernel.l2p = my_Callback_L2P;
kernel.p2pinner = my_Callback_P2PInner;
kernel.p2p = my_Callback_P2P;
// Init the data to pass to all our callbacks
struct MyData my_data;
memset(&my_data, 0, sizeof(struct MyData));
my_data.insertedPositions = particleXYZ;
// Execute the FMM
Scalfmm_execute_kernel(handle, kernel, &my_data);
// Print the results store in our callback
printf("There was %d P2M\n", my_data.countP2M);
printf("There was %d M2M\n", my_data.countM2M);
printf("There was %d M2L\n", my_data.countM2L);
printf("There was %d L2L\n", my_data.countL2L);
printf("There was %d L2P\n", my_data.countL2P);
printf("There was %d P2PInner\n", my_data.countP2PInner);
printf("There was %d P2P\n", my_data.countP2P);
// Dealloc the handle
Scalfmm_dealloc_handle(handle,my_Callback_free_cell);
return 0;
}
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