Skip to content

Commit cfd9d1d

Browse files
Add Python function to extract particles scraped during the last step. (#5711)
This adds a function that extracts the particles that were scraped at the current timestep. This is useful in callback functions, where we often want to re-inject particles that hit the boundary, and therefore need to select the ones that were scraped at the current timestep. This also avoids calling `clear_buffer`, which potentially interferes with the `BoundaryScrapingDiagnostic` --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 8bdbd69 commit cfd9d1d

File tree

3 files changed

+76
-27
lines changed

3 files changed

+76
-27
lines changed

Examples/Tests/particle_boundary_interaction/inputs_test_rz_particle_boundary_interaction_picmi.py

+15-13
Original file line numberDiff line numberDiff line change
@@ -128,20 +128,24 @@ def mirror_reflection():
128128
# STEP 1: extract the different parameters of the boundary buffer (normal, time, position)
129129
lev = 0 # level 0 (no mesh refinement here)
130130
delta_t = concat(
131-
buffer.get_particle_boundary_buffer("electrons", "eb", "deltaTimeScraped", lev)
131+
buffer.get_particle_scraped_this_step(
132+
"electrons", "eb", "deltaTimeScraped", lev
133+
)
132134
)
133-
r = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "x", lev))
134-
theta = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "theta", lev))
135-
z = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "z", lev))
135+
r = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "x", lev))
136+
theta = concat(
137+
buffer.get_particle_scraped_this_step("electrons", "eb", "theta", lev)
138+
)
139+
z = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "z", lev))
136140
x = r * np.cos(theta) # from RZ coordinates to 3D coordinates
137141
y = r * np.sin(theta)
138-
ux = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "ux", lev))
139-
uy = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "uy", lev))
140-
uz = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "uz", lev))
141-
w = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "w", lev))
142-
nx = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "nx", lev))
143-
ny = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "ny", lev))
144-
nz = concat(buffer.get_particle_boundary_buffer("electrons", "eb", "nz", lev))
142+
ux = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "ux", lev))
143+
uy = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "uy", lev))
144+
uz = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "uz", lev))
145+
w = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "w", lev))
146+
nx = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "nx", lev))
147+
ny = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "ny", lev))
148+
nz = concat(buffer.get_particle_scraped_this_step("electrons", "eb", "nz", lev))
145149

146150
# STEP 2: use these parameters to inject particle from the same position in the plasma
147151
elect_pc = particle_containers.ParticleContainerWrapper(
@@ -164,8 +168,6 @@ def mirror_reflection():
164168
) # adds the particle in the general particle container at the next step
165169
#### Can be modified depending on the model of interaction.
166170

167-
buffer.clear_buffer() # reinitialise the boundary buffer
168-
169171

170172
callbacks.installafterstep(
171173
mirror_reflection

Examples/Tests/secondary_ion_emission/inputs_test_rz_secondary_ion_emission_picmi.py

+16-14
Original file line numberDiff line numberDiff line change
@@ -188,26 +188,29 @@ def secondary_emission():
188188
elect_pc = particle_containers.ParticleContainerWrapper("electrons")
189189

190190
if n != 0:
191-
r = concat(buffer.get_particle_boundary_buffer("ions", "eb", "x", lev))
192-
theta = concat(buffer.get_particle_boundary_buffer("ions", "eb", "theta", lev))
193-
z = concat(buffer.get_particle_boundary_buffer("ions", "eb", "z", lev))
191+
r = concat(buffer.get_particle_scraped_this_step("ions", "eb", "x", lev))
192+
theta = concat(
193+
buffer.get_particle_scraped_this_step("ions", "eb", "theta", lev)
194+
)
195+
z = concat(buffer.get_particle_scraped_this_step("ions", "eb", "z", lev))
194196
x = r * np.cos(theta) # from RZ coordinates to 3D coordinates
195197
y = r * np.sin(theta)
196-
ux = concat(buffer.get_particle_boundary_buffer("ions", "eb", "ux", lev))
197-
uy = concat(buffer.get_particle_boundary_buffer("ions", "eb", "uy", lev))
198-
uz = concat(buffer.get_particle_boundary_buffer("ions", "eb", "uz", lev))
199-
w = concat(buffer.get_particle_boundary_buffer("ions", "eb", "w", lev))
200-
nx = concat(buffer.get_particle_boundary_buffer("ions", "eb", "nx", lev))
201-
ny = concat(buffer.get_particle_boundary_buffer("ions", "eb", "ny", lev))
202-
nz = concat(buffer.get_particle_boundary_buffer("ions", "eb", "nz", lev))
198+
ux = concat(buffer.get_particle_scraped_this_step("ions", "eb", "ux", lev))
199+
uy = concat(buffer.get_particle_scraped_this_step("ions", "eb", "uy", lev))
200+
uz = concat(buffer.get_particle_scraped_this_step("ions", "eb", "uz", lev))
201+
w = concat(buffer.get_particle_scraped_this_step("ions", "eb", "w", lev))
202+
nx = concat(buffer.get_particle_scraped_this_step("ions", "eb", "nx", lev))
203+
ny = concat(buffer.get_particle_scraped_this_step("ions", "eb", "ny", lev))
204+
nz = concat(buffer.get_particle_scraped_this_step("ions", "eb", "nz", lev))
203205
delta_t = concat(
204-
buffer.get_particle_boundary_buffer("ions", "eb", "deltaTimeScraped", lev)
206+
buffer.get_particle_scraped_this_step("ions", "eb", "deltaTimeScraped", lev)
205207
)
208+
206209
energy_ions = 0.5 * proton_mass * w * (ux**2 + uy**2 + uz**2)
207210
energy_ions_in_kEv = energy_ions / (e * 1000)
208211
sigma_nascap_ions = sigma_nascap(energy_ions_in_kEv, delta_H, E_HMax)
209-
# Loop over all ions in the EB buffer
210-
for i in range(0, n):
212+
# Loop over all ions that have been scraped in the last timestep
213+
for i in range(0, len(w)):
211214
sigma = sigma_nascap_ions[i]
212215
# Ne_sec is number of the secondary electrons to be emitted
213216
Ne_sec = int(sigma + np.random.uniform())
@@ -258,7 +261,6 @@ def secondary_emission():
258261
uz=uze,
259262
w=we,
260263
)
261-
buffer.clear_buffer() # reinitialise the boundary buffer
262264

263265

264266
# using the new particle container modified at the last step

Python/pywarpx/particle_containers.py

+45
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,51 @@ def get_particle_boundary_buffer(self, species_name, boundary, comp_name, level)
863863
raise RuntimeError("Name %s not found" % comp_name)
864864
return data_array
865865

866+
def get_particle_scraped_this_step(self, species_name, boundary, comp_name, level):
867+
"""
868+
This returns a list of numpy or cupy arrays containing the particle array data
869+
for particles that have been scraped at the current timestep,
870+
for a specific species and simulation boundary.
871+
872+
The data for the arrays is a view of the underlying boundary buffer in WarpX ;
873+
writing to these arrays will therefore also modify the underlying boundary buffer.
874+
875+
Parameters
876+
----------
877+
878+
species_name : str
879+
The species name that the data will be returned for.
880+
881+
boundary : str
882+
The boundary from which to get the scraped particle data in the
883+
form x/y/z_hi/lo or eb.
884+
885+
comp_name : str
886+
The component of the array data that will be returned.
887+
"x", "y", "z", "ux", "uy", "uz", "w"
888+
"stepScraped","deltaTimeScraped",
889+
if boundary='eb': "nx", "ny", "nz"
890+
891+
level : int
892+
Which AMR level to retrieve scraped particle data from.
893+
"""
894+
# Extract the integer number of the current timestep
895+
current_step = libwarpx.libwarpx_so.get_instance().getistep(level)
896+
897+
# Extract the data requested by the user
898+
data_array = self.get_particle_boundary_buffer(
899+
species_name, boundary, comp_name, level
900+
)
901+
step_scraped_array = self.get_particle_boundary_buffer(
902+
species_name, boundary, "stepScraped", level
903+
)
904+
905+
# Select on the particles from the previous step
906+
data_array_this_step = []
907+
for data, step in zip(data_array, step_scraped_array):
908+
data_array_this_step.append(data[step == current_step])
909+
return data_array_this_step
910+
866911
def clear_buffer(self):
867912
"""
868913

0 commit comments

Comments
 (0)