diff options
Diffstat (limited to 'Source/Particles/ParticleCreation')
-rw-r--r-- | Source/Particles/ParticleCreation/CopyParticle.H | 96 | ||||
-rw-r--r-- | Source/Particles/ParticleCreation/DefaultInitialization.H | 86 | ||||
-rw-r--r-- | Source/Particles/ParticleCreation/ElementaryProcess.H | 269 | ||||
-rw-r--r-- | Source/Particles/ParticleCreation/FilterCopyTransform.H | 62 | ||||
-rw-r--r-- | Source/Particles/ParticleCreation/Make.package | 7 | ||||
-rw-r--r-- | Source/Particles/ParticleCreation/SmartCopy.H | 146 | ||||
-rw-r--r-- | Source/Particles/ParticleCreation/SmartCopy.cpp | 45 | ||||
-rw-r--r-- | Source/Particles/ParticleCreation/TransformParticle.H | 50 |
8 files changed, 343 insertions, 418 deletions
diff --git a/Source/Particles/ParticleCreation/CopyParticle.H b/Source/Particles/ParticleCreation/CopyParticle.H deleted file mode 100644 index 8b2770891..000000000 --- a/Source/Particles/ParticleCreation/CopyParticle.H +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright 2019 Axel Huebl, Maxence Thevenet - * - * This file is part of WarpX. - * - * License: BSD-3-Clause-LBNL - */ -#ifndef COPYPARTICLE_H_ -#define COPYPARTICLE_H_ - -#include "WarpXParticleContainer.H" - -/** - * \brief Functor to copy one particle - * - * This is meant to be a very small class captured by value in kernel launches, - * that can be initialized on the host and copied to the device at each - * iteration. It should be general enough to be used by all processes. - * - * Pointers to SoA data are saved when constructor is called. - * AoS data is passed as argument of operator (). - */ -class CopyParticle -{ - -public: - - // ID of MPI rank - int m_cpuid; - // If true, will copy old attribs for back-transforme diagnostics - bool m_do_back_transformed_product; - // Source old (runtime) attribs for back-transformed diagnostics - amrex::GpuArray<amrex::ParticleReal*,3> m_runtime_uold_source; - // Source attribs - amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> m_attribs_source; - // Product attribs - amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> m_attribs_product; - // Product runtime attribs - amrex::GpuArray<amrex::ParticleReal*,6> m_runtime_attribs_product; - - // Simple constructor - AMREX_GPU_HOST_DEVICE - CopyParticle( - const int cpuid, const int do_back_transformed_product, - const amrex::GpuArray<amrex::ParticleReal*,3> runtime_uold_source, - const amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> attribs_source, - const amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> attribs_product, - const amrex::GpuArray<amrex::ParticleReal*,6> runtime_attribs_product) - : - m_cpuid(cpuid), - m_do_back_transformed_product(do_back_transformed_product), - m_runtime_uold_source(runtime_uold_source), - m_attribs_source(attribs_source), - m_attribs_product(attribs_product), - m_runtime_attribs_product(runtime_attribs_product){} - - /** - * \brief Overload operator () to do the copy of 1 particle - * - * \param is index of source particle - * \param ip index of product particle - * \param pid_product ID of first product particle - * \param p_source Struct with data for 1 source particle (position etc.) - * \param p_product Struct with data for 1 product particle (position etc.) - */ - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - void operator () (int is, int ip, int pid_product, - WarpXParticleContainer::ParticleType& p_source, - WarpXParticleContainer::ParticleType& p_product) const noexcept - { - // Copy particle from source to product: AoS - p_product.id() = pid_product + ip; - p_product.cpu() = m_cpuid; - p_product.pos(0) = p_source.pos(0); - p_product.pos(1) = p_source.pos(1); -#if (AMREX_SPACEDIM == 3) - p_product.pos(2) = p_source.pos(2); -#endif - // Copy particle from source to product: SoA - for (int ia = 0; ia < PIdx::nattribs; ++ia) { - m_attribs_product[ia][ip] = m_attribs_source[ia][is]; - } - // Update xold etc. if boosted frame diagnostics required - // for product species. Fill runtime attribs with a copy of - // current properties (xold = x etc.). - if (m_do_back_transformed_product) { - m_runtime_attribs_product[0][ip] = p_source.pos(0); - m_runtime_attribs_product[1][ip] = p_source.pos(1); - m_runtime_attribs_product[2][ip] = p_source.pos(2); - m_runtime_attribs_product[3][ip] = m_runtime_uold_source[0][ip]; - m_runtime_attribs_product[4][ip] = m_runtime_uold_source[1][ip]; - m_runtime_attribs_product[5][ip] = m_runtime_uold_source[2][ip]; - } - } -}; - -#endif // COPYPARTICLE_H_ diff --git a/Source/Particles/ParticleCreation/DefaultInitialization.H b/Source/Particles/ParticleCreation/DefaultInitialization.H new file mode 100644 index 000000000..f2f0dd3d8 --- /dev/null +++ b/Source/Particles/ParticleCreation/DefaultInitialization.H @@ -0,0 +1,86 @@ +#ifndef DEFAULTINITIALIZATION_H_ +#define DEFAULTINITIALIZATION_H_ + +#include "AMReX_REAL.H" +#include "AMReX_GpuContainers.H" + +#include <map> +#include <string> + +/** + * \brief This set of initialization policies describes what happens + * when we need to create a new particle due to an elementary process. + * For example, when an ionization event creates an electron, these + * policies control the initial values of the electron's components. + * These can always be over-written later. + * + * The specific meanings are as follows: + * Zero - set the component to zero + * One - set the component to one + * SignalingNan - set the component to a signalling nan. If you run + * with amrex.fpe_trap_invalid=1 AND built the code + * with gcc, this will throw an exception the first time + * it is used. + * RandomTau - a special flag for the "tau" component used by certain + * QED processes, which gets a random initial value. + * + */ +enum struct InitializationPolicy {Zero=0, One, SignalingNan, RandomTau}; + +/** + * \brief This map sets the initialization policy for each particle component + * used in WarpX. + */ +static std::map<std::string, InitializationPolicy> initialization_policies = { + {"w", InitializationPolicy::Zero }, + {"ux", InitializationPolicy::Zero }, + {"uy", InitializationPolicy::Zero }, + {"uz", InitializationPolicy::Zero }, + {"Ex", InitializationPolicy::Zero }, + {"Ey", InitializationPolicy::Zero }, + {"Ez", InitializationPolicy::Zero }, + {"Bx", InitializationPolicy::Zero }, + {"By", InitializationPolicy::Zero }, + {"Bz", InitializationPolicy::Zero }, +#ifdef WARPX_DIM_RZ + {"theta", InitializationPolicy::Zero}, +#endif + {"tau", InitializationPolicy::RandomTau} +}; + +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +amrex::ParticleReal initializeRealValue (const InitializationPolicy policy) noexcept +{ + switch (policy) { + case InitializationPolicy::Zero : return 0.0; + case InitializationPolicy::One : return 1.0; + case InitializationPolicy::SignalingNan : { + return 1.0; + } + case InitializationPolicy::RandomTau : { + return 1.0; + } + default : { + amrex::Abort("Initialization Policy not recognized"); + return 1.0; + } + } +} + +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +int initializeIntValue (const InitializationPolicy policy) noexcept +{ + switch (policy) { + case InitializationPolicy::Zero : return 0; + case InitializationPolicy::One : return 1; + case InitializationPolicy::SignalingNan : { + return 1; + } + default : { + amrex::Abort("Initialization Policy not recognized"); + return 1; + } + } +} + +#endif diff --git a/Source/Particles/ParticleCreation/ElementaryProcess.H b/Source/Particles/ParticleCreation/ElementaryProcess.H deleted file mode 100644 index 3fe2240cc..000000000 --- a/Source/Particles/ParticleCreation/ElementaryProcess.H +++ /dev/null @@ -1,269 +0,0 @@ -/* Copyright 2019 Axel Huebl, Maxence Thevenet, Weiqun Zhang - * - * - * This file is part of WarpX. - * - * License: BSD-3-Clause-LBNL - */ -#ifndef ELEMENTARYPROCESS_H_ -#define ELEMENTARYPROCESS_H_ - -#include "WarpXParticleContainer.H" -#include "CopyParticle.H" -#include "TransformParticle.H" - -/** - * \brief Base class for particle creation processes - * - * Particles in a source particle container are copied to product particle - * containers if they are flagged. Both source and product particles can be - * modified. - * - * - initialize_copy initializes a general copy functor - * - createParticles formats the data to prepare for the copy, then - * calls copyAndTransformParticles - * - copyAndTransformParticles loops over particles, performs the copy and - * transform source and product particles if needed. - * - * The class is templated on the process type. This gives flexibility - * on source and product particle transformations. - */ -template<ElementaryProcessType ProcessT> -class ElementaryProcess -{ -public: - - /** - * \brief initialize and return functor for particle copy - * - * \param cpuid id of MPI rank - * \param do_back_transformed_product whether to copy old attribs - * \param runtime_uold_source momentum of source particles - * \param attribs_source attribs of source particles - * \param attribs_product attribs of product particles - * \param runtime_attribs_product runtime attribs for product, to store old attribs - */ - CopyParticle initialize_copy( - const int cpuid, const int do_back_transformed_product, - const amrex::GpuArray<amrex::ParticleReal*,3> runtime_uold_source, - const amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> attribs_source, - const amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> attribs_product, - const amrex::GpuArray<amrex::ParticleReal*,6> runtime_attribs_product) const noexcept - { - return CopyParticle( - cpuid, do_back_transformed_product, runtime_uold_source, - attribs_source, attribs_product, runtime_attribs_product - ); - }; - - /** - * \brief create particles in product particle containers - * - * For particle i in mfi, if is_flagged[i]=1, copy particle - * particle i from container pc_source into each container in v_pc_product - * - * \param lev MR level - * \param mfi MFIter where source particles are located - * \param pc_source source particle container - * \param v_pc_product vector of product particle containers - * \param is_flagged particles for which is_flagged is 1 are copied - * \param v_do_back_transformed_product vector: whether to copy old attribs for - * each product container - */ - void createParticles ( - int lev, const amrex::MFIter& mfi, - std::unique_ptr< WarpXParticleContainer>& pc_source, - amrex::Vector<WarpXParticleContainer*> v_pc_product, - amrex::Gpu::ManagedDeviceVector<int>& is_flagged, - amrex::Gpu::ManagedDeviceVector<int> v_do_back_transformed_product) - { - - BL_PROFILE("createParticles"); - const int grid_id = mfi.index(); - const int tile_id = mfi.LocalTileIndex(); - - // Get source particle data - auto& ptile_source = pc_source->GetParticles(lev)[std::make_pair(grid_id,tile_id)]; - const int np_source = ptile_source.GetArrayOfStructs().size(); - if (np_source == 0) return; - // --- source AoS particle data - WarpXParticleContainer::ParticleType* particles_source = ptile_source.GetArrayOfStructs()().data(); - // --- source SoA particle data - auto& soa_source = ptile_source.GetStructOfArrays(); - amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> attribs_source; - for (int ia = 0; ia < PIdx::nattribs; ++ia) { - attribs_source[ia] = soa_source.GetRealData(ia).data(); - } - // --- source runtime attribs - amrex::GpuArray<amrex::ParticleReal*,3> runtime_uold_source; - // Prepare arrays for boosted frame diagnostics. - runtime_uold_source[0] = soa_source.GetRealData(PIdx::ux).data(); - runtime_uold_source[1] = soa_source.GetRealData(PIdx::uy).data(); - runtime_uold_source[2] = soa_source.GetRealData(PIdx::uz).data(); - - // --- source runtime integer attribs - amrex::GpuArray<int*,1> runtime_iattribs_source; - std::map<std::string, int> icomps_source = pc_source->getParticleiComps(); - runtime_iattribs_source[0] = soa_source.GetIntData(icomps_source["ionization_level"]).data(); - - int nproducts = v_pc_product.size(); - AMREX_ALWAYS_ASSERT_WITH_MESSAGE( - v_do_back_transformed_product.size() == nproducts, - "v_pc_product and v_do_back_transformed_product must have the same size."); - - // Indices of product particle for each source particle. - // i_product[i]-1 is the location in product tile of product particle - // from source particle i. - amrex::Gpu::ManagedDeviceVector<int> i_product; - i_product.resize(np_source); - // 0<i<np_source - // 0<i_product<np_flagged - // Strictly speaking, i_product should be an exclusive_scan of - // is_flagged. However, for indices where is_flagged is 1, the - // inclusive scan gives the same result with an offset of 1. - // The advantage of inclusive_scan is that the sum of is_flagged - // is in the last element, so no other reduction is required to get - // number of particles. - // Gpu::inclusive_scan runs on the current GPU stream, and synchronizes - // with the CPU, so that the next line (executed by the CPU) has the - // updated values of i_product - amrex::Gpu::inclusive_scan(is_flagged.begin(), is_flagged.end(), i_product.begin()); - int np_flagged = i_product[np_source-1]; - if (np_flagged == 0) return; - - amrex::Gpu::ManagedDeviceVector<CopyParticle> v_copy_functor; - v_copy_functor.reserve(nproducts); - amrex::Gpu::ManagedDeviceVector<int> v_pid_product(nproducts); - amrex::Gpu::ManagedDeviceVector<WarpXParticleContainer::ParticleType*> v_particles_product(nproducts); - for (int iproduct=0; iproduct<nproducts; iproduct++){ - WarpXParticleContainer*& pc_product = v_pc_product[iproduct]; - // Get product particle data - auto& ptile_product = pc_product->GetParticles(lev)[std::make_pair(grid_id,tile_id)]; - // old and new (i.e., including flagged particles) number of particles - // for product species - const int np_product_old = ptile_product.GetArrayOfStructs().size(); - const int np_product_new = np_product_old + np_flagged; - // Allocate extra space in product species for flagged particles. - ptile_product.resize(np_product_new); - // --- product AoS particle data - // WarpXParticleContainer::ParticleType* particles_product = ptile_product.GetArrayOfStructs()().data() + np_product_old; - v_particles_product[iproduct] = ptile_product.GetArrayOfStructs()().data() + np_product_old; - // First element is the first newly-created product particle - // --- product SoA particle data - auto& soa_product = ptile_product.GetStructOfArrays(); - amrex::GpuArray<amrex::ParticleReal*,PIdx::nattribs> attribs_product; - for (int ia = 0; ia < PIdx::nattribs; ++ia) { - // First element is the first newly-created product particle - attribs_product[ia] = soa_product.GetRealData(ia).data() + np_product_old; - } - // --- product runtime attribs - amrex::GpuArray<amrex::ParticleReal*,6> runtime_attribs_product; - const int do_boost = v_do_back_transformed_product[iproduct]; - if (do_boost) { - std::map<std::string, int> comps_product = pc_product->getParticleComps(); - runtime_attribs_product[0] = soa_product.GetRealData(comps_product[ "xold"]).data() + np_product_old; - runtime_attribs_product[1] = soa_product.GetRealData(comps_product[ "yold"]).data() + np_product_old; - runtime_attribs_product[2] = soa_product.GetRealData(comps_product[ "zold"]).data() + np_product_old; - runtime_attribs_product[3] = soa_product.GetRealData(comps_product["uxold"]).data() + np_product_old; - runtime_attribs_product[4] = soa_product.GetRealData(comps_product["uyold"]).data() + np_product_old; - runtime_attribs_product[5] = soa_product.GetRealData(comps_product["uzold"]).data() + np_product_old; - } - - // --- product runtime integer attribs - int pid_product; -#ifdef _OPENMP -#pragma omp critical (doParticleCreation_nextid) -#endif - { - // ID of first newly-created product particle - pid_product = pc_product->NextID(); - // Update NextID to include particles created in this function - pc_product->setNextID(pid_product+np_flagged); - } - const int cpuid = amrex::ParallelDescriptor::MyProc(); - - // Create instance of copy functor, and add it to the vector - v_copy_functor.push_back( initialize_copy( - cpuid, v_do_back_transformed_product[iproduct], - runtime_uold_source, - attribs_source, - attribs_product, - runtime_attribs_product - ) ); - v_pid_product[iproduct] = pid_product; - - } - // Loop over source particles and create product particles - copyAndTransformParticles(is_flagged, i_product, np_source, v_pid_product, - v_particles_product, particles_source, v_copy_functor, - runtime_iattribs_source); - // Synchronize to prevent the destruction of temporary arrays (at the - // end of the function call) before the kernel executes. - amrex::Gpu::streamSynchronize(); - } - - /** - * \brief Loop over source particles and create product particles - * - * \param is_flagged particles for which is_flagged is 1 are copied - * \param i_product relative indices of product particle. This is the same - * for all product particle containers. - * \param np_source number of particles in source container - * \param v_pid_product for each product particle container: ID of the - * first product particle. Others IDs are incremented from this one - * \param v_particles_product for each product particle container: pointer - * to the AoS particle data - * \param particles_source pointter to the AoS source particle data - * \param v_copy_functor vector of copy functors, one for each product particle container - * \param runtime_iattribs_source pointer to source runtime integer attribs - */ - void copyAndTransformParticles( - amrex::Gpu::ManagedDeviceVector<int>& is_flagged, - amrex::Gpu::ManagedDeviceVector<int>& i_product, - int np_source, - amrex::Gpu::ManagedDeviceVector<int> v_pid_product, - amrex::Gpu::ManagedDeviceVector<WarpXParticleContainer::ParticleType*> v_particles_product, - WarpXParticleContainer::ParticleType* particles_source, - const amrex::Gpu::ManagedDeviceVector<CopyParticle>& v_copy_functor, - amrex::GpuArray<int*,1> runtime_iattribs_source) - { - int const * const AMREX_RESTRICT p_is_flagged = is_flagged.dataPtr(); - int const * const AMREX_RESTRICT p_i_product = i_product.dataPtr(); - CopyParticle const * const AMREX_RESTRICT p_copy_functor = v_copy_functor.dataPtr(); - WarpXParticleContainer::ParticleType * * p_particles_product = v_particles_product.data(); - int const * const p_pid_product = v_pid_product.data(); - - // Loop over all source particles. If is_flagged, copy particle data - // to corresponding product particle. - int nproducts = v_particles_product.size(); - amrex::For( - np_source, [=] AMREX_GPU_DEVICE (int is) noexcept - { - if(p_is_flagged[is]){ - // offset of 1 due to inclusive scan - int ip = p_i_product[is]-1; - WarpXParticleContainer::ParticleType& p_source = particles_source[is]; - for (int iproduct=0; iproduct<nproducts; iproduct++){ - // is: index of flagged particle in source species - // ip: index of corresponding new particle in product species - WarpXParticleContainer::ParticleType* particles_product = p_particles_product[iproduct]; - WarpXParticleContainer::ParticleType& p_product = particles_product[ip]; - p_copy_functor[iproduct](is, ip, p_pid_product[iproduct], p_source, p_product); - } - // Transform source particle - transformSourceParticle<ProcessT>(is, p_source, runtime_iattribs_source); - // Transform product particles. The loop over product - // species is done inside the function to allow for - // more flexibility. - transformProductParticle<ProcessT>(ip, p_particles_product); - } - } - ); - } -}; - -// Derived class for ionization process -class IonizationProcess: public ElementaryProcess<ElementaryProcessType::Ionization> -{}; - -#endif // ELEMENTARYPROCESS_H_ diff --git a/Source/Particles/ParticleCreation/FilterCopyTransform.H b/Source/Particles/ParticleCreation/FilterCopyTransform.H new file mode 100644 index 000000000..6e47dd732 --- /dev/null +++ b/Source/Particles/ParticleCreation/FilterCopyTransform.H @@ -0,0 +1,62 @@ +#ifndef FILTER_COPY_TRANSFORM_H_ +#define FILTER_COPY_TRANSFORM_H_ + +#include <AMReX_GpuContainers.H> +#include <AMReX_TypeTraits.H> + +template <typename DstTile, typename SrcTile, typename Index, + typename TransFunc, typename CopyFunc, + amrex::EnableIf_t<std::is_integral<Index>::value, int> foo = 0> +Index filterCopyTransformParticles (DstTile& dst, SrcTile& src, Index* mask, Index dst_index, + CopyFunc&& copy, TransFunc&& transform) noexcept +{ + using namespace amrex; + auto np = src.numParticles(); + Gpu::DeviceVector<Index> offsets(np); + Gpu::exclusive_scan(mask, mask+np, offsets.begin()); + + Index last_mask, last_offset; + Gpu::copyAsync(Gpu::deviceToHost, mask+np-1, mask + np, &last_mask); + Gpu::copyAsync(Gpu::deviceToHost, offsets.data()+np-1, offsets.data()+np, &last_offset); + + auto p_offsets = offsets.dataPtr(); + + const auto src_data = src.getParticleTileData(); + auto dst_data = dst.getParticleTileData(); + + AMREX_HOST_DEVICE_FOR_1D( np, i, + { + if (mask[i]) + { + copy(dst_data, src_data, i, p_offsets[i] + dst_index); + transform(dst_data, src_data, i, p_offsets[i] + dst_index); + } + }); + + Gpu::streamSynchronize(); + return last_mask + last_offset; +} + +template <typename DstTile, typename SrcTile, typename Index, + typename PredFunc, typename TransFunc, typename CopyFunc> +Index filterCopyTransformParticles (DstTile& dst, SrcTile& src, Index dst_index, + PredFunc&& filter, CopyFunc&& copy, TransFunc&& transform) noexcept +{ + using namespace amrex; + auto np = src.numParticles(); + Gpu::DeviceVector<Index> mask(np); + + auto p_mask = mask.dataPtr(); + const auto src_data = src.getParticleTileData(); + + AMREX_HOST_DEVICE_FOR_1D(np, i, + { + p_mask[i] = filter(src_data, i); + }); + + return filterCopyTransformParticles(dst, src, mask.dataPtr(), dst_index, + std::forward<CopyFunc>(copy), + std::forward<TransFunc>(transform)); +} + +#endif diff --git a/Source/Particles/ParticleCreation/Make.package b/Source/Particles/ParticleCreation/Make.package index 6e32f4a77..32c0add64 100644 --- a/Source/Particles/ParticleCreation/Make.package +++ b/Source/Particles/ParticleCreation/Make.package @@ -1,6 +1,7 @@ -CEXE_headers += ElementaryProcess.H -CEXE_headers += CopyParticle.H -CEXE_headers += TransformParticle.H +CEXE_headers += DefaultInitialization.H +CEXE_headers += FilterCopyTransform.H +CEXE_headers += SmartCopy.H +CEXE_sources += SmartCopy.cpp INCLUDE_LOCATIONS += $(WARPX_HOME)/Source/Particles/ParticleCreation/ VPATH_LOCATIONS += $(WARPX_HOME)/Source/Particles/ParticleCreation/ diff --git a/Source/Particles/ParticleCreation/SmartCopy.H b/Source/Particles/ParticleCreation/SmartCopy.H new file mode 100644 index 000000000..e72a2f299 --- /dev/null +++ b/Source/Particles/ParticleCreation/SmartCopy.H @@ -0,0 +1,146 @@ +#ifndef SMART_COPY_H_ +#define SMART_COPY_H_ + +#include <DefaultInitialization.H> + +#include <AMReX_GpuContainers.H> +#include <AMReX_ParallelDescriptor.H> + +#include <map> +#include <string> + +using NameMap = std::map<std::string, int>; +using PolicyVec = amrex::Gpu::DeviceVector<InitializationPolicy>; + +struct SmartCopyTag +{ + std::vector<std::string> common_names; + amrex::Gpu::DeviceVector<int> src_comps; + amrex::Gpu::DeviceVector<int> dst_comps; + + int size () const noexcept { return common_names.size(); } +}; + +PolicyVec getPolicies (const NameMap& names) noexcept; + +SmartCopyTag getSmartCopyTag (const NameMap& src, const NameMap& dst) noexcept; + +template <typename PTile> +void setNewParticleIDs (PTile& ptile, int old_size, int num_added) +{ + int pid; +#ifdef _OPENMP +#pragma omp critical (ionization_nextid) +#endif + { + pid = PTile::ParticleType::NextID(); + PTile::ParticleType::NextID(pid + num_added); + } + + const int cpuid = amrex::ParallelDescriptor::MyProc(); + auto pp = ptile.GetArrayOfStructs()().data() + old_size; + amrex::For(num_added, [=] AMREX_GPU_DEVICE (int ip) noexcept + { + auto& p = pp[ip]; + p.id() = pid+ip; + p.cpu() = cpuid; + }); +} + +struct SmartCopy +{ + int m_num_copy_real; + const int* m_src_comps_r; + const int* m_dst_comps_r; + + int m_num_copy_int; + const int* m_src_comps_i; + const int* m_dst_comps_i; + + const InitializationPolicy* m_policy_real; + const InitializationPolicy* m_policy_int; + + template <typename DstData, typename SrcData> + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + void operator() (DstData& dst, const SrcData& src, int i_src, int i_dst) const noexcept + { + // the particle struct is always copied over + dst.m_aos[i_dst] = src.m_aos[i_src]; + + // initialize the real components + for (int j = 0; j < DstData::NAR; ++j) + dst.m_rdata[j][i_dst] = initializeRealValue(m_policy_real[j]); + for (int j = 0; j < dst.m_num_runtime_real; ++j) + dst.m_rdata[j][i_dst] = initializeRealValue(m_policy_real[j+DstData::NAR]); + + // initialize the int components + for (int j = 0; j < DstData::NAI; ++j) + dst.m_idata[j][i_dst] = initializeIntValue(m_policy_int[j]); + for (int j = 0; j < dst.m_num_runtime_int; ++j) + dst.m_idata[j][i_dst] = initializeIntValue(m_policy_int[j+DstData::NAI]); + + // copy the shared real components + for (int j = 0; j < m_num_copy_real; ++j) + { + int src_comp = (m_src_comps_r[j] < SrcData::NAR) ? m_src_comps_r[j] : m_src_comps_r[j] - SrcData::NAR; + int dst_comp = (m_dst_comps_r[j] < DstData::NAR) ? m_dst_comps_r[j] : m_dst_comps_r[j] - DstData::NAR; + + amrex::ParticleReal* AMREX_RESTRICT dst_data = (m_dst_comps_r[j] < DstData::NAR) ? dst.m_rdata[dst_comp] : dst.m_runtime_rdata[dst_comp]; + const amrex::ParticleReal* AMREX_RESTRICT src_data = (m_src_comps_r[j] < SrcData::NAR) ? src.m_rdata[src_comp] : src.m_runtime_rdata[src_comp]; + + dst_data[i_dst] = src_data[i_src]; + } + + // copy the shared int components + for (int j = 0; j < m_num_copy_int; ++j) + { + int src_comp = (m_src_comps_i[j] < SrcData::NAI) ? m_src_comps_i[j] : m_src_comps_i[j] - SrcData::NAI; + int dst_comp = (m_dst_comps_i[j] < DstData::NAI) ? m_dst_comps_i[j] : m_dst_comps_i[j] - DstData::NAI; + + int* AMREX_RESTRICT dst_data = (m_dst_comps_i[j] < DstData::NAI) ? dst.m_idata[dst_comp] : dst.m_runtime_idata[dst_comp]; + const int* AMREX_RESTRICT src_data = (m_src_comps_i[j] < SrcData::NAI) ? src.m_idata[src_comp] : src.m_runtime_idata[src_comp]; + + dst_data[i_dst] = src_data[i_src]; + } + } +}; + +class SmartCopyFactory +{ + SmartCopyTag m_tag_real; + SmartCopyTag m_tag_int; + PolicyVec m_policy_real; + PolicyVec m_policy_int; + bool m_defined; + +public: + template <class SrcPC, class DstPC> + SmartCopyFactory (const SrcPC& src, const DstPC& dst) noexcept + : m_defined(false) + { + m_tag_real = getSmartCopyTag(src.getParticleComps(), dst.getParticleComps()); + m_tag_int = getSmartCopyTag(src.getParticleiComps(), dst.getParticleiComps()); + + m_policy_real = getPolicies(dst.getParticleComps()); + m_policy_int = getPolicies(dst.getParticleiComps()); + + m_defined = true; + } + + SmartCopy getSmartCopy () const noexcept + { + AMREX_ASSERT(m_defined); + return SmartCopy{m_tag_real.size(), + m_tag_real.src_comps.dataPtr(), + m_tag_real.dst_comps.dataPtr(), + m_tag_int.size(), + m_tag_int. src_comps.dataPtr(), + m_tag_int. dst_comps.dataPtr(), + m_policy_real.dataPtr(), + m_policy_int.dataPtr()}; + } + + bool isDefined () const noexcept { return m_defined; } +}; + +#endif diff --git a/Source/Particles/ParticleCreation/SmartCopy.cpp b/Source/Particles/ParticleCreation/SmartCopy.cpp new file mode 100644 index 000000000..5ceb625a8 --- /dev/null +++ b/Source/Particles/ParticleCreation/SmartCopy.cpp @@ -0,0 +1,45 @@ +#include "SmartCopy.H" + +PolicyVec getPolicies (const NameMap& names) noexcept +{ + PolicyVec policies; + policies.resize(names.size()); + for (const auto& kv : names) + { + policies[kv.second] = initialization_policies[kv.first]; + } + return policies; +} + +SmartCopyTag getSmartCopyTag (const NameMap& src, const NameMap& dst) noexcept +{ + SmartCopyTag tag; + + // we use the fact that maps are sorted + auto i_src = src.begin(); + auto i_dst = dst.begin(); + while ( (i_src != src.end()) and (i_dst != dst.end()) ) + { + if (i_src->first < i_dst->first) + { + // names are not the same and src is lower + ++i_src; + } + else if (i_src->first > i_dst->first) + { + // names are not the same and dst is lower + ++i_dst; + } + else + { + // name is in both... + tag.common_names.push_back(i_src->first); + tag.src_comps.push_back(i_src->second); + tag.dst_comps.push_back(i_dst->second); + ++i_src; + ++i_dst; + } + } + + return tag; +} diff --git a/Source/Particles/ParticleCreation/TransformParticle.H b/Source/Particles/ParticleCreation/TransformParticle.H deleted file mode 100644 index eb5820e32..000000000 --- a/Source/Particles/ParticleCreation/TransformParticle.H +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright 2019 Axel Huebl, Maxence Thevenet - * - * This file is part of WarpX. - * - * License: BSD-3-Clause-LBNL - */ -#ifndef TRANSFORMPARTICLE_H_ -#define TRANSFORMPARTICLE_H_ - -#include "WarpXParticleContainer.H" - -enum struct ElementaryProcessType { Ionization }; - -/** - * \brief small modifications on source particle - * \param i index of particle - * \param particle particle struct - * \param runtime_iattribs integer attribs - */ -template < ElementaryProcessType ProcessT > -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void transformSourceParticle( - int i, - WarpXParticleContainer::ParticleType& particle, - amrex::GpuArray<int*,1> runtime_iattribs){} - -/** - * \brief small modifications on product particle - * \param i index of particle - * \param v_particle pointer to vector of particles - */ -template < ElementaryProcessType ProcessT > -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void transformProductParticle( - int i, - WarpXParticleContainer::ParticleType* * v_particle){} - -// For ionization, increase ionization level of source particle -template <> -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void transformSourceParticle < ElementaryProcessType::Ionization > ( - int i, - WarpXParticleContainer::ParticleType& particle, - amrex::GpuArray<int*,1> runtime_iattribs) -{ - // increment particle's ionization level - runtime_iattribs[0][i] += 1; -} - -#endif // TRANSFORMPARTICLE_H_ |