LCOV - code coverage report
Current view: top level - src/Particle - ParticleBase.h (source / functions) Coverage Total Hit
Test: report.info Lines: 72.7 % 22 16
Test Date: 2025-05-21 10:57:37 Functions: 71.0 % 372 264
Branches: 65.5 % 168 110

             Branch data     Line data    Source code
       1                 :             : //
       2                 :             : // Class ParticleBase
       3                 :             : //   Base class for all user-defined particle classes.
       4                 :             : //
       5                 :             : //   ParticleBase is a container and manager for a set of particles.
       6                 :             : //   The user must define a class derived from ParticleBase which describes
       7                 :             : //   what specific data attributes the particle has (e.g., mass or charge).
       8                 :             : //   Each attribute is an instance of a ParticleAttribute<T> class; ParticleBase
       9                 :             : //   keeps a list of pointers to these attributes, and performs particle creation
      10                 :             : //   and destruction.
      11                 :             : //
      12                 :             : //   ParticleBase is templated on the ParticleLayout mechanism for the particles.
      13                 :             : //   This template parameter should be a class derived from ParticleLayout.
      14                 :             : //   ParticleLayout-derived classes maintain the info on which particles are
      15                 :             : //   located on which processor, and performs the specific communication
      16                 :             : //   required between processors for the particles.  The ParticleLayout is
      17                 :             : //   templated on the type and dimension of the atom position attribute, and
      18                 :             : //   ParticleBase uses the same types for these items as the given
      19                 :             : //   ParticleLayout.
      20                 :             : //
      21                 :             : //   ParticleBase and all derived classes have the following common
      22                 :             : //   characteristics:
      23                 :             : //       - The spatial positions of the N particles are stored in the
      24                 :             : //         particle_position_type variable R
      25                 :             : //       - The global index of the N particles are stored in the
      26                 :             : //         particle_index_type variable ID
      27                 :             : //       - A pointer to an allocated layout class.  When you construct a
      28                 :             : //         ParticleBase, you must provide a layout instance, and ParticleBase
      29                 :             : //         will delete this instance when it (the ParticleBase) is deleted.
      30                 :             : //
      31                 :             : //   To use this class, the user defines a derived class with the same
      32                 :             : //   structure as in this example:
      33                 :             : //
      34                 :             : //     class UserParticles :
      35                 :             : //              public ParticleBase< ParticleSpatialLayout<double,3> > {
      36                 :             : //     public:
      37                 :             : //       // attributes for this class
      38                 :             : //       ParticleAttribute<double> rad;  // radius
      39                 :             : //       particle_position_type    vel;  // velocity, same storage type as R
      40                 :             : //
      41                 :             : //       // constructor: add attributes to base class
      42                 :             : //       UserParticles(ParticleSpatialLayout<double,2>* L) : ParticleBase(L) {
      43                 :             : //         addAttribute(rad);
      44                 :             : //         addAttribute(vel);
      45                 :             : //       }
      46                 :             : //     };
      47                 :             : //
      48                 :             : //   This example defines a user class with 3D position and two extra
      49                 :             : //   attributes: a radius rad (double), and a velocity vel (a 3D Vector).
      50                 :             : //
      51                 :             : #ifndef IPPL_PARTICLE_BASE_H
      52                 :             : #define IPPL_PARTICLE_BASE_H
      53                 :             : 
      54                 :             : #include <tuple>
      55                 :             : #include <type_traits>
      56                 :             : #include <vector>
      57                 :             : 
      58                 :             : #include "Types/IpplTypes.h"
      59                 :             : 
      60                 :             : #include "Utility/TypeUtils.h"
      61                 :             : 
      62                 :             : #include "Particle/ParticleLayout.h"
      63                 :             : 
      64                 :             : namespace ippl {
      65                 :             : 
      66                 :             :     /*!
      67                 :             :      * @class ParticleBase
      68                 :             :      * @tparam PLayout the particle layout implementing an algorithm to
      69                 :             :      * distribute the particles among MPI ranks
      70                 :             :      * @tparam IDProperties the view properties for particle IDs (if any
      71                 :             :      * of the provided types is ippl::DisableParticleIDs, then particle
      72                 :             :      * IDs will be disabled for the bunch)
      73                 :             :      */
      74                 :             :     template <class PLayout, typename... IDProperties>
      75                 :             :     class ParticleBase {
      76                 :             :         constexpr static bool EnableIDs = sizeof...(IDProperties) > 0;
      77                 :             : 
      78                 :             :     public:
      79                 :             :         using vector_type            = typename PLayout::vector_type;
      80                 :             :         using index_type             = typename PLayout::index_type;
      81                 :             :         using particle_position_type = typename PLayout::particle_position_type;
      82                 :             :         using particle_index_type    = ParticleAttrib<index_type, IDProperties...>;
      83                 :             : 
      84                 :             :         using Layout_t = PLayout;
      85                 :             : 
      86                 :             :         template <typename... Properties>
      87                 :             :         using attribute_type = typename detail::ParticleAttribBase<Properties...>;
      88                 :             : 
      89                 :             :         template <typename MemorySpace>
      90                 :             :         using container_type = std::vector<attribute_type<MemorySpace>*>;
      91                 :             : 
      92                 :             :         using attribute_container_type =
      93                 :             :             typename detail::ContainerForAllSpaces<container_type>::type;
      94                 :             : 
      95                 :             :         using bc_container_type = typename PLayout::bc_container_type;
      96                 :             : 
      97                 :             :         using hash_container_type = typename detail::ContainerForAllSpaces<detail::hash_type>::type;
      98                 :             : 
      99                 :             :         using size_type = detail::size_type;
     100                 :             : 
     101                 :             :     public:
     102                 :             :         //! view of particle positions
     103                 :             :         particle_position_type R;
     104                 :             : 
     105                 :             :         //! view of particle IDs
     106                 :             :         particle_index_type ID;
     107                 :             : 
     108                 :             :         /*!
     109                 :             :          * If this constructor is used, the user must call 'initialize' with
     110                 :             :          * a layout object in order to use this.
     111                 :             :          */
     112                 :             :         ParticleBase();
     113                 :             : 
     114                 :             :         /*!
     115                 :             :          * Ctor called when layout is provided with std::shared_ptr. It
     116                 :             :          * calls the default ctor which then calls the private ctor. The
     117                 :             :          * layout instance is moved to this class, hence, the argument
     118                 :             :          * is null afterwards, i.e., layout == nullptr.
     119                 :             :          * @param layout to be moved.
     120                 :             :          */
     121                 :             :         ParticleBase(Layout_t& layout);
     122                 :             : 
     123                 :             :         /* cannot use '= default' since we get a
     124                 :             :          * compiler warning otherwise:
     125                 :             :          * warning: calling a __host__ function("std::vector< ::ippl::detail::ParticleAttribBase *,
     126                 :             :          * ::std::allocator<
     127                 :             :          * ::ippl::detail::ParticleAttribBase *> > ::~vector") from a __host__ __device__
     128                 :             :          * function("ippl::ParticleBase<
     129                 :             :          * ::ippl::ParticleLayout<double, (unsigned int)3u> > ::~ParticleBase") is not allowed
     130                 :             :          */
     131                 :         204 :         ~ParticleBase() {}  // = default; //{ }
     132                 :             : 
     133                 :             :         /*!
     134                 :             :          * Initialize the particle layout. Needs to be called
     135                 :             :          * when the ParticleBase instance is constructed with the
     136                 :             :          * default ctor.
     137                 :             :          */
     138                 :             :         void initialize(Layout_t& layout);
     139                 :             : 
     140                 :             :         /*!
     141                 :             :          * @returns processor local number of particles
     142                 :             :          */
     143                 :        3144 :         size_type getLocalNum() const { return localNum_m; }
     144                 :             : 
     145                 :             :         void setLocalNum(size_type size) { localNum_m = size; }
     146                 :             : 
     147                 :             :         /*!
     148                 :             :          * @returns total number of particles (across all processes)
     149                 :             :          */
     150                 :             :         size_type getTotalNum() const { return totalNum_m; }
     151                 :             : 
     152                 :             :         /*!
     153                 :             :          * @returns particle layout
     154                 :             :          */
     155                 :         120 :         Layout_t& getLayout() { return *layout_m; }
     156                 :             : 
     157                 :             :         /*!
     158                 :             :          * @returns particle layout
     159                 :             :          */
     160                 :             :         const Layout_t& getLayout() const { return *layout_m; }
     161                 :             : 
     162                 :             :         /*!
     163                 :             :          * Set all boundary conditions
     164                 :             :          * @param bc the boundary conditions
     165                 :             :          */
     166                 :          12 :         void setParticleBC(const bc_container_type& bcs) { layout_m->setParticleBC(bcs); }
     167                 :             : 
     168                 :             :         /*!
     169                 :             :          * Set all boundary conditions to this BC
     170                 :             :          * @param bc the boundary conditions
     171                 :             :          */
     172                 :          96 :         void setParticleBC(BC bc) { layout_m->setParticleBC(bc); }
     173                 :             : 
     174                 :             :         /*!
     175                 :             :          * Add particle attribute
     176                 :             :          * @param pa attribute to be added to ParticleBase
     177                 :             :          */
     178                 :             :         template <typename MemorySpace>
     179                 :             :         void addAttribute(detail::ParticleAttribBase<MemorySpace>& pa);
     180                 :             : 
     181                 :             :         /*!
     182                 :             :          * Get particle attribute
     183                 :             :          * @param i attribute number in container
     184                 :             :          * @returns a pointer to the attribute
     185                 :             :          */
     186                 :             :         template <typename MemorySpace = Kokkos::DefaultExecutionSpace::memory_space>
     187                 :             :         attribute_type<MemorySpace>* getAttribute(size_t i) {
     188                 :             :             return attributes_m.template get<MemorySpace>()[i];
     189                 :             :         }
     190                 :             : 
     191                 :             :         /*!
     192                 :             :          * Calls a given function for all attributes in the bunch
     193                 :             :          * @tparam MemorySpace the memory space of the attributes to visit (void to visit all of
     194                 :             :          * them)
     195                 :             :          * @tparam Functor the functor type
     196                 :             :          * @param f a functor taking a single ParticleAttrib<MemorySpace>
     197                 :             :          */
     198                 :             :         template <typename MemorySpace = void, typename Functor>
     199                 :           0 :         void forAllAttributes(Functor&& f) const {
     200                 :             :             if constexpr (std::is_void_v<MemorySpace>) {
     201                 :             :                 attributes_m.forAll(f);
     202                 :             :             } else {
     203   [ #  #  #  # ]:           0 :                 for (auto& attribute : attributes_m.template get<MemorySpace>()) {
     204         [ #  # ]:           0 :                     f(attribute);
     205                 :             :                 }
     206                 :             :             }
     207                 :           0 :         }
     208                 :             : 
     209                 :             :         // Non-const variant of same function
     210                 :             :         template <typename MemorySpace = void, typename Functor>
     211                 :         180 :         void forAllAttributes(Functor&& f) {
     212                 :             :             if constexpr (std::is_void_v<MemorySpace>) {
     213         [ +  - ]:         360 :                 attributes_m.forAll([&]<typename Attributes>(Attributes& atts) {
     214   [ +  +  +  +  :         456 :                     for (auto& attribute : atts) {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  + ]
           [ +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  +  
                      + ]
           [ #  #  #  # ]
     215   [ +  -  +  -  :         276 :                         f(attribute);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
           [ +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
           [ #  #  #  # ]
     216                 :             :                     }
     217                 :             :                 });
     218                 :             :             } else {
     219   [ #  #  #  # ]:           0 :                 for (auto& attribute : attributes_m.template get<MemorySpace>()) {
     220         [ #  # ]:           0 :                     f(attribute);
     221                 :             :                 }
     222                 :             :             }
     223                 :         180 :         }
     224                 :             : 
     225                 :             :         /*!
     226                 :             :          * @returns the number of attributes
     227                 :             :          */
     228                 :          12 :         unsigned getAttributeNum() const {
     229                 :          12 :             unsigned total = 0;
     230         [ +  - ]:          36 :             detail::runForAllSpaces([&]<typename MemorySpace>() {
     231                 :          12 :                 total += attributes_m.template get<MemorySpace>().size();
     232                 :             :             });
     233                 :          12 :             return total;
     234                 :             :         }
     235                 :             : 
     236                 :             :         /*!
     237                 :             :          * Create nLocal processor local particles. This is a collective call,
     238                 :             :          * i.e. all MPI ranks must call this.
     239                 :             :          * @param nLocal number of local particles to be created
     240                 :             :          */
     241                 :             :         void create(size_type nLocal);
     242                 :             : 
     243                 :             :         /*!
     244                 :             :          * Create a new particle with a given ID. This is a collective call. If a process
     245                 :             :          * passes a negative number, it does not create a particle.
     246                 :             :          * @param id particle identity number
     247                 :             :          */
     248                 :             :         void createWithID(index_type id);
     249                 :             : 
     250                 :             :         /*!
     251                 :             :          * Create nTotal particles globally, equally distributed among all processors.
     252                 :             :          * This is a collective call.
     253                 :             :          * @param nTotal number of total particles to be created
     254                 :             :          */
     255                 :             :         void globalCreate(size_type nTotal);
     256                 :             : 
     257                 :             :         /*!
     258                 :             :          * Particle deletion Function. Partition the particles into a valid region
     259                 :             :          * and an invalid region,
     260                 :             :          * effectively deleting the invalid particles. This is a collective call.
     261                 :             :          * @param invalid View marking which indices are invalid
     262                 :             :          * @param destroyNum Total number of invalid particles
     263                 :             :          */
     264                 :             :         template <typename... Properties>
     265                 :             :         void destroy(const Kokkos::View<bool*, Properties...>& invalid, const size_type destroyNum);
     266                 :             : 
     267                 :             :         // This is a collective call.
     268                 :          84 :         void update() { layout_m->update(*this); }
     269                 :             : 
     270                 :             :         /*
     271                 :             :          * The following functions should not be called in an application.
     272                 :             :          */
     273                 :             : 
     274                 :             :         /* This function does not alter the totalNum_m member function. It should only be called
     275                 :             :          * during the update function where we know the number of particles remains the same.
     276                 :             :          */
     277                 :             :         template <typename... Properties>
     278                 :             :         void internalDestroy(const Kokkos::View<bool*, Properties...>& invalid,
     279                 :             :                              const size_type destroyNum);
     280                 :             : 
     281                 :             :         /*!
     282                 :             :          * Sends particles to another rank
     283                 :             :          * @tparam HashType the hash view type
     284                 :             :          * @param rank the destination rank
     285                 :             :          * @param tag the MPI tag
     286                 :             :          * @param sendNum the number of messages already sent (to distinguish the buffers)
     287                 :             :          * @param requests destination vector in which to store the MPI requests for polling
     288                 :             :          * purposes
     289                 :             :          * @param hash a hash view indicating which particles need to be sent to which rank
     290                 :             :          */
     291                 :             :         template <typename HashType>
     292                 :             :         void sendToRank(int rank, int tag, std::vector<MPI_Request>& requests,
     293                 :             :                         const HashType& hash);
     294                 :             : 
     295                 :             :         /*!
     296                 :             :          * Receives particles from another rank
     297                 :             :          * @param rank the source rank
     298                 :             :          * @param tag the MPI tag
     299                 :             :          * @param recvNum the number of messages already received (to distinguish the buffers)
     300                 :             :          * @param nRecvs the number of particles to receive
     301                 :             :          */
     302                 :             :         void recvFromRank(int rank, int tag, size_type nRecvs);
     303                 :             : 
     304                 :             :         /*!
     305                 :             :          * Serialize to do MPI calls.
     306                 :             :          * @param ar archive
     307                 :             :          */
     308                 :             :         template <typename Archive>
     309                 :             :         void serialize(Archive& ar, size_type nsends);
     310                 :             : 
     311                 :             :         /*!
     312                 :             :          * Deserialize to do MPI calls.
     313                 :             :          * @param ar archive
     314                 :             :          */
     315                 :             :         template <typename Archive>
     316                 :             :         void deserialize(Archive& ar, size_type nrecvs);
     317                 :             : 
     318                 :             :         /*!
     319                 :             :          * Determine the total space necessary to store a certain number of particles
     320                 :             :          * @tparam MemorySpace only consider attributes stored in this memory space
     321                 :             :          * @param count particle number
     322                 :             :          * @return Total size of a buffer packed with the given number of particles
     323                 :             :          */
     324                 :             :         template <typename MemorySpace>
     325                 :             :         size_type packedSize(const size_type count) const;
     326                 :             : 
     327                 :             :     protected:
     328                 :             :         /*!
     329                 :             :          * Fill attributes of buffer.
     330                 :             :          * @param buffer to send
     331                 :             :          * @param hash function to access index.
     332                 :             :          */
     333                 :             :         void pack(const hash_container_type& hash);
     334                 :             : 
     335                 :             :         /*!
     336                 :             :          * Fill my attributes.
     337                 :             :          * @param buffer received
     338                 :             :          */
     339                 :             :         void unpack(size_type nrecvs);
     340                 :             : 
     341                 :             :     private:
     342                 :             :         //! particle layout
     343                 :             :         // cannot use std::unique_ptr due to Kokkos
     344                 :             :         Layout_t* layout_m;
     345                 :             : 
     346                 :             :         //! processor local number of particles
     347                 :             :         size_type localNum_m;
     348                 :             : 
     349                 :             :         //! total number of particles (across all processes)
     350                 :             :         size_type totalNum_m;
     351                 :             : 
     352                 :             :         //! all attributes
     353                 :             :         attribute_container_type attributes_m;
     354                 :             : 
     355                 :             :         //! next unique particle ID
     356                 :             :         index_type nextID_m;
     357                 :             : 
     358                 :             :         //! number of MPI ranks
     359                 :             :         index_type numNodes_m;
     360                 :             : 
     361                 :             :         //! buffers for particle partitioning
     362                 :             :         hash_container_type deleteIndex_m;
     363                 :             :         hash_container_type keepIndex_m;
     364                 :             :     };
     365                 :             : }  // namespace ippl
     366                 :             : 
     367                 :             : #include "Particle/ParticleBase.hpp"
     368                 :             : 
     369                 :             : #endif
        

Generated by: LCOV version 2.0-1