1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
/* Copyright 2019 David Grote, Maxence Thevenet, Remi Lehe
* Weiqun Zhang
*
* This file is part of WarpX.
*
* License: BSD-3-Clause-LBNL
*/
#ifndef WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
#define WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
#include "Particles/WarpXParticleContainer.H"
#include <AMReX.H>
#include <AMReX_REAL.H>
#include <cmath>
#include <limits>
/** \brief Extract the cartesian position coordinates of the particle
* p and store them in the variables `x`, `y`, `z`
* This version operates on a SuperParticle */
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void get_particle_position (const WarpXParticleContainer::SuperParticleType& p,
amrex::ParticleReal& x,
amrex::ParticleReal& y,
amrex::ParticleReal& z) noexcept
{
#ifdef WARPX_DIM_RZ
amrex::ParticleReal theta = p.rdata(PIdx::theta);
amrex::ParticleReal r = p.pos(0);
x = r*std::cos(theta);
y = r*std::sin(theta);
z = p.pos(1);
#elif WARPX_DIM_3D
x = p.pos(0);
y = p.pos(1);
z = p.pos(2);
#else
x = p.pos(0);
y = std::numeric_limits<amrex::ParticleReal>::quiet_NaN();
z = p.pos(1);
#endif
}
/** \brief Functor that can be used to extract the positions of the macroparticles
* inside a ParallelFor kernel
*
* \param a_pti iterator to the tile containing the macroparticles
* \param a_offset offset to apply to the particle indices
*/
struct GetParticlePosition
{
using PType = WarpXParticleContainer::ParticleType;
using RType = amrex::ParticleReal;
const PType* AMREX_RESTRICT m_structs = nullptr;
#if (defined WARPX_DIM_RZ)
const RType* m_theta = nullptr;
#elif (AMREX_SPACEDIM == 2)
static constexpr RType m_snan = std::numeric_limits<RType>::quiet_NaN();
#endif
GetParticlePosition () = default;
GetParticlePosition (const WarpXParIter& a_pti, int a_offset = 0) noexcept
{
const auto& aos = a_pti.GetArrayOfStructs();
m_structs = aos().dataPtr() + a_offset;
#if (defined WARPX_DIM_RZ)
const auto& soa = a_pti.GetStructOfArrays();
m_theta = soa.GetRealData(PIdx::theta).dataPtr() + a_offset;
#endif
}
/** \brief Extract the cartesian position coordinates of the particle
* located at index `i + a_offset` and store them in the variables
* `x`, `y`, `z` */
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void operator() (const int i, RType& x, RType& y, RType& z) const noexcept
{
const PType& p = m_structs[i];
#ifdef WARPX_DIM_RZ
RType r = p.pos(0);
x = r*std::cos(m_theta[i]);
y = r*std::sin(m_theta[i]);
z = p.pos(1);
#elif WARPX_DIM_3D
x = p.pos(0);
y = p.pos(1);
z = p.pos(2);
#else
x = p.pos(0);
y = m_snan;
z = p.pos(1);
#endif
}
/** \brief Extract the position coordinates of the particle as stored
* located at index `i + a_offset` and store them in the variables
* `x`, `y`, `z`
* This is only different for RZ since this returns (r, theta, z)
* in that case. */
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void AsStored (const int i, RType& x, RType& y, RType& z) const noexcept
{
const PType& p = m_structs[i];
#ifdef WARPX_DIM_RZ
x = p.pos(0);
y = m_theta[i];
z = p.pos(1);
#elif WARPX_DIM_3D
x = p.pos(0);
y = p.pos(1);
z = p.pos(2);
#else
x = p.pos(0);
y = m_snan;
z = p.pos(1);
#endif
}
};
/** \brief Functor that can be used to modify the positions of the macroparticles,
* inside a ParallelFor kernel.
*
* \param a_pti iterator to the tile being modified
* \param a_offset offset to apply to the particle indices
*/
struct SetParticlePosition
{
using PType = WarpXParticleContainer::ParticleType;
using RType = amrex::ParticleReal;
PType* AMREX_RESTRICT m_structs;
#if (defined WARPX_DIM_RZ)
RType* AMREX_RESTRICT m_theta;
#endif
SetParticlePosition (WarpXParIter& a_pti, int a_offset = 0) noexcept
{
auto& aos = a_pti.GetArrayOfStructs();
m_structs = aos().dataPtr() + a_offset;
#if (defined WARPX_DIM_RZ)
auto& soa = a_pti.GetStructOfArrays();
m_theta = soa.GetRealData(PIdx::theta).dataPtr() + a_offset;
#endif
}
/** \brief Set the position of the particle at index `i + a_offset`
* to `x`, `y`, `z` */
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void operator() (const int i, RType x, RType y, RType z) const noexcept
{
#if defined(WARPX_DIM_XZ)
amrex::ignore_unused(y);
#endif
#ifdef WARPX_DIM_RZ
m_theta[i] = std::atan2(y, x);
m_structs[i].pos(0) = std::sqrt(x*x + y*y);
m_structs[i].pos(1) = z;
#elif WARPX_DIM_3D
m_structs[i].pos(0) = x;
m_structs[i].pos(1) = y;
m_structs[i].pos(2) = z;
#else
m_structs[i].pos(0) = x;
m_structs[i].pos(1) = z;
#endif
}
/** \brief Set the position of the particle at index `i + a_offset`
* to `x`, `y`, `z`
* This is only different for RZ since the input should
* be (r, theta, z) in that case. */
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void AsStored (const int i, RType x, RType y, RType z) const noexcept
{
#if defined(WARPX_DIM_XZ)
amrex::ignore_unused(y);
#endif
#ifdef WARPX_DIM_RZ
m_structs[i].pos(0) = x;
m_theta[i] = y;
m_structs[i].pos(1) = z;
#elif WARPX_DIM_3D
m_structs[i].pos(0) = x;
m_structs[i].pos(1) = y;
m_structs[i].pos(2) = z;
#else
m_structs[i].pos(0) = x;
m_structs[i].pos(1) = z;
#endif
}
};
#endif // WARPX_PARTICLES_PUSHER_GETANDSETPOSITION_H_
|