Commit 13278d73 authored by COULAUD Olivier's avatar COULAUD Olivier
Browse files

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

# By bramas (7) and piacibel (4)
# Via bramas
* 'master' of git+ssh://scm.gforge.inria.fr//gitroot/scalfmm/scalfmm:
  Add a name to critical section (even if they should not be called at the same time but to ensure that they cannot interfere with some others)
  Add critical when creating kernel for each thread to ensure that the thread are in a protected environment
  minor fix on that test
  Add operation to the vector to ensure that object without default constructor can be user with it
  Both version (user defined kernel and interpolation kernel) provides same features
  oops missmatch in the deleter for the smart ptr
  Remove some warnings and add the patch for the omp to starpu auto version
  Remove some warnings and add the patch for the omp to starpu auto version
  remove some conversion warnings
  Forgot 1 modifocation
  Update in API in order to remove memory leaks (changes added to FChebInterpolator too.)
parents 0569d1fc f01521a6
......@@ -101,9 +101,6 @@ typedef void* scalfmm_handle;
/**
* @brief This function initialize scalfmm datas.
* @param TreeHeight Height of the octree.
* @param BoxWidth Width of the entire simulation box.
* @param BoxCenter Coordinate of the center of the box (ie array)
* @param KernelType kernel to be used
* @return scalfmm_handle (ie void *). This handle will be given to
* every other scalfmm functions.
......@@ -111,15 +108,58 @@ typedef void* scalfmm_handle;
* Every data will be stored in order to crete later through a builder
* what is needed for the simulation
*/
scalfmm_handle scalfmm_init(int TreeHeight,double BoxWidth,double* BoxCenter, scalfmm_kernel_type KernelType);
scalfmm_handle scalfmm_init( scalfmm_kernel_type KernelType);
/////////////////////////////////////////////////////////////////////
////////////////// Tree Part //////////////
/////////////////////////////////////////////////////////////////////
//In order to initate the tree for user defined cell and kernel, we
//define here the call_backs to deal with cells
/**
* @brief Function to init the cells (should be given by the user when
* calling Scalfmm_init_cell)
* @param level level of the cell.
* @param morton_index morton index of the cell to be allocated.
* @param tree_position int[3] position inside the tree (number of boxes in
* each direction)
* @param spatial_position double[3] center of the cell
*/
typedef void* (*Callback_init_cell)(int level, long long morton_index, int* tree_position, double* spatial_position);
/**
* Function to destroy what have bee initialized by the user (should
* be give in Scalfmm_dealloc_handle)
*/
typedef void (*Callback_free_cell)(void*);
/**
* @brief Structure containing user's call_backs in order to
* initialize/free the cell's user data.
*/
typedef struct User_Scalfmm_Cell_Descriptor{
Callback_free_cell user_free_cell;
Callback_init_cell user_init_cell;
}Scalfmm_Cell_Descriptor;
/**
* @brief This function build the tree. If scalfmm_init has been
* called with a user defined kernel, then user_cell_descriptor need
* to be provided
*
* @param TreeHeight Height of the octree.
* @param BoxWidth Width of the entire simulation box.
* @param BoxCenter Coordinate of the center of the box (ie array)
*/
void scalfmm_build_tree(scalfmm_handle handle,int TreeHeight,double BoxWidth,double* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor);
/**
* @brief This function insert an array of position into the octree
* @param Handle scalfmm_handle provided by scalfmm_init.
......@@ -414,30 +454,14 @@ void scalfmm_user_kernel_config(scalfmm_handle Handle, Scalfmm_Kernel_Descriptor
//To fill gestion des cellules utilisateurs
/**
* @brief Function to init the cells (should be given by the user when
* calling Scalfmm_init_cell)
* @param level level of the cell.
* @param morton_index morton index of the cell to be allocated.
* @param tree_position int[3] position inside the tree (number of boxes in
* each direction)
* @param spatial_position double[3] center of the cell
*/
typedef void* (*Callback_init_cell)(int level, long long morton_index, int* tree_position, double* spatial_position);
/**
* Function to destroy what have bee initialized by the user (should
* be give in Scalfmm_dealloc_handle)
*/
typedef void (*Callback_free_cell)(void*);
void scalfmm_init_cell(scalfmm_handle Handle, Callback_init_cell user_cell_initializer);
void scalfmm_free_cell(scalfmm_handle Handle, Callback_free_cell user_cell_deallocator);
/* void scalfmm_init_cell(scalfmm_handle Handle, Callback_init_cell user_cell_initializer); */
/* void scalfmm_free_cell(scalfmm_handle Handle, Callback_free_cell user_cell_deallocator); */
/* /\** */
/* *@param Struct defining how scalfmm will handle user's cell data. */
/* *\/ */
/* void scalfmm_user_cell_config(scalfmm_handle Handle, Scalfmm_Cell_Descriptor user_cell_descriptor); */
///////////////// Common kernel part : /////////////////
......@@ -465,7 +489,7 @@ void scalfmm_execute_fmm(scalfmm_handle Handle);
* The last param cellDestroyer is meaningless in case the user uses
* one of the provided kernel. (i.e. Chebyshev, Lagrange)
*/
void Scalfmm_dealloc_handle(scalfmm_handle handle, Callback_free_cell cellDestroyer);
void scalfmm_dealloc_handle(scalfmm_handle handle, Callback_free_cell cellDestroyer);
#endif
......@@ -24,9 +24,10 @@
#include "FScalFMMEngine.hpp"
#include "Kernels/Interpolation/FInterpMatrixKernel.hpp"
#include "Kernels/P2P/FP2PLeafInterface.hpp"
//#include "Kernels/P2P/FP2PLeafInterface.hpp"
#include "Arranger/FOctreeArranger.hpp"
#include "Arranger/FArrangerPeriodic.hpp"
#include "Arranger/FBasicParticleContainerIndexedMover.hpp"
#include "Core/FFmmAlgorithmThread.hpp"
#include "Core/FFmmAlgorithm.hpp"
......@@ -45,12 +46,14 @@ class FInterEngine : public FScalFMMEngine{
private:
//Typedef on the octree class, in order to clarify following code
typedef FOctree<InterCell,ContainerClass,LeafClass> OctreeClass;
typedef FP2PLeafInterface<OctreeClass> LeafInterface;
//typedef FP2PLeafInterface<OctreeClass> LeafInterface;
//Typedef on Octree Arranger, in order to clarify following code
typedef FOctreeArranger<OctreeClass,ContainerClass,LeafInterface> ArrangerClass;
typedef FArrangerPeriodic<OctreeClass,ContainerClass,LeafInterface> ArrangerClassPeriodic;
typedef FBasicParticleContainerIndexedMover<OctreeClass, ContainerClass> MoverClass;
typedef FOctreeArranger<OctreeClass, ContainerClass, MoverClass> ArrangerClass;
typedef FArrangerPeriodic<OctreeClass, ContainerClass, MoverClass> ArrangerClassPeriodic;
//Pointer to the kernel to be executed
InterKernel * kernel;
MatrixKernelClass * matrix;
......@@ -67,19 +70,26 @@ public:
* @param BoxCenter double[3] coordinate of the center of the
* simulation box
*/
FInterEngine(int TreeHeight, double BoxWidth , double * BoxCenter,scalfmm_kernel_type KernelType) :
FInterEngine(scalfmm_kernel_type KernelType) :
kernel(nullptr), matrix(nullptr), octree(nullptr),arranger(nullptr){
kernelType = KernelType;
}
void build_tree(int TreeHeight, double BoxWidth , double * BoxCenter,User_Scalfmm_Cell_Descriptor notUsedHere){
octree = new OctreeClass(TreeHeight,FMath::Min(3,TreeHeight-1),BoxWidth,FPoint(BoxCenter));
this->matrix = new MatrixKernelClass();
this->kernel = new InterKernel(TreeHeight,BoxWidth,FPoint(BoxCenter),matrix);
kernelType = KernelType;
arranger = nullptr;
}
//TODO free kernel too
~FInterEngine(){
free(octree);
free(kernel);
delete matrix;
delete octree;
delete kernel;
if(arranger){
delete arranger;
}
}
//Inserting array of position
......@@ -528,7 +538,6 @@ public:
void execute_fmm(){
//typedef FOctree<InterCell,ContainerClass,LeafClass> OctreeClass;
switch(Algorithm){
case 0:
{
......@@ -557,7 +566,9 @@ public:
}
}
void intern_dealloc_handle(Callback_free_cell unUsed){
//this->~FInterEngine();
}
};
......
......@@ -51,11 +51,16 @@ protected:
scalfmm_kernel_type kernelType;
scalfmm_algorithm Algorithm;
FVector<bool> progress;
FVector<bool>* progress;
int nbPart;
public:
FScalFMMEngine() : Algorithm(multi_thread), progress(), nbPart(0){
FScalFMMEngine() : Algorithm(multi_thread), progress(nullptr), nbPart(0){
progress = new FVector<bool>();
}
virtual ~FScalFMMEngine() {
delete progress;
}
//First function displayed there are common function for every
......@@ -75,6 +80,10 @@ public:
//by specific Engine
//Function about the tree
virtual void build_tree(int TreeHeight,double BoxWidth,double* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor){
FAssertLF(0,"Nothing has been done yet, exiting");
}
virtual void tree_insert_particles( int NbPositions, double * arrayX, double * arrayY, double * arrayZ){
FAssertLF(0,"No tree instancied, exiting ...\n");
}
......@@ -196,15 +205,11 @@ public:
FAssertLF(0,"No user kernel defined, exiting ...\n");
}
virtual void init_cell(Callback_init_cell user_cell_initializer){
FAssertLF(0,"No user kernel defined, exiting ...\n");
}
virtual void free_cell(Callback_free_cell user_cell_initializer){
FAssertLF(0,"No user kernel defined, exiting ...\n");
virtual void execute_fmm(){
FAssertLF(0,"No kernel set, cannot execute anything, exiting ...\n");
}
virtual void execute_fmm(){
virtual void intern_dealloc_handle(Callback_free_cell userDeallocator){
FAssertLF(0,"No kernel set, cannot execute anything, exiting ...\n");
}
......@@ -225,7 +230,9 @@ struct ScalFmmCoreHandle {
extern "C" void scalfmm_build_tree(scalfmm_handle Handle,int TreeHeight,double BoxWidth,double* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor){
((ScalFmmCoreHandle *) Handle)->engine->build_tree(TreeHeight,BoxWidth, BoxCenter, user_cell_descriptor);
}
extern "C" void scalfmm_tree_insert_particles(scalfmm_handle Handle, int NbPositions, double * arrayX, double * arrayY, double * arrayZ){
((ScalFmmCoreHandle *) Handle)->engine->tree_insert_particles(NbPositions, arrayX, arrayY, arrayZ);
......@@ -378,12 +385,8 @@ extern "C" void scalfmm_execute_fmm(scalfmm_handle Handle){
((ScalFmmCoreHandle * ) Handle)->engine->execute_fmm();
}
extern "C" void scalfmm_init_cell(scalfmm_handle Handle, Callback_init_cell user_cell_initializer){
((ScalFmmCoreHandle * ) Handle)->engine->init_cell(user_cell_initializer);
}
extern "C" void scalfmm_free_cell(scalfmm_handle Handle, Callback_free_cell user_cell_deallocator){
((ScalFmmCoreHandle * ) Handle)->engine->free_cell(user_cell_deallocator);
extern "C" void scalfmm_user_kernel_config(scalfmm_handle Handle, Scalfmm_Kernel_Descriptor userKernel, void * userDatas){
((ScalFmmCoreHandle * ) Handle)->engine->user_kernel_config(userKernel,userDatas);
}
......
#ifndef CALL_HPP
#define CALL_HPP
/** It should be compiled with C export */
extern "C" {
#include "CScalfmmApi.h"
......@@ -10,13 +6,12 @@ extern "C" {
#include "FInterEngine.hpp"
#include "FUserKernelEngine.hpp"
extern "C" scalfmm_handle scalfmm_init(int TreeHeight,double BoxWidth,double* BoxCenter, scalfmm_kernel_type KernelType){
extern "C" scalfmm_handle scalfmm_init(/*int TreeHeight,double BoxWidth,double* BoxCenter, */scalfmm_kernel_type KernelType){
ScalFmmCoreHandle * handle = new ScalFmmCoreHandle();
switch(KernelType){
case 0:
//handle->engine = new FUserKernelEngine(...);
std::cout<< "User Kernel type unsupported yet" << std::endl;
handle->engine = new FUserKernelEngine(/*TreeHeight, BoxWidth, BoxCenter, */KernelType);
break;
case 1:
......@@ -27,7 +22,7 @@ extern "C" scalfmm_handle scalfmm_init(int TreeHeight,double BoxWidth,double* Bo
typedef FInterpMatrixKernelR MatrixKernelClass;
typedef FChebSymKernel<ChebCell,ContainerClass,MatrixKernelClass,7> ChebKernel;
handle->engine = new FInterEngine<ChebCell,ChebKernel>(TreeHeight,BoxWidth,BoxCenter, KernelType);
handle->engine = new FInterEngine<ChebCell,ChebKernel>(/*TreeHeight,BoxWidth,BoxCenter, */KernelType);
break;
case 2:
//TODO typedefs
......@@ -37,7 +32,7 @@ extern "C" scalfmm_handle scalfmm_init(int TreeHeight,double BoxWidth,double* Bo
typedef FInterpMatrixKernelR MatrixKernelClass;
typedef FUnifKernel<UnifCell,ContainerClass,MatrixKernelClass,7> UnifKernel;
handle->engine = new FInterEngine<UnifCell,UnifKernel>(TreeHeight,BoxWidth,BoxCenter,KernelType);
handle->engine = new FInterEngine<UnifCell,UnifKernel>(/*TreeHeight,BoxWidth,BoxCenter, */KernelType);
break;
default:
......@@ -48,5 +43,8 @@ extern "C" scalfmm_handle scalfmm_init(int TreeHeight,double BoxWidth,double* Bo
return handle;
}
#endif
extern "C" void scalfmm_dealloc_handle(scalfmm_handle handle, Callback_free_cell userDeallocator){
((ScalFmmCoreHandle *) handle)->engine->intern_dealloc_handle(userDeallocator);
delete ((ScalFmmCoreHandle *) handle)->engine ;
delete (ScalFmmCoreHandle *) handle;
}
......@@ -31,12 +31,32 @@ class CoreCell : public FBasicCell {
// Mutable in order to work with the API
mutable void* userData;
//Static members to be initialised before octree creation
static Scalfmm_Cell_Descriptor user_cell_descriptor;
public:
static void Init(Scalfmm_Cell_Descriptor cell_descriptor){
user_cell_descriptor=cell_descriptor;
}
static Callback_init_cell GetInit(){
return user_cell_descriptor.user_init_cell;
}
static Callback_free_cell GetFree(){
return user_cell_descriptor.user_free_cell;
}
CoreCell() : userData(nullptr) {
}
//We free the cells here
~CoreCell(){
if(userData){
this->user_cell_descriptor.user_free_cell(userData);
}
}
/**
* @brief setContainer store the ptr to the user data inside our
* struct
......@@ -54,6 +74,10 @@ public:
}
};
/**
* Define here static member
*/
Scalfmm_Cell_Descriptor CoreCell::user_cell_descriptor;
/**
* This class simply call the function pointers from Scalfmm_Kernel_Descriptor.
......@@ -142,8 +166,6 @@ public:
};
class FUserKernelEngine : public FScalFMMEngine{
private:
......@@ -153,10 +175,11 @@ private:
typedef FSimpleLeaf<ContainerClass> LeafClass;
typedef FOctree<CoreCell,ContainerClass,LeafClass> OctreeClass;
typedef CoreKernel<CoreCell,ContainerClass> CoreKernelClass;
typedef FP2PLeafInterface<OctreeClass> LeafInterface;
//For arranger classes
typedef FOctreeArranger<OctreeClass,ContainerClass,LeafInterface> ArrangerClass;
typedef FArrangerPeriodic<OctreeClass,ContainerClass,LeafInterface> ArrangerClassPeriodic;
typedef FBasicParticleContainerIndexedMover<OctreeClass, ContainerClass> MoverClass;
typedef FOctreeArranger<OctreeClass, ContainerClass, MoverClass> ArrangerClass;
typedef FArrangerPeriodic<OctreeClass, ContainerClass, MoverClass> ArrangerClassPeriodic;
//Attributes
......@@ -164,27 +187,45 @@ private:
CoreKernelClass * kernel;
ArrangerClass * arranger;
public:
FUserKernelEngine(int TreeHeight, double BoxWidth , double * BoxCenter, scalfmm_kernel_type KernelType) :
FUserKernelEngine(/*int TreeHeight, double BoxWidth , double * BoxCenter, */scalfmm_kernel_type KernelType) :
octree(nullptr), kernel(nullptr), arranger(nullptr){
octree = new OctreeClass(TreeHeight,FMath::Min(3,TreeHeight-1),BoxWidth,FPoint(BoxCenter));
// octree = new OctreeClass(TreeHeight,FMath::Min(3,TreeHeight-1),BoxWidth,FPoint(BoxCenter));
kernelType = KernelType;
//Kernel is not set now because the user must provide a
//Scalfmm_Kernel_descriptor
//kernel = new CoreKernelClass();
}
~FUserKernelEngine(){
delete octree;
if(arranger){
delete arranger;
}
if(kernel){
delete kernel;
}
}
void user_kernel_config( Scalfmm_Kernel_Descriptor userKernel, void * userDatas){
kernel = new CoreKernelClass(userKernel,userDatas);
if(!kernel){
kernel = new CoreKernelClass(userKernel,userDatas);
}
}
void build_tree(int TreeHeight,double BoxWidth,double* BoxCenter,Scalfmm_Cell_Descriptor user_cell_descriptor){
CoreCell::Init(user_cell_descriptor);
this->octree = new OctreeClass(TreeHeight,FMath::Min(3,TreeHeight-1),BoxWidth,FPoint(BoxCenter));
}
void tree_insert_particles( int NbPositions, double * arrayX, double * arrayY, double * arrayZ){
for(int idPart = 0; idPart<NbPositions ; ++idPart){
octree->insert(FPoint(arrayX[idPart],arrayY[idPart],arrayZ[idPart]),idPart);
}
nbPart += NbPositions;
this->init_cell();
}
void tree_insert_particles_xyz( int NbPositions, double * XYZ){
......@@ -194,19 +235,176 @@ public:
nbPart += NbPositions;
}
/**
* To retrieve the positions, in order to move the parts
*/
void get_positions_xyz(int NbPositions, double * positionsToFill){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
positionsToFill[indexes[idxPart]*3+0] = sources->getPositions()[0][idxPart];
positionsToFill[indexes[idxPart]*3+1] = sources->getPositions()[1][idxPart];
positionsToFill[indexes[idxPart]*3+2] = sources->getPositions()[2][idxPart];
}
});
}
void get_positions_xyz_npart(int NbPositions, int * idxOfParticles, double * positionsToFill){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
int iterPart = 0;
bool notFoundYet = true;
while(iterPart < NbPositions && notFoundYet){
if(indexes[idxPart] == idxOfParticles[iterPart]){
positionsToFill[indexes[idxPart]*3+0] = sources->getPositions()[0][idxPart];
positionsToFill[indexes[idxPart]*3+1] = sources->getPositions()[1][idxPart];
positionsToFill[indexes[idxPart]*3+2] = sources->getPositions()[2][idxPart];
notFoundYet = false;
}
else{
++iterPart;
}
}
}
});
}
void get_positions( int NbPositions, double * X, double * Y , double * Z){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
X[indexes[idxPart]] = sources->getPositions()[0][idxPart];
Y[indexes[idxPart]] = sources->getPositions()[1][idxPart];
Z[indexes[idxPart]] = sources->getPositions()[2][idxPart];
}
});
}
void get_positions_npart(int NbPositions, int * idxOfParticles,double * X, double * Y , double * Z){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
int iterPart = 0;
bool notFoundYet = true;
while(iterPart < NbPositions && notFoundYet){
if(indexes[idxPart] == idxOfParticles[iterPart]){
X[indexes[idxPart]] = sources->getPositions()[0][idxPart];
Y[indexes[idxPart]] = sources->getPositions()[1][idxPart];
Z[indexes[idxPart]] = sources->getPositions()[2][idxPart];
notFoundYet = false;
}
else{
++iterPart;
}
}
}
});
}
//Arranger parts : following function provide a way to move parts
//inside the tree
void add_to_positions_xyz(int NbPositions,double * updatedXYZ){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
sources->getWPositions()[0][idxPart] += updatedXYZ[indexes[idxPart]*3+0];
sources->getWPositions()[1][idxPart] += updatedXYZ[indexes[idxPart]*3+1];
sources->getWPositions()[2][idxPart] += updatedXYZ[indexes[idxPart]*3+2];
}
});
}
void add_to_positions(int NbPositions,double * X, double * Y , double * Z){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
sources->getWPositions()[0][idxPart] += X[indexes[idxPart]];
sources->getWPositions()[1][idxPart] += Y[indexes[idxPart]];
sources->getWPositions()[2][idxPart] += Z[indexes[idxPart]];
}
});
}
void set_positions_xyz(int NbPositions, double * updatedXYZ){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
sources->getWPositions()[0][idxPart] = updatedXYZ[indexes[idxPart]*3+0];
sources->getWPositions()[1][idxPart] = updatedXYZ[indexes[idxPart]*3+1];
sources->getWPositions()[2][idxPart] = updatedXYZ[indexes[idxPart]*3+2];
}
});
}
void set_positions(int NbPositions, double * X, double * Y, double * Z){
octree->forEachLeaf([&](LeafClass* leaf){
ContainerClass * sources = leaf->getSrc();
const FVector<int>& indexes = sources->getIndexes();
int nbPartThere = sources->getNbParticles();
for(int idxPart = 0 ; idxPart<nbPartThere ; ++idxPart){
sources->getWPositions()[0][idxPart] = X[indexes[idxPart]];
sources->getWPositions()[1][idxPart] = Y[indexes[idxPart]];
sources->getWPositions()[2][idxPart] = Z[indexes[idxPart]];
}
});
}
void update_tree(){
if(arranger){
arranger->rearrange();
//then, we need to re-allocate cells user data for the
//cells created during the process and free user datas for
//the cells removed during the process
init_cell();
}
else{
if(Algorithm == 2){ //case in wich the periodic algorithm is used
arranger = new ArrangerClassPeriodic(octree);
arranger->rearrange();
}
else{
arranger = new ArrangerClass(octree);
arranger->rearrange();
init_cell();
}
}
}
/*
* Call the user allocator on userDatas member field of each cell
*/
void init_cell(Callback_init_cell user_cell_initializer){
if(user_cell_initializer){