FQuick.dox 15.9 KB
 PIACIBELLO Cyrille committed Nov 29, 2013 1 2 3 /*! \page quick Quick Start * In this section, we present the data structure organization and the  BRAMAS Berenger committed Sep 01, 2014 4 5  * classes design to understand fully ScalFmm and customized it.  BRAMAS Berenger committed Sep 03, 2014 6  * Remark : There is a big difference between the versions 1.0 and 2.0  BRAMAS Berenger committed Sep 01, 2014 7 8  * since we do not store array of particles anymore but rather several arrays. * This was needed in order to be able to vectorize the P2P code.  PIACIBELLO Cyrille committed Nov 29, 2013 9   BRAMAS Berenger committed Sep 03, 2014 10 11 12 13 14 15 16 17 18  * We would like to inform users that are not familiar with 'C++' and * who are familiar with 'C' and would like to create a kernel * (and do not want to work on the parallelization), * that an C API have been made for them. * In order to get access to this API, go in Addons/CKernelApi. * (To compile, enable the addons and then the CKernelApi). * However, to have access to all the features of ScalFmm it is required to use C++ * as described in this QuickStart.  PIACIBELLO Cyrille committed Nov 29, 2013 19 20 21 22  * \tableofcontents * \section prerequisite Prerequisite  BRAMAS Berenger committed Sep 01, 2014 23 24  * It is recommanded to have built the library or at minimum to have * downloaded the sources code. The user needs to be comfortable with 'C++'  PIACIBELLO Cyrille committed Nov 29, 2013 25 26  * language and if possible templates.  PIACIBELLO Cyrille committed Dec 04, 2013 27 28  * If you want to browse the code, you may want to see first our \ref rules.  PIACIBELLO Cyrille committed Dec 03, 2013 29   PIACIBELLO Cyrille committed Nov 29, 2013 30 31 32 33 34 35 36 37  * \section classes Overview of general architecture * * \image html Classes.png "General architecture" * \section data What Data * In ScalFmm we proceed the Fast Multipole Method. New users should see * this process has a way to estimate far interactions and compute  BRAMAS Berenger committed Sep 01, 2014 38 39  * accurately the close interactions in a group of particles. We start * with some particles that we insert in a octree. The octree stores the  PIACIBELLO Cyrille committed Nov 29, 2013 40 41 42 43 44 45 46  * particles in its leaves. From the root to the leaves there are the * cells. At this point we only express primitives classes which hold * data or primitives classes. * Then, we need a kernel which is computational part of the FMM. It is a * class that is able to compute the interactions between particles or * cells, etc. There is several possible kernels depending on what we  BRAMAS Berenger committed Sep 01, 2014 47  * want to compute and it is easy to implement your own.  PIACIBELLO Cyrille committed Nov 29, 2013 48 49 50 51  * Finally, the FMM Core algorithm is a class that takes the primitives * classes and calls the kernel with the correct arguments. In our * implementation, the user has to choose between sequential FMM or  BRAMAS Berenger committed Sep 01, 2014 52  * OpenMP FMM or even MPI FMM.  PIACIBELLO Cyrille committed Nov 29, 2013 53 54 55 56 57  * \section primitivesclasses Primitives Classes * \subsection particles Particles  BRAMAS Berenger committed Sep 01, 2014 58 59 60 61 62 63  * In order to put the particles in the right leaf, the octree needs to know its spatial position. * Then, then once the right leaf is found it is allocated (using the given template LeafClass of the octree), * and the particles is pushed into the leaf. If a basic leaf is used, this one only push to a particles container * what it has received. So a particles container is nothing more than a class that has a push method * which matches the one you call on the octree. To ensure that, * a particle container should inherit from FAbstractParticleContainer.  PIACIBELLO Cyrille committed Nov 29, 2013 64 65  *

BRAMAS Berenger committed Sep 01, 2014     66                                                                                                                                                                                                                                                                                                                                                                                            * class FAbstractParticleContainer{  
PIACIBELLO Cyrille committed Nov 29, 2013  67     68                                                                                                                                                                                                                                                                                                                                                                                     * template  * void push(const FPoint& , Args ... ){ 
BRAMAS Berenger committed Sep 01, 2014     69     70     71     72     73     74     75     76     77     78     79     80     81     82     83     84     85     86     87     88     89     90     91     92     93     94     95     96     97     98     99     100     101     102     103     104                                                                                                                                  *      // This method should be specialed  * };  *
* Here is how we can print the index of the particles that is inserted from a particles containers : *
* class MyCustomContainer : public FAbstractParticleContainer{   * template  * void push(const FPoint& , int particleIndex, double anythingElse){  *      std::cout << "The particle " << particleIndex << " has just been inserted with " << anythingElse << "\n";  * };  *  * // In the main  *     typedef MyCustomContainer      ContainerClass;  *     typedef FSimpleLeaf< ContainerClass >                     LeafClass;  *     typedef FOctree< FBasicCell, ContainerClass , LeafClass >  OctreeClass;  * // From your system properties  * OctreeClass tree(treeHeight, subHeight, loader.getBoxWidth(), loader.getCenterOfBox());  *  * // Add a particle  * tree.push(FPoint(x, y, z), particleIndex, anythingElse);  * // The octree will push in the FSimpleLeaf which will push in the MyCustomContainer which will print the message.  *
* In the same way you can sort your particles in different buffer by passing a flag which will be passed to your container: *
* class MyCustomContainer : public FAbstractParticleContainer{   * std::vector bigParticles;  * std::vector smallParticles;  * template  * void push(const FPoint& , bool isBig, int particleIndex){  *      if(isBig) bigParticles.push_back(particleIndex);  *      else smallParticles.push_back(particleIndex);         
PIACIBELLO Cyrille committed Nov 29, 2013  105                                                                                                                                                                                                                                                                                                                                                                                           * }; 
BRAMAS Berenger committed Sep 01, 2014     106     107     108     109     110     111     112     113     114     115     116                                                                                                                                                                                                                                                                                                           *  * // In the main  *     typedef MyCustomContainer      ContainerClass;  *     typedef FSimpleLeaf< ContainerClass >                     LeafClass;  *     typedef FOctree< FBasicCell, ContainerClass , LeafClass >  OctreeClass;  * // From your system properties  * OctreeClass tree(treeHeight, subHeight, loader.getBoxWidth(), loader.getCenterOfBox());  *  * // Add a particle  * tree.push(FPoint(x, y, z), boolIsBigParticle, particleIndex);  * // The octree will push in the FSimpleLeaf which will push in the MyCustomContainer which will store idx in the correct vector 
PIACIBELLO Cyrille committed Nov 29, 2013  117     118                                                                                                                                                                                                                                                                                                                                                                                   *
 BRAMAS Berenger committed Sep 01, 2014 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166  * The FBasicParticleContainer class is given for those who would like to store one or several data type * of the same kind per particles (and their position). * For example if some one want to store one (or several) integers for the particles or * one (or several) double values per particles. *
*  // Declaration  * template   * class FBasicParticleContainer : public FAbstractParticleContainer, public FAbstractSerializable;   *
* If for example you would like to store 2 doubles per particles (one intialized during the push * wherease the other if set to 0) you can use the following code: *
*     typedef FBasicParticleContainer< 2, double>      ContainerClass;  *     typedef FSimpleLeaf< ContainerClass >                     LeafClass;  *     typedef FOctree< FBasicCell, ContainerClass , LeafClass >  OctreeClass;  * // From your system properties  * OctreeClass tree(treeHeight, subHeight, loader.getBoxWidth(), loader.getCenterOfBox());  *  * // Add a particle  * tree.push(FPoint(x, y, z), myFirstDouble); //, mySecondValueIfNotZero);  *  * // Then to print all the doubles value :  * tree.forEachLeaf([&](LeafClass* lf){  *      ContainerClass* container = lf->getSrc();  *      int nbParticlesInLeaf = container->getNbParticles();  *      double* x_pos = container->getPositions()[0];  *      double* y_pos = container->getPositions()[1];  *      double* z_pos = container->getPositions()[2];  *      double* firstDoubleArray = container->getAttribute(0); // same as getAttribute<0>()  *      double* secondDoubleArray = container->getAttribute(1); // same as getAttribute<1>()  *  *      for(int idxPart = 0 ; idxPart < nbParticlesInLeaf ; ++idxPart){  *          std::cout << "Particle inserted " << idxPart << " in the leaf\n";  *          std::cout << "Has position " << x_pos[idxPart] << " " << y_pos[idxPart] << " " << z_part[idxPart] << "\n";  *          std::cout << "And values " << firstDoubleArray[idxPart] << " and " << secondDoubleArray[idxPart] << "\n";  *      }  * });  *
* Therefor, we propose a particle container called FP2PParticleContainer to store the position, * a force vector, a potential and a physical value per particle. * This container is one used in our kernels and you can read our P2P (or P2M/L2P) in order to catch * the way it works.  PIACIBELLO Cyrille committed Nov 29, 2013 167 168 169 170 171 172  * \subsection cells Cells * The same principle apply to cells. There is a minimum sets of * methods that must propose a cell class to be able to be used in the * octree. And then, there are some other methods that you can add to  BRAMAS Berenger committed Sep 01, 2014 173  * make it usable per your kernel.  PIACIBELLO Cyrille committed Nov 29, 2013 174 175 176 177 178 179 180 181 182 183 184 185 186 187  * The class Src/Components/FAbstractCell.hpp shows what should * implement a cell: *
* class FAbstractCell{    *  public:    *  virtual ~FAbstractCell(){    *  }    *  virtual MortonIndex getMortonIndex() const = 0;    *  virtual void setMortonIndex(const MortonIndex inIndex) = 0;    *  virtual void setPosition(const FPoint& inPosition) = 0;    *  virtual const FTreeCoordinate& getCoordinate() const = 0;    *  virtual void setCoordinate(const long inX, const long inY, const long inZ) = 0;  
BRAMAS Berenger committed Sep 01, 2014     188     189     190     191                                                                                                                                                                                                                                                                                                                                                                    *  virtual bool hasSrcChild() const = 0;  // Needed if TSM (target source model) is used   *  virtual bool hasTargetsChild() const = 0;   // Needed if TSM (target source model) is used   *  virtual void setSrcChildTrue() = 0;   // Needed if TSM (target source model) is used   *  virtual void setTargetsChildTrue() = 0;   // Needed if TSM (target source model) is used 
PIACIBELLO Cyrille committed Nov 29, 2013  192     193     194     195     196     197     198     199     200     201     202     203     204     205     206     207     208                                                                                                                                                                                                                                                            *  };   *
* The FBasicCell class provides an implementation of all these * methods. * \subsection leaves Leaves * The leaf is the class responsible of hosting the particles. The * octree uses this class and order to store a particle. Behind the * scene, the leaf does what it wants. But, the octree also needs a way * to get the particles it has inserted which can be targets or * sources * In the following class, FAbstractLeaf, one can see what is required * by the algorithm :  BRAMAS Berenger committed Sep 01, 2014 209  *

PIACIBELLO Cyrille committed Nov 29, 2013  210     211     212     213     214                                                                                                                                                                                                                                                                                                                                                           * template< class ParticleClass, class ContainerClass >   *   class FAbstractLeaf {   *   public:   *   // Default destructor  *   virtual ~FAbstractLeaf(){  
BRAMAS Berenger committed Sep 01, 2014     215     216     217     218     219                                                                                                                                                                                                                                                                                                                                                           *   }       *  template  *   void push(const FPoint& inParticlePosition, Args ... args){  *       FLOG( FLog::Controller.write("Warning, push is not implemented!").write(FLog::Flush) );  *   } 
PIACIBELLO Cyrille committed Nov 29, 2013  220     221     222     223     224                                                                                                                                                                                                                                                                                                                                                           *   virtual ContainerClass* getSrc() = 0;   *   virtual ContainerClass* getTargets() = 0;   *   };   *
 BRAMAS Berenger committed Sep 01, 2014 225  * The FSimpleLeaf class provides an implementation of all these methods.  PIACIBELLO Cyrille committed Nov 29, 2013 226 227 228  * \subsection loading Loading Particle  BRAMAS Berenger committed Sep 01, 2014 229 230 231  * In most of our examples, we are using "loaders" which are classes used to manage the files. * They returned the physical properties (box width, center of box, ...) which are used to build the octree. * Then they are used to get the particle positions (and their physical values if appropriate).  PIACIBELLO Cyrille committed Nov 29, 2013 232   BRAMAS Berenger committed Sep 01, 2014 233  *

PIACIBELLO Cyrille committed Nov 29, 2013  234     235     236     237     238     239     240     241     242     243                                                                                                                                                                                                                                                                                                                   * template    *   class FAbstractLoader {   *   public:	   *   // Default destructor   *   virtual ~FAbstractLoader(){   *   }   *   virtual FSize getNumberOfParticles() const = 0;   *   virtual FPoint getCenterOfBox() const = 0;   *   virtual FReal getBoxWidth() const = 0;   *   virtual bool isOpen() const = 0;  
BRAMAS Berenger committed Sep 01, 2014     244                                                                                                                                                                                                                                                                                                                                                                                           *   void fillTree(FPoint& particlesPos); 
PIACIBELLO Cyrille committed Nov 29, 2013  245     246     247                                                                                                                                                                                                                                                                                                                                                                           *  };   *
 BRAMAS Berenger committed Sep 01, 2014 248 249 250 251  * There exist several loaders; one per file format. * Usually we do as the following: *
* FRandomLoader loader(NbPart, 1, FPoint(0.5,0.5,0.5), 1); 
PIACIBELLO Cyrille committed Nov 29, 2013  252                                                                                                                                                                                                                                                                                                                                                                                           * OctreeClass tree(10, 3, loader.getBoxWidth(), loader.getCenterOfBox()); 
BRAMAS Berenger committed Sep 01, 2014     253     254     255     256     257                                                                                                                                                                                                                                                                                                                                                           * FPoint particlePosition;  * for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){  *     loader.fillParticle(&particlePosition);  *     tree.insert(particlePosition);  * } 
PIACIBELLO Cyrille committed Nov 29, 2013  258     259     260     261                                                                                                                                                                                                                                                                                                                                                                   *
* \subsection octreeIterator Iterating on an Octree  BRAMAS Berenger committed Sep 01, 2014 262 263  * There are two ways to iterate on the data of an octree : * Using an iterator, or using a lambda function.  PIACIBELLO Cyrille committed Nov 29, 2013 264   BRAMAS Berenger committed Sep 01, 2014 265  * This next sample is taken from Tests/Utils/testOctreeIter.cpp and count the leaves :  PIACIBELLO Cyrille committed Nov 29, 2013 266   BRAMAS Berenger committed Sep 01, 2014 267  *

PIACIBELLO Cyrille committed Nov 29, 2013  268     269     270     271     272     273     274                                                                                                                                                                                                                                                                                                                                           * OctreeClass::Iterator octreeIterator(&tree);  *     octreeIterator.gotoBottomLeft();  *     int counter = 0;  *     do{  *             ++counter;  *     } while(octreeIterator.moveRight());  *
 BRAMAS Berenger committed Sep 01, 2014 275 276 277 278 279  * But here is the equivalent using lambda function: * long counter = 0; * tree.forEachLeaf([&](LeafClass* leaf){ * ++counter; * });  PIACIBELLO Cyrille committed Nov 29, 2013 280 281  * To iterate on the cells we can proceed as follow :  BRAMAS Berenger committed Sep 01, 2014 282  *

PIACIBELLO Cyrille committed Nov 29, 2013  283     284     285     286     287     288     289     290     291     292     293     294                                                                                                                                                                                                                                                                                                   * OctreeClass::Iterator octreeIterator(&tree);  * octreeIterator.gotoBottomLeft();  * for(int idxLevel = NbLevels - 1 ; idxLevel >= 1 ; --idxLevel ){  *    int counter = 0;  *    do{  *       ++counter;  *    } while(octreeIterator.moveRight());  *    octreeIterator.moveUp();  *    octreeIterator.gotoLeft();  *    std::cout << "Cells at level " << idxLevel << " = " << counter << " ...\n";  * }  *
 BRAMAS Berenger committed Sep 01, 2014 295 296 297 298 299 300  * Here is an equivalent: *
*  long nbCells[TreeHeight];   *  tree.forEachCellWithLevel([&nbCells](CellClass* cell, int idxLevel){   *      nbCells[idxLevel] += 1;   *  }); 
PIACIBELLO Cyrille committed Nov 29, 2013  301     302     303                                                                                                                                                                                                                                                                                                                                                                            * \section kernel The kernel   
BRAMAS Berenger committed Sep 01, 2014     304                                                                                                                                                                                                                                                                                                                                                                                           * Kernel refers to the class that perform the computation. 
PIACIBELLO Cyrille committed Nov 29, 2013  305     306     307     308                                                                                                                                                                                                                                                                                                                                                                    * An empty kernel can be found in Src/Components/FBasicKernels.hpp,  * it implements the class definition FAbstractKernels :  
BRAMAS Berenger committed Sep 01, 2014     309     310                                                                                                                                                                                                                                                                                                                                                                                   *
* template< class CellClass, class ContainerClass> class FBasicKernels : public FAbstractKernels {  
PIACIBELLO Cyrille committed Nov 29, 2013  311     312     313     314     315     316     317     318     319     320     321     322     323     324     325     326     327     328     329     330     331     332     333     334                                                                                                                                                                                                   * public:   *  * // Default destructor  * virtual ~FBasicKernels(){}  * virtual void P2M(CellClass* const , const ContainerClass* const ) {}  * virtual void M2M(CellClass* const FRestrict , const CellClass*const FRestrict *const FRestrict , const int ) {}   * virtual void M2L(CellClass* const FRestrict , const CellClass* [], const int , const int ) {}  * virtual void L2L(const CellClass* const FRestrict , CellClass* FRestrict *const FRestrict  , const int ) {}  * virtual void L2P(const CellClass* const , ContainerClass* const ){}  * virtual void P2P(const FTreeCoordinate& ,   *                  ContainerClass* const FRestrict , const ContainerClass* const FRestrict ,   *                  ContainerClass* const [27], const int ){}  * virtual void P2PRemote(const FTreeCoordinate& ,   *                  ContainerClass* const FRestrict , const ContainerClass* const FRestrict ,   *                  ContainerClass* const [27], const int ){}  *
* One example of kernel is the 'test' kernel called * FTestKernels. This kernels simply sum the particles (one particle * weigh = 1) so at the end of the simulation each particles should be * have a weigh of N. We just declare this kernel based on the * components type but usually do not call any method manually since * this is performed per the FMM core.  BRAMAS Berenger committed Sep 01, 2014 335 336  *
* typedef FTestKernels         KernelClass; 
PIACIBELLO Cyrille committed Nov 29, 2013  337     338     339     340     341     342     343     344     345     346     347     348     349                                                                                                                                                                                                                                                                                           * KernelClass kernels;  *
* \section coreFMM The FMM Core * We showed how to have an octree and a kernel. Now, we show how to use * a Fmm Algorithm on the data. Remember, the FMM algorithm simply * takes the data from the octree and call the method of the * kernel. The goal is to have a FMM independent from the data. * The next sample is taken from Tests/Utils/testFmmAlgorithm.cpp and * use the basic sequential FMM :  BRAMAS Berenger committed Sep 01, 2014 350 351  *
* typedef FFmmAlgorithm     FmmClass; 
PIACIBELLO Cyrille committed Nov 29, 2013  352     353     354     355     356     357     358                                                                                                                                                                                                                                                                                                                                           * FmmClass algo(&tree,&kernels);  * algo.execute();  *
* To move to the OpenMP threaded FMM we can use the fallowing code by * changing 'FFmmAlgorithm' per 'FFmmAlgorithmThread' :  BRAMAS Berenger committed Sep 01, 2014 359 360  *
* typedef FFmmAlgorithmThread     FmmClass; 
PIACIBELLO Cyrille committed Nov 29, 2013  361     362     363     364     365     366     367     368     369     370     371     372     373     374                                                                                                                                                                                                                                                                                   * FmmClass algo(&tree,&kernels);  * algo.execute();  *
\section reasons The reasons why ... * Of course the library is changing and re-factorized usually but * lets discuss about 'The reasons why' : *
*
• Every things is templatized : *
* The reason is to avoid the use of virtual and abstract class. In * this page we present some abstract classes, but they are not really  BRAMAS Berenger committed Sep 01, 2014 375 376  * use. They only define what we need, the minimum required to implement a * particle container or a cell. But the kernels should not work on an abstract  PIACIBELLO Cyrille committed Nov 29, 2013 377 378 379 380 381 382 383 384 385 386  * type but on the real data. This enable lots of compiler * optimizations and avoid the use of V-Table. *
*
• *
• * Typedef is used like this : *
* It can take some time to understand how it works. But all our users * finally like the way of using typedef and template. As you will see  BRAMAS Berenger committed Sep 01, 2014 387 388  * in most of the examples the struct is the same and you will not be * lost.  PIACIBELLO Cyrille committed Nov 29, 2013 389 390 391 392 393 394 395  *
*
• *
*/