aboutsummaryrefslogtreecommitdiff
path: root/Python/pywarpx/_libwarpx.py
diff options
context:
space:
mode:
authorGravatar Phil Miller <phil@intensecomputing.com> 2021-08-30 16:26:55 -0400
committerGravatar GitHub <noreply@github.com> 2021-08-30 13:26:55 -0700
commite130e57efcee4fb08cae9a5888c67c83db63abb4 (patch)
tree2e8cc1688c5842ba2d478c04887d8ba214bcd6f6 /Python/pywarpx/_libwarpx.py
parentc17b786f935a52530e7d559b7bae4c6ab740ae85 (diff)
downloadWarpX-e130e57efcee4fb08cae9a5888c67c83db63abb4.tar.gz
WarpX-e130e57efcee4fb08cae9a5888c67c83db63abb4.tar.zst
WarpX-e130e57efcee4fb08cae9a5888c67c83db63abb4.zip
Make buffer of scraped particles available to Python code (#2164)
* Added wrapper to get number of particle species tracked by the scraper Not sure if this is going to be useful, but it demonstrates a method to get information from the ParticleBoundaryBuffer into Python. * Stubbed out the main wrapper functions * Added parameters to wrapper * Added wrapper for getting the number of particles scraped of a species on a boundary * added picmi arguments to scrape particles at the domain boundary * Added wrapper to get the full particle buffer into python * rearanged the getBuffer properties code a little * Added docstrings +other suggested changes * Added num_particles_impacted_boundary docstring * fixed mistake in docstring * Changed boundary parameter to be a string for clarity * Fixed issue with the boundary parameter for scraping * Fixed issue with the boundary input for scraping stats wrapper * Added demonstration of particle scraping wrapper * Added analysis.py file * Fix typo in one of the dimension maps Co-authored-by: Roelof Groenewald <40245517+roelof-groenewald@users.noreply.github.com> * Added before esolve to warpx evolve * added test for the scraped particle buffer wrappers * Moved python PICMI particle boundary scrape test * Renamed test file to the correct name * Removed old test * added special functionality to get the timestep at which particles were scraped * removed debug print * added python wrapper for the clearParticles() function of the scraper buffer * added special wrapper function to get the timesteps at which the particles in the boundary buffer were scraped * updated test to match the non-PICMI test for the particle scraper buffer * Fix uncaught rebase mistake * re-activated picmi test of accessing the scraped particle buffers via python * added documentation for the new parameters involved in the scraped particle buffer and fixed remaining issue with picmi test * changes requested during code review Co-authored-by: mkieburtz <michaelkieburtz@gmail.com> Co-authored-by: Roelof <roelof.groenewald@modernelectron.com> Co-authored-by: Roelof Groenewald <40245517+roelof-groenewald@users.noreply.github.com>
Diffstat (limited to 'Python/pywarpx/_libwarpx.py')
-rwxr-xr-xPython/pywarpx/_libwarpx.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/Python/pywarpx/_libwarpx.py b/Python/pywarpx/_libwarpx.py
index 110de5190..ca87f4f41 100755
--- a/Python/pywarpx/_libwarpx.py
+++ b/Python/pywarpx/_libwarpx.py
@@ -120,6 +120,7 @@ class Particle(ctypes.Structure):
# some useful typenames
_LP_particle_p = ctypes.POINTER(ctypes.POINTER(Particle))
_LP_c_int = ctypes.POINTER(ctypes.c_int)
+_LP_LP_c_int = ctypes.POINTER(_LP_c_int)
_LP_c_void_p = ctypes.POINTER(ctypes.c_void_p)
_LP_c_real = ctypes.POINTER(c_real)
_LP_LP_c_real = ctypes.POINTER(_LP_c_real)
@@ -185,6 +186,9 @@ libwarpx.warpx_getChargeDensityCP.restype = _LP_LP_c_real
libwarpx.warpx_getChargeDensityCPLoVects.restype = _LP_c_int
libwarpx.warpx_getChargeDensityFP.restype = _LP_LP_c_real
libwarpx.warpx_getChargeDensityFPLoVects.restype = _LP_c_int
+libwarpx.warpx_getParticleBoundaryBufferSize.restype = ctypes.c_int
+libwarpx.warpx_getParticleBoundaryBuffer.restype = _LP_LP_c_particlereal
+libwarpx.warpx_getParticleBoundaryBufferScrapedSteps.restype = _LP_LP_c_int
libwarpx.warpx_getEx_nodal_flag.restype = _LP_c_int
libwarpx.warpx_getEy_nodal_flag.restype = _LP_c_int
@@ -763,6 +767,127 @@ def add_real_comp(species_name, pid_name, comm=True):
)
+def _get_boundary_number(boundary):
+ '''
+
+ Utility function to find the boundary number given a boundary name.
+
+ Parameters
+ ----------
+
+ boundary : the boundary from which to get the scraped particle data.
+ In the form x/y/z_hi/lo or eb.
+
+ Returns
+ -------
+
+ Integer index in the boundary scraper buffer for the given boundary.
+ '''
+ if geometry_dim == '3d':
+ dimensions = {'x' : 0, 'y' : 1, 'z' : 2}
+ elif geometry_dim == '2d':
+ dimensions = {'x' : 0, 'z' : 1}
+ else:
+ raise NotImplementedError("RZ is not supported for particle scraping.")
+
+ if boundary != 'eb':
+ boundary_parts = boundary.split("_")
+ dim_num = dimensions[boundary_parts[0]]
+ if boundary_parts[1] == 'lo':
+ side = 0
+ elif boundary_parts[1] == 'hi':
+ side = 1
+ else:
+ raise RuntimeError(f'Unknown boundary specified: {boundary}')
+ boundary_num = 2 * dim_num + side
+ else:
+ boundary_num = 4 if geometry_dim == '2d' else 6
+
+ return boundary_num
+
+
+def get_particle_boundary_buffer_size(species_name, boundary):
+ '''
+
+ This returns the number of particles that have been scraped so far in the simulation
+ from the specified boundary and of the specified species.
+
+ Parameters
+ ----------
+
+ species_name : return the number of scraped particles of this species
+ boundary : the boundary from which to get the scraped particle data.
+ In the form x/y/z_hi/lo
+
+ Returns
+ -------
+
+ The number of particles scraped so far from a boundary and of a species.
+
+ '''
+ return libwarpx.warpx_getParticleBoundaryBufferSize(
+ ctypes.c_char_p(species_name.encode('utf-8')),
+ _get_boundary_number(boundary)
+ )
+
+
+def get_particle_boundary_buffer(species_name, boundary, comp_name, level):
+ '''
+
+ This returns a list of numpy arrays containing the particle array data
+ for a species that has been scraped by a specific simulation boundary.
+
+ The data for the numpy arrays are not copied, but share the underlying
+ memory buffer with WarpX. The numpy arrays are fully writeable.
+
+ Parameters
+ ----------
+
+ species_name : the species name that the data will be returned for.
+ boundary : the boundary from which to get the scraped particle data.
+ In the form x/y/z_hi/lo or eb.
+ comp_name : the component of the array data that will be returned.
+ If "step_scraped" the special attribute holding the
+ timestep at which a particle was scraped will be
+ returned.
+ level : Which AMR level to retrieve scraped particle data from.
+ Returns
+ -------
+
+ A List of numpy arrays.
+
+ '''
+ particles_per_tile = _LP_c_int()
+ num_tiles = ctypes.c_int(0)
+ if comp_name == 'step_scraped':
+ data = libwarpx.warpx_getParticleBoundaryBufferScrapedSteps(
+ ctypes.c_char_p(species_name.encode('utf-8')),
+ _get_boundary_number(boundary), level,
+ ctypes.byref(num_tiles), ctypes.byref(particles_per_tile)
+ )
+ else:
+ data = libwarpx.warpx_getParticleBoundaryBuffer(
+ ctypes.c_char_p(species_name.encode('utf-8')),
+ _get_boundary_number(boundary), level,
+ ctypes.byref(num_tiles), ctypes.byref(particles_per_tile),
+ ctypes.c_char_p(comp_name.encode('utf-8'))
+ )
+
+ particle_data = []
+ for i in range(num_tiles.value):
+ arr = np.ctypeslib.as_array(data[i], (particles_per_tile[i],))
+ try:
+ # This fails on some versions of numpy
+ arr.setflags(write=1)
+ except ValueError:
+ pass
+ particle_data.append(arr)
+
+ _libc.free(particles_per_tile)
+ _libc.free(data)
+ return particle_data
+
+
def _get_mesh_field_list(warpx_func, level, direction, include_ghosts):
"""
Generic routine to fetch the list of field data arrays.
@@ -1677,6 +1802,7 @@ def get_mesh_charge_density_cp_lovects(level, include_ghosts=True):
'''
return _get_mesh_array_lovects(level, None, include_ghosts, libwarpx.warpx_getChargeDensityCPLoVects)
+
def get_mesh_charge_density_fp_lovects(level, include_ghosts=True):
'''