diff options
author | 2023-08-12 11:17:38 -0700 | |
---|---|---|
committer | 2023-08-12 11:17:38 -0700 | |
commit | 6c93d9fc13830d574c69ac7b166f5fbdb0809731 (patch) | |
tree | 8742df6045aa2bfdccb5a7991eae436e886e47d1 /Python/pywarpx/_libwarpx.py | |
parent | f6760c8e6d64605f73476f9bc8292dc9d85df454 (diff) | |
download | WarpX-6c93d9fc13830d574c69ac7b166f5fbdb0809731.tar.gz WarpX-6c93d9fc13830d574c69ac7b166f5fbdb0809731.tar.zst WarpX-6c93d9fc13830d574c69ac7b166f5fbdb0809731.zip |
Transition to pyAMReX (#3474)
* pyAMReX: Build System
* CI Updates (Changed Options)
* Callback modernization (#4)
* refactor callbacks.py
* added binding code in `pyWarpX.cpp` to add or remove keys from the callback dictionary
* minor PR cleanups
Co-authored-by: Axel Huebl <axel.huebl@plasma.ninja>
* Added Python level reference to fetch the multifabs (#3)
* pyAMReX: Build System
* Added Python level reference to Ex_aux
* Now uses the multifab map
* Fix typo
Co-authored-by: Axel Huebl <axel.huebl@plasma.ninja>
* Add initialization and finalize routines (#5)
A basic PICMI input file will now run to completion.
* Regression Tests: WarpX_PYTHON=ON
* Update Imports to nD pyAMReX
* IPO/LTO Control
Although pybind11 relies heavily on IPO/LTO to create low-latency,
small-binary bindings, some compilers will have troubles with that.
Thus, we add a compile-time option to optionally disable it when
needed.
* Fix: Link Legacy WarpXWrappers.cpp
* Wrap WarpX instance and start multi particle container
* Fix test Python_pass_mpi_comm
* Start wrapper for multiparticle container
* Add return policy
Co-authored-by: Axel Huebl <axel.huebl@plasma.ninja>
* Update fields to use MultiFabs directly
Remove EOL white space
Removed old routines accessing MultiFabs
Update to use "node_centered"
* Fix compilation with Python
* Update fields.py to use modified MultiFab tag names
* Remove incorrect, unused code
* Add function to extract the WarpX MultiParticleContainer
* Complete class WarpXParticleContainer
* Wrap functions getNprocs / getMyProc
* restore `install___` callback API - could remove later if we want but should maintain backward compatibility for now
* add `gett_new` and `getistep` functions wrappers; fix typos in `callbacks.py`; avoid error in getting `rho` from `fields.py`
* Update callback call and `getNproc`/`getMyProc` function
* Replace function add_n_particles
* Fix setitem in fields.py for 1d and 2d
* also update `gett_new()` in `_libwarpx.py` in case we want to keep that API
* added binding for `WarpXParIter` - needed to port `libwarpx.depositChargeDensity()` which is an ongoing effort
* Wrap function num_real_comp
* added binding for `TotalNumberOfParticles` and continue progress on enabling 1d MCC test to run
* add `SyncRho()` binding and create helper function in `libwarpx.depositChargeDensity` to manage scope of the particle iter
* Clean up issues in fields.py
* update bindings for `get_particle_structs`
* Fix setitem in fields.py
* switch order of initialization for particle container and particle iterator
* switch deposit_charge loop to C++ code; bind `ApplyInverseVolumeScalingToChargeDensity`
* move `WarpXParticleContainer.cpp` and `MultiParticleContainer.cpp` to new Particles folder
* added binding for `ParticleBoundaryBuffer`
* More fixes for fields.py
* Fix: Backtraces from Python
Add the Python executable name with an absolute path, so backtraces
in AMReX work. See linked AMReX issue for details.
* Cleaning
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* Fix: Backtraces from Python Part II
Do not add Python script name - it confuses the AMReX ParmParser to
build its table.
* Fix: CMake Dependencies for Wheel
This fixes a racecondition during `pip_install`: it was possible
that not all dimensions where yet build from pybind before we
start packing them in the wheel for pip install.
* MCC Test: Install Callbacks before Run
Otherwise hangs in aquiring the gil during shutdown.
* addition of `Python/pywarpx/particle_containers.py` and various associated bindings
* Fix: CMake Superbuild w/ Shared AMReX
We MUST build AMReX as a shared (so/dll/dylib) library, otherwise
all the global state in it will cause split-brain situations, where
our Python modules operate on different stacks.
* add `clear_all()` to callbacks in order to remove all callbacks at finalize
* add `-DWarpX_PYTHON=ON` to CI tests that failed to build
* add `get_comp_index` and continue to port particle data bindings
* Add AMReX Module as `libwarpx_so.amr`
Attribute to pass through the already loaded AMReX module with the
matching dimensionality to the simulation.
* Fix for fields accounting for guard cells
* Fix handling of ghost cells in fields
* Update & Test: Particle Boundary Scraping
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* CI: Python Updates
- modernize Python setups
- drop CUDA 11.0 for good and go 11.3+ as documented already
```
Error #3246: Internal Compiler Error (codegen): "there was an error in verifying the lgenfe output!"
```
* CI: Python Updates (chmod)
* Add support for cupy in fields.py
* Add MultiFab reduction routines
* CI: CUDA 11.3 is <= Ubuntu 20.04
* changed `AddNParticles` to take `amrex::Vector` arguments
* setup.py: WarpX_PYTHON=ON
* update various 2d and rz tests with new APIs
* add `-DWarpX_PYTHON_IPO=OFF` to compile string for 2d and 3d Python CI tests to speed up linking
* CI: -DpyAMReX_IPO=OFF
* CI: -DpyAMReX_IPO=OFF
actually adding `=OFF`
* CI: Intel Python
* CI: macOS Python Executable
Ensure we always use the same `python3` executable, as specified
by the `PATH` priority.
* CMake: Python Multi-Config Build
Add support for multi-config generators, especially on Windows.
* __init__.py: Windows DLL Support
Python 3.8+ on Windows: DLL search paths for dependent
shared libraries
Refs.:
- https://github.com/python/cpython/issues/80266
- https://docs.python.org/3.8/library/os.html#os.add_dll_directory
* CI: pywarpx Update
our setup.py cannot install pyamrex yet as a dependency.
* ABLASTR: `ablastr/export.H`
Add a new header to export public globals that are not covered by
`WINDOWS_EXPORT_ALL_SYMBOLS`.
https://stackoverflow.com/questions/54560832/cmake-windows-export-all-symbols-does-not-cover-global-variables/54568678#54568678
* WarpX: EXPORT Globals in `.dll` files
WarpX still uses a lot of globals:
- `static` member variables
- `extern` global variables
These globals cannot be auto-exported with CMake's
`WINDOWS_EXPORT_ALL_SYMBOLS` helper and thus we need to mark them
manually for DLL export (and import) via the new ABLASTR
`ablastr/export.H` helper macros.
This starts to export symbols in the:
- WarpX and particle container classes
- callback hook database map
- ES solver
* CI: pywarpx Clang CXXFLAGS Down
Move CXXFLAGS (`-Werror ...`) down until deps are installed.
* GNUmake: Generate `ablastr/export.H`
* CMake: More Symbol Exports for Windows
* `WarpX-tests.ini`: Simplify Python no-IPO
Also avoids subtle differences in compilation that increase
compile time.
* Update PICMI_inputs_EB_API.py for embedded_boundary_python_API CI test
* Fix Python_magnetostatic_eb_3d
* Update: Python_restart_runtime_components
New Python APIs
* Windows: no dllimport for now
* CI: Skip `PYINSTALLOPTIONS` For Now
* CMake: Dependency Bump Min-Versions
for external packages picked up by `find_package`.
* Fix F and G_fp names in fields.py
* Tests: Disable `Python_pass_mpi_comm`
* Wrappers: Cleanup
* pyWarpX: Include Cleaning
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* fields.py: Fix F and G Wrappers
Correct MultiFab names (w/o components).
* Remove unused in fields.py
* Windows: New Export Headers
- ABLASTR: `ablastr/export.H`
- WarpX: `Utils/export.H`
* removed `WarpInterface.py` since that functionality is now in `particle_containers.py`; removed parts of `WarpXWrappers.cpp` that have been ported to pyamrex
* CMake: Link OBJECT Target PRIVATE
* CMake: Remove OBJECT Target
Simplify and make `app` link `lib` (default: static). Remove OBJECT
target.
* Fix in fields.py for the components index
* Update get_particle_id/cpu
As implemented in pyAMReX with
https://github.com/AMReX-Codes/pyamrex/pull/165
* WarpX: Update for Private Constructor
* Import AMReX Before pyd DLL Call
Importing AMReX will add the `add_dll_directory` to a potentially
shared amrex DLL on Windows.
* Windows CI: Set PATH to amrex_Nd.dll
* CMake: AMReX_INSTALL After Python
In superbuild, Python can modify `AMReX_BUILD_SHARED_LIBS`.
* Clang Win CI: Manually Install requirements
Sporadic error is:
```
...
Installing collected packages: pyparsing, numpy, scipy, periodictable, picmistandard
ERROR: Could not install packages due to an OSError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\hostedtoolcache\\windows\\Python\\3.11.4\\x64\\Lib\\site-packages\\numpy\\polynomial\\__init__.py'
Consider using the `--user` option or check the permissions.
```
* Hopefully final fixes to fields.py
* Update getProbLo/getProbHi
* Set plasma length strength
Co-authored-by: Remi Lehe <remi.lehe@normalesup.org>
* Fix fields method to remove CodeQL notice
* Update Comments & Some Finalize
* Move: set_plasma_lens_strength
to MPC
---------
Co-authored-by: Roelof Groenewald <40245517+roelof-groenewald@users.noreply.github.com>
Co-authored-by: David Grote <dpgrote@lbl.gov>
Co-authored-by: Remi Lehe <remi.lehe@normalesup.org>
Co-authored-by: Dave Grote <grote1@llnl.gov>
Co-authored-by: Roelof Groenewald <regroenewald@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Diffstat (limited to 'Python/pywarpx/_libwarpx.py')
-rwxr-xr-x | Python/pywarpx/_libwarpx.py | 2734 |
1 files changed, 97 insertions, 2637 deletions
diff --git a/Python/pywarpx/_libwarpx.py b/Python/pywarpx/_libwarpx.py index 2a297b908..592459132 100755 --- a/Python/pywarpx/_libwarpx.py +++ b/Python/pywarpx/_libwarpx.py @@ -1,52 +1,31 @@ -# Copyright 2017-2019 Andrew Myers, David Grote, Remi Lehe -# Weiqun Zhang +# Copyright 2017-2022 The WarpX Community # -# This file is part of WarpX. +# This file is part of WarpX. It defines the wrapper functions that directly +# call the underlying compiled routines through pybind11. +# +# NOTE: We will reduce the libwarpx.py level of abstraction eventually! +# Please add new functionality directly to pybind11-bound modules +# and call them via sim.extension.libwarpx_so. ... and sim.extension.warpx. +# ... from user code. +# +# Authors: Axel Huebl, Andrew Myers, David Grote, Remi Lehe, Weiqun Zhang # # License: BSD-3-Clause-LBNL import atexit -import ctypes -from ctypes.util import find_library as _find_library -# --- This defines the wrapper functions that directly call the underlying compiled routines import os -import platform import sys import numpy as np -from numpy.ctypeslib import ndpointer as _ndpointer from .Geometry import geometry -try: - # --- If mpi4py is going to be used, this needs to be imported - # --- before libwarpx is loaded, because mpi4py calls MPI_Init - from mpi4py import MPI - - # --- Change MPI Comm type depending on MPICH (int) or OpenMPI (void*) - if MPI._sizeof(MPI.Comm) == ctypes.sizeof(ctypes.c_int): - _MPI_Comm_type = ctypes.c_int - else: - _MPI_Comm_type = ctypes.c_void_p -except ImportError: - MPI = None - _MPI_Comm_type = ctypes.c_void_p - -if platform.system() == 'Windows': - _path_libc = _find_library('msvcrt') -else: - _path_libc = _find_library('c') -_libc = ctypes.CDLL(_path_libc) -_LP_c_int = ctypes.POINTER(ctypes.c_int) -_LP_c_char = ctypes.c_char_p - class LibWarpX(): - - """This class manages the warpx shared object, the library from the compiled C++ code. + """This class manages the WarpX classes, part of the Python module from the compiled C++ code. It will only load the library when it is referenced, and this can only be done after the geometry is defined so that the version of the library that is needed can be determined. - Once loaded, all of the setting of function call interfaces is setup. + Once loaded, all the settings of function call interfaces are set up. """ def __init__(self): @@ -82,7 +61,9 @@ class LibWarpX(): if 'libwarpx_so' in self.__dict__: raise RuntimeError( - "Invalid attempt to load libwarpx_so library multiple times." + "Invalid attempt to load the pybind11 bindings library multiple times. " + "Note that multiple AMReX/WarpX geometries cannot be loaded yet into the same Python process. " + "Please write separate scripts for each geometry." ) # --- Use geometry to determine whether to import the 1D, 2D, 3D or RZ version. @@ -91,7 +72,7 @@ class LibWarpX(): _prob_lo = geometry.prob_lo _dims = geometry.dims except AttributeError: - raise Exception('The shared object could not be loaded. The geometry must be setup before the WarpX shared object can be accessesd. The geometry determines which version of the shared object to load.') + raise Exception('The shared object could not be loaded. The geometry must be setup before the WarpX pybind11 module can be accessesd. The geometry determines which version of the shared object to load.') if _dims == 'RZ': self.geometry_dim = 'rz' @@ -100,287 +81,33 @@ class LibWarpX(): else: raise Exception('Undefined geometry %d'%_dims) - # this is a plain C/C++ shared library, not a Python module - if os.name == 'nt': - mod_ext = 'dll' - else: - mod_ext = 'so' - libname = f'libwarpx.{self.geometry_dim}.{mod_ext}' - try: - self.libwarpx_so = ctypes.CDLL(os.path.join(self._get_package_root(), libname)) - except OSError as e: - value = e.args[0] - if f'{libname}: cannot open shared object file: No such file or directory' in value: - raise Exception(f'"{libname}" was not installed. Installation instructions can be found here https://warpx.readthedocs.io/en/latest/install/users.html') from e - else: - print("Failed to load the libwarpx shared object library") - raise - - # WarpX can be compiled using either double or float - self.libwarpx_so.warpx_Real_size.restype = ctypes.c_int - self.libwarpx_so.warpx_ParticleReal_size.restype = ctypes.c_int - - _Real_size = self.libwarpx_so.warpx_Real_size() - _ParticleReal_size = self.libwarpx_so.warpx_ParticleReal_size() - - if _Real_size == 8: - c_real = ctypes.c_double - self._numpy_real_dtype = 'f8' - else: - c_real = ctypes.c_float - self._numpy_real_dtype = 'f4' - - if _ParticleReal_size == 8: - c_particlereal = ctypes.c_double - self._numpy_particlereal_dtype = 'f8' - else: - c_particlereal = ctypes.c_float - self._numpy_particlereal_dtype = 'f4' - - self.dim = self.libwarpx_so.warpx_SpaceDim() - - # our particle data type, depends on _ParticleReal_size - _p_struct = ( - [(d, self._numpy_particlereal_dtype) for d in 'xyz'[:self.dim]] - + [('idcpu', 'u8')] - ) - self._p_dtype = np.dtype(_p_struct, align=True) - - _numpy_to_ctypes = {} - _numpy_to_ctypes[self._numpy_particlereal_dtype] = c_particlereal - _numpy_to_ctypes['u8'] = ctypes.c_uint64 - - class Particle(ctypes.Structure): - _fields_ = [(v[0], _numpy_to_ctypes[v[1]]) for v in _p_struct] - - # some useful typenames - _LP_particle_p = ctypes.POINTER(ctypes.POINTER(Particle)) - _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) - _LP_c_particlereal = ctypes.POINTER(c_particlereal) - _LP_LP_c_particlereal = ctypes.POINTER(_LP_c_particlereal) - _LP_LP_c_char = ctypes.POINTER(_LP_c_char) - - # set the arg and return types of the wrapped functions - self.libwarpx_so.amrex_init.argtypes = (ctypes.c_int, _LP_LP_c_char) - self.libwarpx_so.amrex_init_with_inited_mpi.argtypes = (ctypes.c_int, _LP_LP_c_char, _MPI_Comm_type) - self.libwarpx_so.warpx_getParticleStructs.restype = _LP_particle_p - self.libwarpx_so.warpx_getParticleArrays.restype = _LP_LP_c_particlereal - self.libwarpx_so.warpx_getParticleCompIndex.restype = ctypes.c_int - self.libwarpx_so.warpx_getEfield.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getEfieldLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getEfieldCP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getEfieldCPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getEfieldFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getEfieldFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getEfieldCP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getEfieldCPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getEfieldFP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getEfieldFPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getBfield.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getBfieldLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getBfieldCP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getBfieldCPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getBfieldFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getBfieldFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getBfieldCP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getBfieldCPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getBfieldFP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getBfieldFPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getCurrentDensity.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getCurrentDensityLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getCurrentDensityCP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getCurrentDensityCPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getCurrentDensityFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getCurrentDensityFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getCurrentDensityCP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getCurrentDensityCPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getCurrentDensityFP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getCurrentDensityFPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getCurrentDensityFP_Ampere.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getChargeDensityCP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getChargeDensityCPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getChargeDensityFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getChargeDensityFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getPhiFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getPhiFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getVectorPotentialFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getVectorPotentialFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getFfieldCP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getFfieldCPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getFfieldFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getFfieldFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getFfieldCP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getFfieldCPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getFfieldFP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getFfieldFPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getGfieldCP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getGfieldCPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getGfieldFP.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getGfieldFPLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getGfieldCP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getGfieldCPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getGfieldFP_PML.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getGfieldFPLoVects_PML.restype = _LP_c_int - self.libwarpx_so.warpx_getEdgeLengths.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getEdgeLengthsLoVects.restype = _LP_c_int - self.libwarpx_so.warpx_getFaceAreas.restype = _LP_LP_c_real - self.libwarpx_so.warpx_getFaceAreasLoVects.restype = _LP_c_int - - self.libwarpx_so.warpx_sumParticleCharge.restype = c_real - self.libwarpx_so.warpx_getParticleBoundaryBufferSize.restype = ctypes.c_int - self.libwarpx_so.warpx_getParticleBoundaryBufferStructs.restype = _LP_LP_c_particlereal - self.libwarpx_so.warpx_getParticleBoundaryBuffer.restype = _LP_LP_c_particlereal - self.libwarpx_so.warpx_getParticleBoundaryBufferScrapedSteps.restype = _LP_LP_c_int - - self.libwarpx_so.warpx_getEx_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getEy_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getEz_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getBx_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getBy_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getBz_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getJx_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getJy_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getJz_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getAx_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getAy_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getAz_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getRho_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getPhi_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getF_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getG_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getF_pml_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_getG_pml_nodal_flag.restype = _LP_c_int - - self.libwarpx_so.warpx_get_edge_lengths_x_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_get_edge_lengths_y_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_get_edge_lengths_z_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_get_face_areas_x_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_get_face_areas_y_nodal_flag.restype = _LP_c_int - self.libwarpx_so.warpx_get_face_areas_z_nodal_flag.restype = _LP_c_int - - #self.libwarpx_so.warpx_getPMLSigma.restype = _LP_c_real - #self.libwarpx_so.warpx_getPMLSigmaStar.restype = _LP_c_real - #self.libwarpx_so.warpx_ComputePMLFactors.argtypes = (ctypes.c_int, c_real) - self.libwarpx_so.warpx_addNParticles.argtypes = (ctypes.c_char_p, ctypes.c_int, - _ndpointer(c_particlereal, flags="C_CONTIGUOUS"), - _ndpointer(c_particlereal, flags="C_CONTIGUOUS"), - _ndpointer(c_particlereal, flags="C_CONTIGUOUS"), - _ndpointer(c_particlereal, flags="C_CONTIGUOUS"), - _ndpointer(c_particlereal, flags="C_CONTIGUOUS"), - _ndpointer(c_particlereal, flags="C_CONTIGUOUS"), - ctypes.c_int, - _ndpointer(c_particlereal, flags="C_CONTIGUOUS"), - ctypes.c_int, - _ndpointer(ctypes.c_int, flags="C_CONTIGUOUS"), - ctypes.c_int) - self.libwarpx_so.warpx_convert_id_to_long.argtypes = (_ndpointer(ctypes.c_int64, flags="C_CONTIGUOUS"), - _ndpointer(Particle, flags="C_CONTIGUOUS"), - ctypes.c_int) - self.libwarpx_so.warpx_convert_cpu_to_int.argtypes = (_ndpointer(ctypes.c_int32, flags="C_CONTIGUOUS"), - _ndpointer(Particle, flags="C_CONTIGUOUS"), - ctypes.c_int) - self.libwarpx_so.warpx_getProbLo.restype = c_real - self.libwarpx_so.warpx_getProbHi.restype = c_real - self.libwarpx_so.warpx_getCellSize.restype = c_real - self.libwarpx_so.warpx_getistep.restype = ctypes.c_int - self.libwarpx_so.warpx_gett_new.restype = c_real - self.libwarpx_so.warpx_getdt.restype = c_real - self.libwarpx_so.warpx_maxStep.restype = ctypes.c_int - self.libwarpx_so.warpx_stopTime.restype = c_real - self.libwarpx_so.warpx_finestLevel.restype = ctypes.c_int - self.libwarpx_so.warpx_getMyProc.restype = ctypes.c_int - self.libwarpx_so.warpx_getNProcs.restype = ctypes.c_int - - self.libwarpx_so.warpx_EvolveE.argtypes = [c_real] - self.libwarpx_so.warpx_EvolveB.argtypes = [c_real] - self.libwarpx_so.warpx_FillBoundaryE.argtypes = [] - self.libwarpx_so.warpx_FillBoundaryB.argtypes = [] - self.libwarpx_so.warpx_UpdateAuxilaryData.argtypes = [] - self.libwarpx_so.warpx_SyncCurrent.argtypes = [] - self.libwarpx_so.warpx_PushParticlesandDepose.argtypes = [c_real] - self.libwarpx_so.warpx_getProbLo.argtypes = [ctypes.c_int] - self.libwarpx_so.warpx_getProbHi.argtypes = [ctypes.c_int] - self.libwarpx_so.warpx_getCellSize.argtypes = [ctypes.c_int, ctypes.c_int] - self.libwarpx_so.warpx_getistep.argtypes = [ctypes.c_int] - self.libwarpx_so.warpx_setistep.argtypes = [ctypes.c_int, ctypes.c_int] - self.libwarpx_so.warpx_gett_new.argtypes = [ctypes.c_int] - self.libwarpx_so.warpx_sett_new.argtypes = [ctypes.c_int, c_real] - self.libwarpx_so.warpx_getdt.argtypes = [ctypes.c_int] - self.libwarpx_so.warpx_setPotentialEB.argtypes = [ctypes.c_char_p] - self.libwarpx_so.warpx_setPlasmaLensStrength.argtypes = [ctypes.c_int, c_real, c_real] - - def _get_boundary_number(self, boundary): - ''' - - Utility function to find the boundary number given a boundary name. - - Parameters - ---------- - - boundary : str - The boundary from which to get the scraped particle data. In the - form x/y/z_hi/lo or eb. - - Returns - ------- - int - Integer index in the boundary scraper buffer for the given boundary. - ''' - if self.geometry_dim == '3d': - dimensions = {'x' : 0, 'y' : 1, 'z' : 2} - elif self.geometry_dim == '2d' or self.geometry_dim == 'rz': - dimensions = {'x' : 0, 'z' : 1} - elif self.geometry_dim == '1d': - dimensions = {'z' : 0} - else: - raise RuntimeError(f"Unknown simulation geometry: {self.geometry_dim}") - - 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: - if self.geometry_dim == '3d': - boundary_num = 6 - elif self.geometry_dim == '2d' or self.geometry_dim == 'rz': - boundary_num = 4 - elif self.geometry_dim == '1d': - boundary_num = 2 - - return boundary_num - - @staticmethod - def _array1d_from_pointer(pointer, dtype, size): - ''' - - Function for converting a ctypes pointer to a numpy array - - ''' - if not pointer: - raise Exception(f'_array1d_from_pointer: pointer is a nullptr') - if sys.version_info.major >= 3: - # from where do I import these? this might only work for CPython... - #PyBuf_READ = 0x100 - PyBUF_WRITE = 0x200 - buffer_from_memory = ctypes.pythonapi.PyMemoryView_FromMemory - buffer_from_memory.argtypes = (ctypes.c_void_p, ctypes.c_int, ctypes.c_int) - buffer_from_memory.restype = ctypes.py_object - buf = buffer_from_memory(pointer, dtype.itemsize*size, PyBUF_WRITE) - else: - buffer_from_memory = ctypes.pythonapi.PyBuffer_FromReadWriteMemory - buffer_from_memory.restype = ctypes.py_object - buf = buffer_from_memory(pointer, dtype.itemsize*size) - return np.frombuffer(buf, dtype=dtype, count=size) + if self.geometry_dim == "1d": + import amrex.space1d as amr + self.amr = amr + from . import warpx_pybind_1d as cxx_1d + self.libwarpx_so = cxx_1d + self.dim = 1 + elif self.geometry_dim == "2d": + import amrex.space2d as amr + self.amr = amr + from . import warpx_pybind_2d as cxx_2d + self.libwarpx_so = cxx_2d + self.dim = 2 + elif self.geometry_dim == "rz": + import amrex.space2d as amr + self.amr = amr + from . import warpx_pybind_rz as cxx_rz + self.libwarpx_so = cxx_rz + self.dim = 2 + elif self.geometry_dim == "3d": + import amrex.space3d as amr + self.amr = amr + from . import warpx_pybind_3d as cxx_3d + self.libwarpx_so = cxx_3d + self.dim = 3 + except ImportError: + raise Exception(f"Dimensionality '{self.geometry_dim}' was not compiled in this Python install. Please recompile with -DWarpX_DIMS={_dims}") def getNProcs(self): ''' @@ -388,7 +115,7 @@ class LibWarpX(): Get the number of processors ''' - return self.libwarpx_so.warpx_getNProcs() + return self.libwarpx_so.getNProcs() def getMyProc(self): ''' @@ -396,7 +123,7 @@ class LibWarpX(): Get the number of the processor ''' - return self.libwarpx_so.warpx_getMyProc() + return self.libwarpx_so.getMyProc() def get_nattr(self): ''' @@ -417,29 +144,16 @@ class LibWarpX(): species_name: str Name of the species ''' - - return self.libwarpx_so.warpx_nCompsSpecies( - ctypes.c_char_p(species_name.encode('utf-8'))) + warpx = self.libwarpx_so.get_instance() + mpc = warpx.multi_particle_container() + pc = mpc.get_particle_container_from_name(species_name) + return pc.num_real_comps() def amrex_init(self, argv, mpi_comm=None): - # --- Construct the ctype list of strings to pass in - argc = len(argv) - - # note: +1 since there is an extra char-string array element, - # that ANSII C requires to be a simple NULL entry - # https://stackoverflow.com/a/39096006/2719194 - argvC = (_LP_c_char * (argc+1))() - for i, arg in enumerate(argv): - enc_arg = arg.encode('utf-8') - argvC[i] = _LP_c_char(enc_arg) - argvC[argc] = _LP_c_char(b"\0") # +1 element must be NULL - - if mpi_comm is None or MPI is None: - self.libwarpx_so.amrex_init(argc, argvC) + if mpi_comm is None: # or MPI is None: + self.libwarpx_so.amrex_init(argv) else: - comm_ptr = MPI._addressof(mpi_comm) - comm_val = _MPI_Comm_type.from_address(comm_ptr) - self.libwarpx_so.amrex_init_with_inited_mpi(argc, argvC, comm_val) + raise Exception('mpi_comm argument not yet supported') def initialize(self, argv=None, mpi_comm=None): ''' @@ -450,11 +164,16 @@ class LibWarpX(): if argv is None: argv = sys.argv self.amrex_init(argv, mpi_comm) - self.libwarpx_so.warpx_ConvertLabParamsToBoost() - self.libwarpx_so.warpx_ReadBCParams() + self.libwarpx_so.convert_lab_params_to_boost() + self.libwarpx_so.read_BC_params() if self.geometry_dim == 'rz': - self.libwarpx_so.warpx_CheckGriddingForRZSpectral() - self.libwarpx_so.warpx_init() + self.libwarpx_so.check_gridding_for_RZ_spectral() + self.warpx = self.libwarpx_so.get_instance() + self.warpx.initialize_data() + self.libwarpx_so.execute_python_callback("afterinit") + self.libwarpx_so.execute_python_callback("particleloader") + + #self.libwarpx_so.warpx_init() self.initialized = True @@ -464,9 +183,15 @@ class LibWarpX(): Call finalize for WarpX and AMReX. Registered to run at program exit. ''' + # TODO: simplify, part of pyAMReX already if self.initialized: - self.libwarpx_so.warpx_finalize() - self.libwarpx_so.amrex_finalize(finalize_mpi) + del self.warpx + # The call to warpx_finalize causes a crash - don't know why + #self.libwarpx_so.warpx_finalize() + self.libwarpx_so.amrex_finalize() + + from pywarpx import callbacks + callbacks.clear_all() def getistep(self, level=0): ''' @@ -479,7 +204,7 @@ class LibWarpX(): The refinement level to reference ''' - return self.libwarpx_so.warpx_getistep(level) + return self.warpx.getistep(level) def gett_new(self, level=0): ''' @@ -493,7 +218,7 @@ class LibWarpX(): The refinement level to reference ''' - return self.libwarpx_so.warpx_gett_new(level) + return self.warpx.gett_new(level) def evolve(self, num_steps=-1): ''' @@ -508,9 +233,9 @@ class LibWarpX(): The number of steps to take ''' - self.libwarpx_so.warpx_evolve(num_steps); + self.warpx.evolve(num_steps) - def getProbLo(self, direction): + def getProbLo(self, direction, level=0): ''' Get the values of the lower domain boundary. @@ -522,9 +247,9 @@ class LibWarpX(): ''' assert 0 <= direction < self.dim, 'Inappropriate direction specified' - return self.libwarpx_so.warpx_getProbLo(direction) + return self.warpx.Geom(level).ProbLo(direction) - def getProbHi(self, direction): + def getProbHi(self, direction, level=0): ''' Get the values of the upper domain boundary. @@ -536,7 +261,7 @@ class LibWarpX(): ''' assert 0 <= direction < self.dim, 'Inappropriate direction specified' - return self.libwarpx_so.warpx_getProbHi(direction) + return self.warpx.Geom(level).ProbHi(direction) def getCellSize(self, direction, level=0): ''' @@ -597,598 +322,7 @@ class LibWarpX(): # # self.libwarpx_so.warpx_ComputePMLFactors(lev, dt) - def add_particles(self, species_name, x=None, y=None, z=None, ux=None, uy=None, - uz=None, w=None, unique_particles=True, **kwargs): - ''' - A function for adding particles to the WarpX simulation. - - Parameters - ---------- - - species_name : str - The type of species for which particles will be added - - x, y, z : arrays or scalars - The particle positions (default = 0.) - - ux, uy, uz : arrays or scalars - The particle momenta (default = 0.) - - w : array or scalars - Particle weights (default = 0.) - - unique_particles : bool - Whether the particles are unique or duplicated on several processes - (default = True) - kwargs : dict - Containing an entry for all the extra particle attribute arrays. If - an attribute is not given it will be set to 0. - ''' - - # --- Get length of arrays, set to one for scalars - lenx = np.size(x) - leny = np.size(y) - lenz = np.size(z) - lenux = np.size(ux) - lenuy = np.size(uy) - lenuz = np.size(uz) - lenw = np.size(w) - - # --- Find the max length of the parameters supplied - maxlen = 0 - if x is not None: - maxlen = max(maxlen, lenx) - if y is not None: - maxlen = max(maxlen, leny) - if z is not None: - maxlen = max(maxlen, lenz) - if ux is not None: - maxlen = max(maxlen, lenux) - if uy is not None: - maxlen = max(maxlen, lenuy) - if uz is not None: - maxlen = max(maxlen, lenuz) - if w is not None: - maxlen = max(maxlen, lenw) - - # --- Make sure that the lengths of the input parameters are consistent - assert x is None or lenx==maxlen or lenx==1, "Length of x doesn't match len of others" - assert y is None or leny==maxlen or leny==1, "Length of y doesn't match len of others" - assert z is None or lenz==maxlen or lenz==1, "Length of z doesn't match len of others" - assert ux is None or lenux==maxlen or lenux==1, "Length of ux doesn't match len of others" - assert uy is None or lenuy==maxlen or lenuy==1, "Length of uy doesn't match len of others" - assert uz is None or lenuz==maxlen or lenuz==1, "Length of uz doesn't match len of others" - assert w is None or lenw==maxlen or lenw==1, "Length of w doesn't match len of others" - for key, val in kwargs.items(): - assert np.size(val)==1 or len(val)==maxlen, f"Length of {key} doesn't match len of others" - - # --- Broadcast scalars into appropriate length arrays - # --- If the parameter was not supplied, use the default value - if lenx == 1: - x = np.full(maxlen, (x or 0.), self._numpy_particlereal_dtype) - if leny == 1: - y = np.full(maxlen, (y or 0.), self._numpy_particlereal_dtype) - if lenz == 1: - z = np.full(maxlen, (z or 0.), self._numpy_particlereal_dtype) - if lenux == 1: - ux = np.full(maxlen, (ux or 0.), self._numpy_particlereal_dtype) - if lenuy == 1: - uy = np.full(maxlen, (uy or 0.), self._numpy_particlereal_dtype) - if lenuz == 1: - uz = np.full(maxlen, (uz or 0.), self._numpy_particlereal_dtype) - if lenw == 1: - w = np.full(maxlen, (w or 0.), self._numpy_particlereal_dtype) - for key, val in kwargs.items(): - if np.size(val) == 1: - kwargs[key] = np.full( - maxlen, val, self._numpy_particlereal_dtype - ) - - # --- The number of built in attributes - # --- The three velocities - built_in_attrs = 3 - if self.geometry_dim == 'rz': - # --- With RZ, there is also theta - built_in_attrs += 1 - - # --- The number of extra attributes (including the weight) - nattr = self.get_nattr_species(species_name) - built_in_attrs - attr = np.zeros((maxlen, nattr), self._numpy_particlereal_dtype) - attr[:,0] = w - - # --- Note that the velocities are handled separately and not included in attr - # --- (even though they are stored as attributes in the C++) - for key, vals in kwargs.items(): - attr[:,self.get_particle_comp_index(species_name, key) - built_in_attrs] = vals - - nattr_int = 0 - attr_int = np.empty([0], ctypes.c_int) - - # Iff x/y/z/ux/uy/uz are not numpy arrays of the correct dtype, new - # array copies are made with the correct dtype - x = x.astype(self._numpy_particlereal_dtype, copy=False) - y = y.astype(self._numpy_particlereal_dtype, copy=False) - z = z.astype(self._numpy_particlereal_dtype, copy=False) - ux = ux.astype(self._numpy_particlereal_dtype, copy=False) - uy = uy.astype(self._numpy_particlereal_dtype, copy=False) - uz = uz.astype(self._numpy_particlereal_dtype, copy=False) - - self.libwarpx_so.warpx_addNParticles( - ctypes.c_char_p(species_name.encode('utf-8')), x.size, - x, y, z, ux, uy, uz, nattr, attr, nattr_int, attr_int, unique_particles - ) - - def get_particle_count(self, species_name, local=False): - ''' - Get the number of particles of the specified species in the simulation. - - Parameters - ---------- - - species_name : str - The species name that the number will be returned for - - local : bool - If True the particle count on this processor will be returned. - Default False. - - Returns - ------- - - int - An integer count of the number of particles - ''' - - return self.libwarpx_so.warpx_getNumParticles( - ctypes.c_char_p(species_name.encode('utf-8')), local - ) - - def get_particle_structs(self, species_name, level): - ''' - This returns a list of numpy arrays containing the particle struct data - on each tile for this process. The particle data is represented as a structured - numpy array and contains the particle 'x', 'y', 'z', and 'idcpu'. - - 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 : str - The species name that the data will be returned for - - level : int - The refinement level to reference - - Returns - ------- - - List of numpy arrays - The requested particle struct data - ''' - - particles_per_tile = _LP_c_int() - num_tiles = ctypes.c_int(0) - data = self.libwarpx_so.warpx_getParticleStructs( - ctypes.c_char_p(species_name.encode('utf-8')), level, - ctypes.byref(num_tiles), ctypes.byref(particles_per_tile) - ) - - particle_data = [] - for i in range(num_tiles.value): - if particles_per_tile[i] == 0: - continue - arr = self._array1d_from_pointer(data[i], self._p_dtype, particles_per_tile[i]) - particle_data.append(arr) - - _libc.free(particles_per_tile) - _libc.free(data) - return particle_data - - def get_particle_arrays(self, species_name, comp_name, level): - ''' - This returns a list of numpy arrays containing the particle array data - on each tile for this process. - - 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 : str - The species name that the data will be returned for - - comp_name : str - The component of the array data that will be returned - - level : int - The refinement level to reference - - Returns - ------- - - List of numpy arrays - The requested particle array data - ''' - - particles_per_tile = _LP_c_int() - num_tiles = ctypes.c_int(0) - data = self.libwarpx_so.warpx_getParticleArrays( - ctypes.c_char_p(species_name.encode('utf-8')), - ctypes.c_char_p(comp_name.encode('utf-8')), - level, ctypes.byref(num_tiles), ctypes.byref(particles_per_tile) - ) - - particle_data = [] - for i in range(num_tiles.value): - if particles_per_tile[i] == 0: - continue - if not data[i]: - raise Exception(f'get_particle_arrays: data[i] for i={i} was not initialized') - 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_particle_x(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle 'x' - positions on each tile. - - ''' - structs = self.get_particle_structs(species_name, level) - if self.geometry_dim == '3d' or self.geometry_dim == '2d': - return [struct['x'] for struct in structs] - elif self.geometry_dim == 'rz': - return [struct['x']*np.cos(theta) for struct, theta in zip(structs, self.get_particle_theta(species_name))] - elif self.geometry_dim == '1d': - raise Exception('get_particle_x: There is no x coordinate with 1D Cartesian') - - def get_particle_y(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle 'y' - positions on each tile. - - ''' - structs = self.get_particle_structs(species_name, level) - if self.geometry_dim == '3d': - return [struct['y'] for struct in structs] - elif self.geometry_dim == 'rz': - return [struct['x']*np.sin(theta) for struct, theta in zip(structs, self.get_particle_theta(species_name))] - elif self.geometry_dim == '1d' or self.geometry_dim == '2d': - raise Exception('get_particle_y: There is no y coordinate with 1D or 2D Cartesian') - - def get_particle_r(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle 'r' - positions on each tile. - - ''' - structs = self.get_particle_structs(species_name, level) - if self.geometry_dim == 'rz': - return [struct['x'] for struct in structs] - elif self.geometry_dim == '3d': - return [np.sqrt(struct['x']**2 + struct['y']**2) for struct in structs] - elif self.geometry_dim == '2d' or self.geometry_dim == '1d': - raise Exception('get_particle_r: There is no r coordinate with 1D or 2D Cartesian') - - def get_particle_z(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle 'z' - positions on each tile. - - ''' - structs = self.get_particle_structs(species_name, level) - if self.geometry_dim == '3d': - return [struct['z'] for struct in structs] - elif self.geometry_dim == 'rz' or self.geometry_dim == '2d': - return [struct['y'] for struct in structs] - elif self.geometry_dim == '1d': - return [struct['x'] for struct in structs] - - def get_particle_id(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle 'id' - numbers on each tile. - - ''' - ids = [] - structs = self.get_particle_structs(species_name, level) - for ptile_of_structs in structs: - arr = np.empty(ptile_of_structs.shape, np.int64) - self.libwarpx_so.warpx_convert_id_to_long(arr, ptile_of_structs, arr.size) - ids.append(arr) - return ids - - def get_particle_cpu(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle 'cpu' - numbers on each tile. - - ''' - cpus = [] - structs = self.get_particle_structs(species_name, level) - for ptile_of_structs in structs: - arr = np.empty(ptile_of_structs.shape, np.int32) - self.libwarpx_so.warpx_convert_cpu_to_int(arr, ptile_of_structs, arr.size) - cpus.append(arr) - return cpus - - def get_particle_weight(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle - weight on each tile. - - ''' - - return self.get_particle_arrays(species_name, 'w', level) - - def get_particle_ux(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle - x momentum on each tile. - - ''' - - return self.get_particle_arrays(species_name, 'ux', level) - - def get_particle_uy(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle - y momentum on each tile. - - ''' - - return self.get_particle_arrays(species_name, 'uy', level) - - def get_particle_uz(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle - z momentum on each tile. - - ''' - - return self.get_particle_arrays(species_name, 'uz', level) - - def get_particle_theta(self, species_name, level=0): - ''' - - Return a list of numpy arrays containing the particle - theta on each tile. - - ''' - - if self.geometry_dim == 'rz': - return self.get_particle_arrays(species_name, 'theta', level) - elif self.geometry_dim == '3d': - structs = self.get_particle_structs(species_name, level) - return [np.arctan2(struct['y'], struct['x']) for struct in structs] - elif self.geometry_dim == '2d' or self.geometry_dim == '1d': - raise Exception('get_particle_theta: There is no theta coordinate with 1D or 2D Cartesian') - - def get_particle_comp_index(self, species_name, pid_name): - ''' - Get the component index for a given particle attribute. This is useful - to get the corrent ordering of attributes when adding new particles using - `add_particles()`. - - Parameters - ---------- - - species_name : str - The name of the species - - pid_name : str - Name of the component for which the index will be returned - - Returns - ------- - - int - Integer corresponding to the index of the requested attribute - ''' - - return self.libwarpx_so.warpx_getParticleCompIndex( - ctypes.c_char_p(species_name.encode('utf-8')), - ctypes.c_char_p(pid_name.encode('utf-8')) - ) - - def add_real_comp(self, species_name, pid_name, comm=True): - ''' - Add a real component to the particle data array. - - Parameters - ---------- - - species_name : str - The species name for which the new component will be added - - pid_name : str - Name that can be used to identify the new component - - comm : bool - Should the component be communicated - ''' - - self.libwarpx_so.warpx_addRealComp( - ctypes.c_char_p(species_name.encode('utf-8')), - ctypes.c_char_p(pid_name.encode('utf-8')), comm - ) - - def get_species_charge_sum(self, species_name, local=False): - ''' - Returns the total charge in the simulation due to the given species. - - Parameters - ---------- - - species_name : str - The species name for which charge will be summed - - local : bool - If True return total charge per processor - ''' - - return self.libwarpx_so.warpx_sumParticleCharge( - ctypes.c_char_p(species_name.encode('utf-8')), local - ) - - def get_particle_boundary_buffer_size(self, species_name, boundary, local=False): - ''' - 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 : str - Return the number of scraped particles of this species - - boundary : str - The boundary from which to get the scraped particle data in the - form x/y/z_hi/lo - - local : bool - Whether to only return the number of particles in the current - processor's buffer - ''' - - return self.libwarpx_so.warpx_getParticleBoundaryBufferSize( - ctypes.c_char_p(species_name.encode('utf-8')), - self._get_boundary_number(boundary), local - ) - - def get_particle_boundary_buffer_structs(self, species_name, boundary, level): - ''' - This returns a list of numpy arrays containing the particle struct data - for a species that has been scraped by a specific simulation boundary. The - particle data is represented as a structured numpy array and contains the - particle 'x', 'y', 'z', and 'idcpu'. - - 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 : str - The species name that the data will be returned for - - boundary : str - The boundary from which to get the scraped particle data in the - form x/y/z_hi/lo or eb. - - level : int - Which AMR level to retrieve scraped particle data from. - ''' - - particles_per_tile = _LP_c_int() - num_tiles = ctypes.c_int(0) - data = self.libwarpx_so.warpx_getParticleBoundaryBufferStructs( - ctypes.c_char_p(species_name.encode('utf-8')), - self._get_boundary_number(boundary), level, - ctypes.byref(num_tiles), ctypes.byref(particles_per_tile) - ) - - particle_data = [] - for i in range(num_tiles.value): - if particles_per_tile[i] == 0: - continue - arr = self._array1d_from_pointer(data[i], self._p_dtype, particles_per_tile[i]) - particle_data.append(arr) - - _libc.free(particles_per_tile) - _libc.free(data) - return particle_data - - def get_particle_boundary_buffer(self, 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 : str - The species name that the data will be returned for. - - boundary : str - The boundary from which to get the scraped particle data in the - form x/y/z_hi/lo or eb. - - comp_name : str - 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 : int - Which AMR level to retrieve scraped particle data from. - ''' - - particles_per_tile = _LP_c_int() - num_tiles = ctypes.c_int(0) - if comp_name == 'step_scraped': - data = self.libwarpx_so.warpx_getParticleBoundaryBufferScrapedSteps( - ctypes.c_char_p(species_name.encode('utf-8')), - self._get_boundary_number(boundary), level, - ctypes.byref(num_tiles), ctypes.byref(particles_per_tile) - ) - else: - data = self.libwarpx_so.warpx_getParticleBoundaryBuffer( - ctypes.c_char_p(species_name.encode('utf-8')), - self._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): - if particles_per_tile[i] == 0: - continue - if not data[i]: - raise Exception(f'get_particle_arrays: data[i] for i={i} was not initialized') - 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 clearParticleBoundaryBuffer(self): - ''' - - Clear the buffer that holds the particles lost at the boundaries. - - ''' - self.libwarpx_so.warpx_clearParticleBoundaryBuffer() def depositChargeDensity(self, species_name, level, clear_rho=True, sync_rho=True): ''' @@ -1210,15 +344,30 @@ class LibWarpX(): sync_rho : bool If True, perform MPI exchange and properly set boundary cells for rho_fp. ''' + rho_fp = self.warpx.multifab(f'rho_fp[level={level}]') + + if rho_fp is None: + raise RuntimeError("Multifab `rho_fp` is not allocated.") + # ablastr::warn_manager::WMRecordWarning( + # "WarpXWrappers", "rho_fp is not allocated", + # ablastr::warn_manager::WarnPriority::low + # ); + # return if clear_rho: - from . import fields - fields.RhoFPWrapper(level, True)[...] = 0.0 - self.libwarpx_so.warpx_depositChargeDensity( - ctypes.c_char_p(species_name.encode('utf-8')), level - ) + rho_fp.set_val(0.0) + + # deposit the charge density from the desired species + mypc = self.warpx.multi_particle_container() + myspc = mypc.get_particle_container_from_name(species_name) + myspc.deposit_charge(rho_fp, level) + + if self.geometry_dim == 'rz': + self.warpx.apply_inverse_volume_scaling_to_charge_density(rho_fp, level) + if sync_rho: - self.libwarpx_so.warpx_SyncRho() + self.warpx.sync_rho() + def set_potential_EB(self, potential): """ @@ -1230,1696 +379,7 @@ class LibWarpX(): potential : str The expression string """ - self.libwarpx_so.warpx_setPotentialEB(ctypes.c_char_p(potential.encode('utf-8'))) - - def set_plasma_lens_strength( self, i_lens, strength_E, strength_B ): - """ - Set the strength of the `i_lens`-th lens - - Parameters - ---------- - i_lens: int - Index of the lens to be modified - - strength_E, strength_B: floats - The electric and magnetic focusing strength of the lens - """ - if self._numpy_real_dtype == 'f8': - c_real = ctypes.c_double - else: - c_real = ctypes.c_float - - self.libwarpx_so.warpx_setPlasmaLensStrength( - ctypes.c_int(i_lens), c_real(strength_E), c_real(strength_B) ) - - - def _get_mesh_field_list(self, warpx_func, level, direction, include_ghosts): - """ - Generic routine to fetch the list of field data arrays. - """ - shapes = _LP_c_int() - size = ctypes.c_int(0) - ncomps = ctypes.c_int(0) - ngrowvect = _LP_c_int() - if direction is None: - data = warpx_func(level, - ctypes.byref(size), ctypes.byref(ncomps), - ctypes.byref(ngrowvect), ctypes.byref(shapes)) - else: - data = warpx_func(level, direction, - ctypes.byref(size), ctypes.byref(ncomps), - ctypes.byref(ngrowvect), ctypes.byref(shapes)) - if not data: - raise Exception('object was not initialized') - - ngvect = [ngrowvect[i] for i in range(self.dim)] - grid_data = [] - shapesize = self.dim - if ncomps.value > 1: - shapesize += 1 - for i in range(size.value): - shape = tuple([shapes[shapesize*i + d] for d in range(shapesize)]) - # --- The data is stored in Fortran order, hence shape is reversed and a transpose is taken. - if shape[::-1] == 0: - continue - if not data[i]: - raise Exception(f'get_particle_arrays: data[i] for i={i} was not initialized') - arr = np.ctypeslib.as_array(data[i], shape[::-1]).T - try: - # This fails on some versions of numpy - arr.setflags(write=1) - except ValueError: - pass - if include_ghosts: - grid_data.append(arr) - else: - grid_data.append(arr[tuple([slice(ngvect[d], -ngvect[d]) for d in range(self.dim)])]) - - _libc.free(shapes) - _libc.free(data) - return grid_data - - def get_mesh_electric_field(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh electric field - data on each grid for this process. - - This version is for the full "auxiliary" solution on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getEfield, level, direction, include_ghosts) - - def get_mesh_electric_field_cp(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh electric field - data on each grid for this process. This version returns the field on - the coarse patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getEfieldCP, level, direction, include_ghosts) - - def get_mesh_electric_field_fp(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh electric field - data on each grid for this process. This version returns the field on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getEfieldFP, level, direction, include_ghosts) - - def get_mesh_electric_field_cp_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh electric field - data on each grid for this process. This version returns the field on - the coarse patch for the PML for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getEfieldCP_PML, level, direction, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_electric_field_fp_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh electric field - data on each grid for this process. This version returns the field on - the fine patch for the PML for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getEfieldFP_PML, level, direction, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_magnetic_field(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh magnetic field - data on each grid for this process. - - This version is for the full "auxiliary" solution on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getBfield, level, direction, include_ghosts) - - def get_mesh_magnetic_field_cp(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh magnetic field - data on each grid for this process. This version returns the field on - the coarse patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getBfieldCP, level, direction, include_ghosts) - - def get_mesh_magnetic_field_fp(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh magnetic field - data on each grid for this process. This version returns the field on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getBfieldFP, level, direction, include_ghosts) - - def get_mesh_vector_potential_fp(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh vector potential - data on each grid for this process. This version returns the field on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getVectorPotentialFP, level, direction, include_ghosts) - - def get_mesh_magnetic_field_cp_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh magnetic field - data on each grid for this process. This version returns the field on - the coarse patch for the PML for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getBfieldCP_PML, level, direction, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_magnetic_field_fp_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh magnetic field - data on each grid for this process. This version returns the field on - the fine patch for the PML for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getBfieldFP_PML, level, direction, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_current_density(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh current density - data on each grid for this process. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getCurrentDensity, level, direction, include_ghosts) - - def get_mesh_current_density_cp(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh current density - data on each grid for this process. This version returns the density for - the coarse patch on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getCurrentDensityCP, level, direction, include_ghosts) - - def get_mesh_current_density_fp(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh current density - data on each grid for this process. This version returns the density on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getCurrentDensityFP, level, direction, include_ghosts) - - def get_mesh_current_density_cp_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh current density - data on each grid for this process. This version returns the density for - the coarse patch for the PML for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getCurrentDensityCP_PML, level, direction, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_current_density_fp_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh current density - data on each grid for this process. This version returns the density on - the fine patch for the PML for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getCurrentDensityFP_PML, level, direction, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_current_density_fp_ampere(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh current density - data on each grid for this process calculated from the curl of B. This - quantity is calculated in the kinetic-fluid hybrid model to get the - electron current. This function returns the current density on the fine - patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getCurrentDensityFP_Ampere, level, direction, include_ghosts) - except ValueError: - raise Exception('Current multifab not allocated.') - - def get_mesh_charge_density_cp(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh charge density - data on each grid for this process. This version returns the density for - the coarse patch on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getChargeDensityCP, level, None, include_ghosts) - - def get_mesh_charge_density_fp(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh charge density - data on each grid for this process. This version returns the density on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getChargeDensityFP, level, None, include_ghosts) - - def get_mesh_phi_fp(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh electrostatic - potential data on each grid for this process. This version returns the - potential on the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - return self._get_mesh_field_list(self.libwarpx_so.warpx_getPhiFP, level, None, include_ghosts) - - def get_mesh_F_cp(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh F field - data on each grid for this process. This version returns the F field for - the coarse patch on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getFfieldCP, level, None, include_ghosts) - - def get_mesh_F_fp(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh F field - data on each grid for this process. This version returns the F field on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getFfieldFP, level, None, include_ghosts) - - def get_mesh_F_fp_pml(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh F field - data on each grid for this process. This version returns the F field on - the fine patch for the PML on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getFfieldFP_PML, level, None, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_F_cp_pml(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh F field - data on each grid for this process. This version returns the F field on - the coarse patch for the PML on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getFfieldCP_PML, level, None, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_G_cp(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh G field - data on each grid for this process. This version returns the G field for - the coarse patch on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getGfieldCP, level, None, include_ghosts) - - def get_mesh_G_fp(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh G field - data on each grid for this process. This version returns the G field on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getGfieldFP, level, None, include_ghosts) - - def get_mesh_G_cp_pml(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh G field - data on each grid for this process. This version returns the G field on - the coarse patch for the PML on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getGfieldCP_PML, level, None, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_G_fp_pml(self, level, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh G field - data on each grid for this process. This version returns the G field on - the fine patch for the PML on the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - try: - return self._get_mesh_field_list(self.libwarpx_so.warpx_getGfieldFP_PML, level, None, include_ghosts) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_edge_lengths(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh edge lengths - data on each grid for this process. This version returns the density on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getEdgeLengths, level, direction, include_ghosts) - - def get_mesh_face_areas(self, level, direction, include_ghosts=True): - ''' - - This returns a list of numpy arrays containing the mesh face areas - data on each grid for this process. This version returns the density on - the fine patch for the given level. - - The data for the numpy arrays are not copied, but share the underlying - memory buffer with WarpX. The numpy arrays are fully writeable. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A List of numpy arrays. - - ''' - - return self._get_mesh_field_list(self.libwarpx_so.warpx_getFaceAreas, level, direction, include_ghosts) - - def _get_mesh_array_lovects(self, level, direction, include_ghosts=True, getlovectsfunc=None): - assert(0 <= level and level <= self.libwarpx_so.warpx_finestLevel()) - - size = ctypes.c_int(0) - ngrowvect = _LP_c_int() - if direction is None: - data = getlovectsfunc(level, ctypes.byref(size), ctypes.byref(ngrowvect)) - else: - data = getlovectsfunc(level, direction, ctypes.byref(size), ctypes.byref(ngrowvect)) - - if not data: - raise Exception('object was not initialized') - - lovects_ref = np.ctypeslib.as_array(data, (size.value, self.dim)) - - # --- Make a copy of the data to avoid memory problems - # --- Also, take the transpose to give shape (dims, number of grids) - lovects = lovects_ref.copy().T - - ng = [] - if include_ghosts: - for d in range(self.dim): - ng.append(ngrowvect[d]) - else: - for d in range(self.dim): - ng.append(0) - lovects[d,:] += ngrowvect[d] - - del lovects_ref - _libc.free(data) - return lovects, ng - - def get_mesh_electric_field_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - This version is for the full "auxiliary" solution on the given level. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getEfieldLoVects) - - def get_mesh_electric_field_cp_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getEfieldCPLoVects) - - def get_mesh_electric_field_fp_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getEfieldFPLoVects) - - def get_mesh_electric_field_cp_lovects_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getEfieldCPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_electric_field_fp_lovects_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getEfieldFPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_magnetic_field_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - This version is for the full "auxiliary" solution on the given level. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getBfieldLoVects) - - def get_mesh_magnetic_field_cp_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getBfieldCPLoVects) - - def get_mesh_magnetic_field_fp_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getBfieldFPLoVects) - - def get_mesh_vector_potential_fp_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh vector potential field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getVectorPotentialFPLoVects) - - def get_mesh_magnetic_field_cp_lovects_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getBfieldCPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_magnetic_field_fp_lovects_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getBfieldFPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_current_density_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getCurrentDensityLoVects) - - def get_mesh_current_density_cp_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getCurrentDensityCPLoVects) - - def get_mesh_current_density_fp_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getCurrentDensityFPLoVects) - - def get_mesh_current_density_cp_lovects_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getCurrentDensityCPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_current_density_fp_lovects_pml(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getCurrentDensityFPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_charge_density_cp_lovects(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh electric field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getChargeDensityCPLoVects) - - def get_mesh_charge_density_fp_lovects(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh - charge density data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getChargeDensityFPLoVects) - - def get_mesh_phi_fp_lovects(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh - electrostatic potential data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getPhiFPLoVects) - - def get_mesh_F_cp_lovects(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh F field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getFfieldCPLoVects) - - def get_mesh_F_fp_lovects(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh F field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getFfieldFPLoVects) - - def get_mesh_F_cp_lovects_pml(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh F field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getFfieldCPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_F_fp_lovects_pml(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh F field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getFfieldFPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_G_cp_lovects(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh G field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getGfieldCPLoVects) - - def get_mesh_G_fp_lovects(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh G field - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getGfieldFPLoVects) - - def get_mesh_G_cp_lovects_pml(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh G field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getGfieldCPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_G_fp_lovects_pml(self, level, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh G field - data on each PML grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - try: - return self._get_mesh_array_lovects(level, None, include_ghosts, self.libwarpx_so.warpx_getGfieldFPLoVects_PML) - except ValueError: - raise Exception('PML not initialized') - - def get_mesh_edge_lengths_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh edge lengths - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getEdgeLengthsLoVects) - - def get_mesh_face_areas_lovects(self, level, direction, include_ghosts=True): - ''' - - This returns a list of the lo vectors of the arrays containing the mesh face areas - data on each grid for this process. - - Parameters - ---------- - - level : the AMR level to get the data for - direction : the component of the data you want - include_ghosts : whether to include ghost zones or not - - Returns - ------- - - A 2d numpy array of the lo vector for each grid with the shape (dims, number of grids) - - ''' - return self._get_mesh_array_lovects(level, direction, include_ghosts, self.libwarpx_so.warpx_getFaceAreasLoVects) - - def _get_nodal_flag(self, getdatafunc): - data = getdatafunc() - if not data: - raise Exception('object was not initialized') - - nodal_flag_ref = np.ctypeslib.as_array(data, (self.dim,)) - - # --- Make a copy of the data to avoid memory problems - nodal_flag = nodal_flag_ref.copy() - - del nodal_flag_ref - _libc.free(data) - return nodal_flag - - def get_Ex_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Ex along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getEx_nodal_flag) - - def get_Ey_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Ey along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getEy_nodal_flag) - - def get_Ez_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Ez along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getEz_nodal_flag) - - def get_Bx_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Bx along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getBx_nodal_flag) - - def get_By_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for By along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getBy_nodal_flag) - - def get_Bz_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Bz along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getBz_nodal_flag) - - def get_Jx_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Jx along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getJx_nodal_flag) - - def get_Jy_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Jy along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getJy_nodal_flag) - - def get_Jz_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Jz along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getJz_nodal_flag) - - def get_Ax_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Ax along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getAx_nodal_flag) - - def get_Ay_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Ay along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getAy_nodal_flag) - - def get_Az_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Az along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getAz_nodal_flag) - - def get_Rho_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Rho along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getRho_nodal_flag) - - def get_Phi_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for Phi along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getPhi_nodal_flag) - - def get_F_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for F along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getF_nodal_flag) - - def get_G_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for G along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getG_nodal_flag) - - def get_edge_lengths_x_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for the x edge lengths along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_get_edge_lengths_x_nodal_flag) - - def get_edge_lengths_y_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for the y edge lengths along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_get_edge_lengths_y_nodal_flag) - - def get_edge_lengths_z_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for the z edge lengths along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_get_edge_lengths_z_nodal_flag) - - def get_face_areas_x_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for the x face areas along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_get_face_areas_x_nodal_flag) - - def get_face_areas_y_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for the y face areas along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_get_face_areas_y_nodal_flag) - - def get_face_areas_z_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for the z face areas along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_get_face_areas_z_nodal_flag) - - def get_F_pml_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for F in the PML along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getF_pml_nodal_flag) - - def get_G_pml_nodal_flag(self): - ''' - This returns a 1d array of the nodal flags for G in the PML along each direction. A 1 means node centered, and 0 cell centered. - ''' - return self._get_nodal_flag(self.libwarpx_so.warpx_getG_pml_nodal_flag) + self.warpx.set_potential_on_eb(potential) libwarpx = LibWarpX() |