Skip to content

Commit 38c7f86

Browse files
committed
Update Particle Container to Pure SoA
Transition particle containers to pure SoA layouts.
1 parent cdbac8b commit 38c7f86

File tree

8 files changed

+130
-141
lines changed

8 files changed

+130
-141
lines changed

cmake/dependencies/ABLASTR.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,10 @@ set(ImpactX_openpmd_src ""
166166
"Local path to openPMD-api source directory (preferred if set)")
167167

168168
# Git fetcher
169-
set(ImpactX_ablastr_repo "https://github.com/ECP-WarpX/WarpX.git"
169+
set(ImpactX_ablastr_repo "https://github.com/ax3l/WarpX.git"
170170
CACHE STRING
171171
"Repository URI to pull and build ABLASTR from if(ImpactX_ablastr_internal)")
172-
set(ImpactX_ablastr_branch "f71597fca2cf9d3700e7e11533f4a85a1846a2b8"
172+
set(ImpactX_ablastr_branch "topic-particle-soa"
173173
CACHE STRING
174174
"Repository branch for ImpactX_ablastr_repo if(ImpactX_ablastr_internal)")
175175

src/particles/ImpactXParticleContainer.H

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <AMReX_MultiFab.H>
1818
#include <AMReX_ParIter.H>
1919
#include <AMReX_Particles.H>
20+
#include <AMReX_ParticleTile.H>
2021

2122
#include <AMReX_IntVect.H>
2223
#include <AMReX_Vector.H>
@@ -35,6 +36,7 @@ namespace impactx
3536
* because we change the meaning of these "positions" depending on the
3637
* coordinate system we are currently in.
3738
*/
39+
/*
3840
struct RealAoS
3941
{
4042
enum
@@ -52,6 +54,7 @@ namespace impactx
5254
static_assert(names_t.size() == nattribs);
5355
static_assert(names_s.size() == nattribs);
5456
};
57+
*/
5558

5659
/** This struct indexes the additional Real attributes
5760
* stored in an SoA in ImpactXParticleContainer
@@ -60,18 +63,21 @@ namespace impactx
6063
{
6164
enum
6265
{
66+
x, ///< position in x [m] (at fixed t OR fixed s)
67+
y, ///< position in y [m] (at fixed t OR fixed s)
68+
z, ///< position in z [m] (at fixed t) OR time-of-flight ct [m] (at fixed s)
6369
ux, ///< momentum in x, scaled by the magnitude of the reference momentum [unitless] (at fixed t or s)
6470
uy, ///< momentum in y, scaled by the magnitude of the reference momentum [unitless] (at fixed t or s)
6571
pt, ///< momentum in z, scaled by the magnitude of the reference momentum [unitless] (at fixed t) OR energy deviation, scaled by speed of light * the magnitude of the reference momentum [unitless] (at fixed s)
6672
m_qm, ///< charge to mass ratio, in q_e/m_e (q_e/eV) TODO: rename to qm_m
67-
w, ///< particle weight, unitless
73+
w, ///< particle weight, unitless
6874
nattribs ///< the number of attributes above (always last)
6975
};
7076

7177
//! named labels for fixed t
72-
static constexpr auto names_t = { "momentum_x", "momentum_y", "momentum_z", "qmm", "weighting" };
78+
static constexpr auto names_t = { "position_x", "position_y", "position_z", "momentum_x", "momentum_y", "momentum_z", "qmm", "weighting" };
7379
//! named labels for fixed s
74-
static constexpr auto names_s = { "momentum_x", "momentum_y", "momentum_t", "qmm", "weighting" };
80+
static constexpr auto names_s = { "position_x", "position_y", "position_ct", "momentum_x", "momentum_y", "momentum_t", "qmm", "weighting" };
7581
static_assert(names_t.size() == nattribs);
7682
static_assert(names_s.size() == nattribs);
7783
};
@@ -83,55 +89,64 @@ namespace impactx
8389
{
8490
enum
8591
{
86-
nattribs ///< the number of particles above (always last)
92+
id,
93+
cpu,
94+
nattribs ///< the number of attributes above (always last)
8795
};
96+
97+
//! named labels for fixed t
98+
static constexpr auto names_t = { "id", "cpu" };
99+
//! named labels for fixed s
100+
static constexpr auto names_s = { "id", "cpu" };
101+
static_assert(names_t.size() == nattribs);
102+
static_assert(names_s.size() == nattribs);
88103
};
89104

90105
/** AMReX iterator for particle boxes
91106
*
92107
* We subclass here to change the default threading strategy, which is
93108
* `static` in AMReX, to `dynamic` in ImpactX.
94109
*/
95-
class ParIter
96-
: public amrex::ParIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>
110+
class ParIterSoA
111+
: public amrex::ParIterSoA<RealSoA::nattribs, IntSoA::nattribs>
97112
{
98113
public:
99-
using amrex::ParIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>::ParIter;
114+
using amrex::ParIterSoA<RealSoA::nattribs, IntSoA::nattribs>::ParIterSoA;
100115

101-
ParIter (ContainerType& pc, int level);
116+
ParIterSoA (ContainerType& pc, int level);
102117

103-
ParIter (ContainerType& pc, int level, amrex::MFItInfo& info);
118+
ParIterSoA (ContainerType& pc, int level, amrex::MFItInfo& info);
104119
};
105120

106121
/** Const AMReX iterator for particle boxes - data is read only.
107122
*
108123
* We subclass here to change the default threading strategy, which is
109124
* `static` in AMReX, to `dynamic` in ImpactX.
110125
*/
111-
class ParConstIter
112-
: public amrex::ParConstIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>
126+
class ParConstIterSoA
127+
: public amrex::ParConstIterSoA<RealSoA::nattribs, IntSoA::nattribs>
113128
{
114129
public:
115-
using amrex::ParConstIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>::ParConstIter;
130+
using amrex::ParConstIterSoA<RealSoA::nattribs, IntSoA::nattribs>::ParConstIterSoA;
116131

117-
ParConstIter (ContainerType& pc, int level);
132+
ParConstIterSoA (ContainerType& pc, int level);
118133

119-
ParConstIter (ContainerType& pc, int level, amrex::MFItInfo& info);
134+
ParConstIterSoA (ContainerType& pc, int level, amrex::MFItInfo& info);
120135
};
121136

122137
/** Beam Particles in ImpactX
123138
*
124139
* This class stores particles, distributed over MPI ranks.
125140
*/
126141
class ImpactXParticleContainer
127-
: public amrex::ParticleContainer<0, 0, RealSoA::nattribs, IntSoA::nattribs>
142+
: public amrex::ParticleContainerPureSoA<RealSoA::nattribs, IntSoA::nattribs>
128143
{
129144
public:
130145
//! amrex iterator for particle boxes
131-
using iterator = impactx::ParIter;
146+
using iterator = impactx::ParIterSoA;
132147

133148
//! amrex constant iterator for particle boxes (read-only)
134-
using const_iterator = impactx::ParConstIter;
149+
using const_iterator = impactx::ParConstIterSoA;
135150

136151
//! Construct a new particle container
137152
ImpactXParticleContainer (amrex::AmrCore* amr_core);

src/particles/ImpactXParticleContainer.cpp

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <AMReX_AmrParGDB.H>
1818
#include <AMReX_ParallelDescriptor.H>
1919
#include <AMReX_ParmParse.H>
20-
#include <AMReX_ParticleTile.H>
2120

2221
#include <stdexcept>
2322

@@ -31,24 +30,24 @@ namespace impactx
3130
return do_dynamic;
3231
}
3332

34-
ParIter::ParIter (ContainerType& pc, int level)
35-
: amrex::ParIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>(pc, level,
33+
ParIterSoA::ParIterSoA (ContainerType& pc, int level)
34+
: amrex::ParIterSoA<RealSoA::nattribs, IntSoA::nattribs>(pc, level,
3635
amrex::MFItInfo().SetDynamic(do_omp_dynamic())) {}
3736

38-
ParIter::ParIter (ContainerType& pc, int level, amrex::MFItInfo& info)
39-
: amrex::ParIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>(pc, level,
37+
ParIterSoA::ParIterSoA (ContainerType& pc, int level, amrex::MFItInfo& info)
38+
: amrex::ParIterSoA<RealSoA::nattribs, IntSoA::nattribs>(pc, level,
4039
info.SetDynamic(do_omp_dynamic())) {}
4140

42-
ParConstIter::ParConstIter (ContainerType& pc, int level)
43-
: amrex::ParConstIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>(pc, level,
41+
ParConstIterSoA::ParConstIterSoA (ContainerType& pc, int level)
42+
: amrex::ParConstIterSoA<RealSoA::nattribs, IntSoA::nattribs>(pc, level,
4443
amrex::MFItInfo().SetDynamic(do_omp_dynamic())) {}
4544

46-
ParConstIter::ParConstIter (ContainerType& pc, int level, amrex::MFItInfo& info)
47-
: amrex::ParConstIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>(pc, level,
45+
ParConstIterSoA::ParConstIterSoA (ContainerType& pc, int level, amrex::MFItInfo& info)
46+
: amrex::ParConstIterSoA<RealSoA::nattribs, IntSoA::nattribs>(pc, level,
4847
info.SetDynamic(do_omp_dynamic())) {}
4948

5049
ImpactXParticleContainer::ImpactXParticleContainer (amrex::AmrCore* amr_core)
51-
: amrex::ParticleContainer<0, 0, RealSoA::nattribs, IntSoA::nattribs>(amr_core->GetParGDB())
50+
: amrex::ParticleContainerPureSoA<RealSoA::nattribs, IntSoA::nattribs>(amr_core->GetParGDB())
5251
{
5352
SetParticleSize();
5453
}
@@ -105,35 +104,26 @@ namespace impactx
105104
reserveData();
106105
resizeData();
107106

107+
// write Real attributes (SoA) to particle initialized zero
108108
auto& particle_tile = DefineAndReturnParticleTile(0, 0, 0);
109109

110110
/* Create a temporary tile to obtain data from simulation. This data
111111
* is then copied to the permanent tile which is stored on the particle
112112
* (particle_tile).
113113
*/
114-
using PinnedTile = amrex::ParticleTile<
115-
amrex::Particle<NStructReal, NStructInt>,
116-
NArrayReal, NArrayInt,
117-
amrex::PinnedArenaAllocator
118-
>;
114+
using PinnedTile = typename ContainerLike<amrex::PinnedArenaAllocator>::ParticleTileType;
119115
PinnedTile pinned_tile;
120116
pinned_tile.define(NumRuntimeRealComps(), NumRuntimeIntComps());
121117

122118
for (int i = 0; i < np; i++)
123119
{
124-
ParticleType p;
125-
p.id() = ParticleType::NextID();
126-
p.cpu() = amrex::ParallelDescriptor::MyProc();
127-
p.pos(0) = x[i];
128-
p.pos(1) = y[i];
129-
p.pos(2) = z[i];
130-
// write position, creating cpu id, and particle id
131-
pinned_tile.push_back(p);
120+
pinned_tile.push_back_int(IntSoA::id, ParticleType::NextID());
121+
pinned_tile.push_back_int(IntSoA::cpu, amrex::ParallelDescriptor::MyProc());
132122
}
133123

134-
// write Real attributes (SoA) to particle initialized zero
135-
DefineAndReturnParticleTile(0, 0, 0);
136-
124+
pinned_tile.push_back_real(RealSoA::x, x);
125+
pinned_tile.push_back_real(RealSoA::y, y);
126+
pinned_tile.push_back_real(RealSoA::z, z);
137127
pinned_tile.push_back_real(RealSoA::ux, px);
138128
pinned_tile.push_back_real(RealSoA::uy, py);
139129
pinned_tile.push_back_real(RealSoA::pt, pz);
@@ -145,6 +135,7 @@ namespace impactx
145135
*/
146136
auto old_np = particle_tile.numParticles();
147137
auto new_np = old_np + pinned_tile.numParticles();
138+
amrex::AllPrint() << "old_np=" << old_np << " new_np=" << new_np << "\n";
148139
particle_tile.resize(new_np);
149140
amrex::copyParticles(
150141
particle_tile, pinned_tile, 0, old_np, pinned_tile.numParticles());

src/particles/diagnostics/DiagnosticOutput.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <AMReX_ParmParse.H> // for ParmParse
1818
#include <AMReX_REAL.H> // for ParticleReal
1919
#include <AMReX_Print.H> // for PrintToFile
20+
#include <AMReX_ParticleTile.H> // for constructor of SoAParticle
2021

2122

2223
namespace impactx::diagnostics
@@ -46,7 +47,8 @@ namespace impactx::diagnostics
4647
}
4748

4849
// create a host-side particle buffer
49-
auto tmp = pc.make_alike<amrex::PinnedArenaAllocator>();
50+
using ParticleType = amrex::SoAParticle<RealSoA::nattribs,IntSoA::nattribs>;
51+
auto tmp = pc.template make_alike<amrex::PinnedArenaAllocator>();
5052

5153
// copy device-to-host
5254
bool const local = true;
@@ -56,34 +58,34 @@ namespace impactx::diagnostics
5658
int const nLevel = tmp.finestLevel();
5759
for (int lev = 0; lev <= nLevel; ++lev) {
5860
// loop over all particle boxes
59-
using ParIt = typename decltype(tmp)::ParConstIterType;
60-
for (ParIt pti(tmp, lev); pti.isValid(); ++pti) {
61+
using MyPinnedParIter = amrex::ParIterSoA<RealSoA::nattribs,IntSoA::nattribs, amrex::PinnedArenaAllocator>;
62+
for (MyPinnedParIter pti(tmp, lev); pti.isValid(); ++pti) {
6163
const int np = pti.numParticles();
6264

6365
// preparing access to particle data: AoS
64-
using PType = ImpactXParticleContainer::ParticleType;
65-
auto const &aos = pti.GetArrayOfStructs();
66-
PType const *const AMREX_RESTRICT aos_ptr = aos().dataPtr();
66+
//using PType = ImpactXParticleContainer::ParticleType;
67+
//auto const &aos = pti.GetArrayOfStructs();
68+
//PType const *const AMREX_RESTRICT aos_ptr = aos().dataPtr();
6769

6870
// preparing access to particle data: SoA of Reals
69-
auto &soa_real = pti.GetStructOfArrays().GetRealData();
70-
amrex::ParticleReal const *const AMREX_RESTRICT part_px = soa_real[RealSoA::ux].dataPtr();
71-
amrex::ParticleReal const *const AMREX_RESTRICT part_py = soa_real[RealSoA::uy].dataPtr();
72-
amrex::ParticleReal const *const AMREX_RESTRICT part_pt = soa_real[RealSoA::pt].dataPtr();
71+
auto const& particle_attributes = pti.GetStructOfArrays();
72+
auto const& part_px = particle_attributes.GetRealData(RealSoA::ux);
73+
auto const& part_py = particle_attributes.GetRealData(RealSoA::uy);
74+
auto const& part_pt = particle_attributes.GetRealData(RealSoA::pt);
75+
76+
// Preparing the constructor for the new SoA Particle Type
77+
auto ptd = pti.GetParticleTile().getParticleTileData();
7378

7479
if (otype == OutputType::PrintParticles) {
7580
// print out particles (this hack works only on CPU and on GPUs with
7681
// unified memory access)
7782
for (int i = 0; i < np; ++i) {
78-
79-
// access AoS data such as positions and cpu/id
80-
PType const &p = aos_ptr[i];
83+
ParticleType p(ptd, i);
8184
amrex::ParticleReal const x = p.pos(0);
8285
amrex::ParticleReal const y = p.pos(1);
8386
amrex::ParticleReal const t = p.pos(2);
8487
uint64_t const global_id = ablastr::particles::localIDtoGlobal(p.id(), p.cpu());
8588

86-
// access SoA Real data
8789
amrex::ParticleReal const px = part_px[i];
8890
amrex::ParticleReal const py = part_py[i];
8991
amrex::ParticleReal const pt = part_pt[i];
@@ -119,14 +121,11 @@ namespace impactx::diagnostics
119121
// print out particles (this hack works only on CPU and on GPUs with
120122
// unified memory access)
121123
for (int i = 0; i < np; ++i) {
122-
123-
// access AoS data such as positions and cpu/id
124-
PType const &p = aos_ptr[i];
124+
ParticleType p(ptd, i);
125125
amrex::ParticleReal const x = p.pos(0);
126126
amrex::ParticleReal const y = p.pos(1);
127127
uint64_t const global_id = ablastr::particles::localIDtoGlobal(p.id(), p.cpu());
128128

129-
// access SoA Real data
130129
amrex::ParticleReal const px = part_px[i];
131130
amrex::ParticleReal const py = part_py[i];
132131

0 commit comments

Comments
 (0)