diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index 9b9b9145..ba9118cd 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -82,7 +82,7 @@ jobs:
export CXX=$(which g++-10)
python3 -m pip install -U pip setuptools wheel
python3 -m pip install -U cmake
- python3 -m pip install -U pytest mpi4py
+ python3 -m pip install -U pandas pytest mpi4py
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
@@ -174,7 +174,8 @@ jobs:
export CCACHE_MAXSIZE=300M
ccache -z
- python3 -m pip install -U pip pytest
+ python3 -m pip install -U pip
+ python3 -m pip install -U pandas pytest
python3 -m pip install -v .
python3 -c "import amrex.space1d as amr; print(amr.__version__)"
python3 -c "import amrex.space2d as amr; print(amr.__version__)"
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 6682c9dd..b4b8a474 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -18,7 +18,8 @@ jobs:
python-version: '3.x'
- name: Build & Install
run: |
- python3 -m pip install -U pip pytest
+ python3 -m pip install -U pip
+ python3 -m pip install -U pandas pytest
python3 -m pip install -v .
if(!$?) { Exit $LASTEXITCODE }
diff --git a/README.md b/README.md
index c4945f83..dc85c629 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,7 @@ Optional dependencies include:
- [mpi4py](https://mpi4py.readthedocs.io) 2.1+: for multi-node and/or multi-GPU execution
- [CCache](https://ccache.dev): to speed up rebuilds (for CUDA support, needs 3.7.9+ and 4.2+ is recommended)
- further [optional dependencies of AMReX](https://github.com/AMReX-Codes/amrex/)
+- [pandas](https://pandas.pydata.org/) 2+: for DataFrame support
- [pytest](https://docs.pytest.org/en/stable/) 6.2+: for running unit tests
Optional CUDA-capable dependencies for tests include:
@@ -105,6 +106,10 @@ If you wish to run unit tests, then please install `pytest`
python3 -m pip install -U pytest
```
+Some of our tests depend on optional third-party modules (e.g., `pandas`, `cupy`, `numba`, and/or `pytorch`).
+If these are not installed then their tests will be skipped.
+
+
### Configure your compiler
For example, using the Clang compiler:
diff --git a/docs/source/install/dependencies.rst b/docs/source/install/dependencies.rst
index dd51b0fe..d43a6f15 100644
--- a/docs/source/install/dependencies.rst
+++ b/docs/source/install/dependencies.rst
@@ -28,10 +28,11 @@ Optional dependencies include:
- further `optional dependencies of AMReX `__
- `Python dependencies `__
- - `mpi4py `__
- - `cupy `__ 11.2+
- - `numba `__ 0.56+
- - `torch `__ 1.12+
+ - `mpi4py 2.1+ `__: for multi-node and/or multi-GPU execution
+ - `cupy 11.2+ `__
+ - `numba 0.56+ `__
+ - `pandas 2+ `__: for DataFrame support
+ - `torch 1.12+ `__
For all other systems, we recommend to use a **package dependency manager**:
Pick *one* of the installation methods below to install all dependencies for pyAMReX development in a consistent manner.
diff --git a/src/Particle/ParticleContainer.H b/src/Particle/ParticleContainer.H
index d283d85b..114144b8 100644
--- a/src/Particle/ParticleContainer.H
+++ b/src/Particle/ParticleContainer.H
@@ -68,6 +68,8 @@ void make_Base_Iterators (py::module &m, std::string allocstr)
py::return_value_policy::reference_internal)
.def_property_readonly_static("is_soa_particle", [](const py::object&){ return ParticleType::is_soa_particle;})
+ .def_property_readonly("size", &iterator_base::numParticles,
+ "the number of particles on this tile")
.def_property_readonly("num_particles", &iterator_base::numParticles)
.def_property_readonly("num_real_particles", &iterator_base::numRealParticles)
.def_property_readonly("num_neighbor_particles", &iterator_base::numNeighborParticles)
@@ -382,6 +384,14 @@ void make_ParticleContainer_and_Iterators (py::module &m, std::string allocstr)
make_Iterators< false, iterator, Allocator >(m, allocstr);
using const_iterator = amrex::ParConstIter_impl;
make_Iterators< true, const_iterator, Allocator >(m, allocstr);
+
+ // simpler particle iterator loops: return types of this particle box
+ py_pc
+ .def_property_readonly_static("iterator", [](py::object /* pc */){ return py::type::of(); },
+ "amrex iterator for particle boxes")
+ .def_property_readonly_static("const_iterator", [](py::object /* pc */){ return py::type::of(); },
+ "amrex constant iterator for particle boxes (read-only)")
+ ;
}
/** Create ParticleContainers and Iterators
diff --git a/src/amrex/ParticleContainer.py b/src/amrex/ParticleContainer.py
new file mode 100644
index 00000000..266496d9
--- /dev/null
+++ b/src/amrex/ParticleContainer.py
@@ -0,0 +1,104 @@
+"""
+This file is part of pyAMReX
+
+Copyright 2023 AMReX community
+Authors: Axel Huebl
+License: BSD-3-Clause-LBNL
+"""
+
+
+def pc_to_df(self, local=True, comm=None, root_rank=0):
+ """
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+ """
+ import pandas as pd
+
+ # create a DataFrame per particle box and append it to the list of
+ # local DataFrame(s)
+ dfs_local = []
+ for lvl in range(self.finest_level + 1):
+ for pti in self.const_iterator(self, level=lvl):
+ if pti.size == 0:
+ continue
+
+ if self.is_soa_particle:
+ next_df = pd.DataFrame()
+ else:
+ # AoS
+ aos_np = pti.aos().to_numpy(copy=True)
+ next_df = pd.DataFrame(aos_np)
+ next_df.set_index("cpuid")
+ next_df.index.name = "cpuid"
+
+ # SoA
+ soa_view = pti.soa().to_numpy(copy=True)
+ soa_np_real = soa_view.real
+ soa_np_int = soa_view.int
+
+ for idx, array in enumerate(soa_np_real):
+ next_df[f"SoA_real_{idx}"] = array
+ for idx, array in enumerate(soa_np_int):
+ next_df[f"SoA_int_{idx}"] = array
+
+ dfs_local.append(next_df)
+
+ # MPI Gather to root rank if requested
+ if local:
+ if len(dfs_local) == 0:
+ df = None
+ else:
+ df = pd.concat(dfs_local)
+ else:
+ from mpi4py import MPI
+
+ if comm is None:
+ comm = MPI.COMM_WORLD
+ rank = comm.Get_rank()
+
+ # a list for each rank's list of DataFrame(s)
+ df_list_list = comm.gather(dfs_local, root=root_rank)
+
+ if rank == root_rank:
+ flattened_list = [df for sublist in df_list_list for df in sublist]
+
+ if len(flattened_list) == 0:
+ df = pd.DataFrame()
+ else:
+ df = pd.concat(flattened_list, ignore_index=True)
+ else:
+ df = None
+
+ return df
+
+
+def register_ParticleContainer_extension(amr):
+ """ParticleContainer helper methods"""
+ import inspect
+ import sys
+
+ # register member functions for every ParticleContainer_* type
+ for _, ParticleContainer_type in inspect.getmembers(
+ sys.modules[amr.__name__],
+ lambda member: inspect.isclass(member)
+ and member.__module__ == amr.__name__
+ and member.__name__.startswith("ParticleContainer_"),
+ ):
+ ParticleContainer_type.to_df = pc_to_df
diff --git a/src/amrex/space1d/__init__.py b/src/amrex/space1d/__init__.py
index 060a451d..ab4d70f7 100644
--- a/src/amrex/space1d/__init__.py
+++ b/src/amrex/space1d/__init__.py
@@ -48,6 +48,7 @@ def Print(*args, **kwargs):
from ..ArrayOfStructs import register_AoS_extension
from ..MultiFab import register_MultiFab_extension
from ..PODVector import register_PODVector_extension
+from ..ParticleContainer import register_ParticleContainer_extension
from ..StructOfArrays import register_SoA_extension
register_Array4_extension(amrex_1d_pybind)
@@ -55,3 +56,4 @@ def Print(*args, **kwargs):
register_PODVector_extension(amrex_1d_pybind)
register_SoA_extension(amrex_1d_pybind)
register_AoS_extension(amrex_1d_pybind)
+register_ParticleContainer_extension(amrex_1d_pybind)
diff --git a/src/amrex/space1d/__init__.pyi b/src/amrex/space1d/__init__.pyi
index ae08abb9..a70e8422 100644
--- a/src/amrex/space1d/__init__.pyi
+++ b/src/amrex/space1d/__init__.pyi
@@ -40,6 +40,7 @@ from amrex.Array4 import register_Array4_extension
from amrex.ArrayOfStructs import register_AoS_extension
from amrex.MultiFab import register_MultiFab_extension
from amrex.PODVector import register_PODVector_extension
+from amrex.ParticleContainer import register_ParticleContainer_extension
from amrex.StructOfArrays import register_SoA_extension
from amrex.space1d.amrex_1d_pybind import (
AlmostEqual,
@@ -472,6 +473,7 @@ __all__ = [
"register_Array4_extension",
"register_MultiFab_extension",
"register_PODVector_extension",
+ "register_ParticleContainer_extension",
"register_SoA_extension",
"size",
"ubound",
diff --git a/src/amrex/space1d/amrex_1d_pybind/__init__.pyi b/src/amrex/space1d/amrex_1d_pybind/__init__.pyi
index 05d0337b..37e481f3 100644
--- a/src/amrex/space1d/amrex_1d_pybind/__init__.pyi
+++ b/src/amrex/space1d/amrex_1d_pybind/__init__.pyi
@@ -5028,6 +5028,11 @@ class ParConstIterBase_0_0_4_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_4_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5050,6 +5055,11 @@ class ParConstIterBase_0_0_4_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_4_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5072,6 +5082,11 @@ class ParConstIterBase_0_0_4_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5094,6 +5109,11 @@ class ParConstIterBase_0_0_5_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5116,6 +5136,11 @@ class ParConstIterBase_0_0_5_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5138,6 +5163,11 @@ class ParConstIterBase_0_0_5_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5160,6 +5190,11 @@ class ParConstIterBase_1_1_2_1_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5182,6 +5217,11 @@ class ParConstIterBase_1_1_2_1_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5204,6 +5244,11 @@ class ParConstIterBase_1_1_2_1_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5225,6 +5270,11 @@ class ParConstIterBase_pureSoA_8_2_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5246,6 +5296,11 @@ class ParConstIterBase_pureSoA_8_2_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5267,6 +5322,11 @@ class ParConstIterBase_pureSoA_8_2_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIter_0_0_4_0_arena(ParConstIterBase_0_0_4_0_arena):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5373,6 +5433,11 @@ class ParIterBase_0_0_4_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_4_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5395,6 +5460,11 @@ class ParIterBase_0_0_4_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_4_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5417,6 +5487,11 @@ class ParIterBase_0_0_4_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5439,6 +5514,11 @@ class ParIterBase_0_0_5_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5461,6 +5541,11 @@ class ParIterBase_0_0_5_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5483,6 +5568,11 @@ class ParIterBase_0_0_5_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5505,6 +5595,11 @@ class ParIterBase_1_1_2_1_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5527,6 +5622,11 @@ class ParIterBase_1_1_2_1_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5549,6 +5649,11 @@ class ParIterBase_1_1_2_1_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5570,6 +5675,11 @@ class ParIterBase_pureSoA_8_2_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5591,6 +5701,11 @@ class ParIterBase_pureSoA_8_2_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5612,6 +5727,11 @@ class ParIterBase_pureSoA_8_2_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIter_0_0_4_0_arena(ParIterBase_0_0_4_0_arena):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5760,6 +5880,8 @@ class ParticleContainer_0_0_4_0_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_arena
+ iterator = ParIter_0_0_4_0_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -5852,6 +5974,30 @@ class ParticleContainer_0_0_4_0_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -5861,6 +6007,8 @@ class ParticleContainer_0_0_4_0_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_default
+ iterator = ParIter_0_0_4_0_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_default, level: int, ngrow: int = 0
) -> None: ...
@@ -5953,6 +6101,30 @@ class ParticleContainer_0_0_4_0_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -5962,6 +6134,8 @@ class ParticleContainer_0_0_4_0_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_pinned
+ iterator = ParIter_0_0_4_0_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6054,6 +6228,30 @@ class ParticleContainer_0_0_4_0_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6063,6 +6261,8 @@ class ParticleContainer_0_0_5_0_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_arena
+ iterator = ParIter_0_0_5_0_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6155,6 +6355,30 @@ class ParticleContainer_0_0_5_0_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6164,6 +6388,8 @@ class ParticleContainer_0_0_5_0_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_default
+ iterator = ParIter_0_0_5_0_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6256,6 +6482,30 @@ class ParticleContainer_0_0_5_0_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6265,6 +6515,8 @@ class ParticleContainer_0_0_5_0_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_pinned
+ iterator = ParIter_0_0_5_0_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6357,6 +6609,30 @@ class ParticleContainer_0_0_5_0_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6366,6 +6642,8 @@ class ParticleContainer_1_1_2_1_arena:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_arena
+ iterator = ParIter_1_1_2_1_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6458,6 +6736,30 @@ class ParticleContainer_1_1_2_1_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6467,6 +6769,8 @@ class ParticleContainer_1_1_2_1_default:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_default
+ iterator = ParIter_1_1_2_1_default
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6559,6 +6863,30 @@ class ParticleContainer_1_1_2_1_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6568,6 +6896,8 @@ class ParticleContainer_1_1_2_1_pinned:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_pinned
+ iterator = ParIter_1_1_2_1_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6660,6 +6990,30 @@ class ParticleContainer_1_1_2_1_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6669,6 +7023,8 @@ class ParticleContainer_pureSoA_8_2_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_arena
+ iterator = ParIter_pureSoA_8_2_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6747,6 +7103,30 @@ class ParticleContainer_pureSoA_8_2_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6756,6 +7136,8 @@ class ParticleContainer_pureSoA_8_2_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_default
+ iterator = ParIter_pureSoA_8_2_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6834,6 +7216,30 @@ class ParticleContainer_pureSoA_8_2_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6843,6 +7249,8 @@ class ParticleContainer_pureSoA_8_2_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_pinned
+ iterator = ParIter_pureSoA_8_2_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6921,6 +7329,30 @@ class ParticleContainer_pureSoA_8_2_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
diff --git a/src/amrex/space2d/__init__.py b/src/amrex/space2d/__init__.py
index 6c654c52..799e9c7c 100644
--- a/src/amrex/space2d/__init__.py
+++ b/src/amrex/space2d/__init__.py
@@ -48,6 +48,7 @@ def Print(*args, **kwargs):
from ..ArrayOfStructs import register_AoS_extension
from ..MultiFab import register_MultiFab_extension
from ..PODVector import register_PODVector_extension
+from ..ParticleContainer import register_ParticleContainer_extension
from ..StructOfArrays import register_SoA_extension
register_Array4_extension(amrex_2d_pybind)
@@ -55,3 +56,4 @@ def Print(*args, **kwargs):
register_PODVector_extension(amrex_2d_pybind)
register_SoA_extension(amrex_2d_pybind)
register_AoS_extension(amrex_2d_pybind)
+register_ParticleContainer_extension(amrex_2d_pybind)
diff --git a/src/amrex/space2d/__init__.pyi b/src/amrex/space2d/__init__.pyi
index 10319d3d..a1c6bff1 100644
--- a/src/amrex/space2d/__init__.pyi
+++ b/src/amrex/space2d/__init__.pyi
@@ -40,6 +40,7 @@ from amrex.Array4 import register_Array4_extension
from amrex.ArrayOfStructs import register_AoS_extension
from amrex.MultiFab import register_MultiFab_extension
from amrex.PODVector import register_PODVector_extension
+from amrex.ParticleContainer import register_ParticleContainer_extension
from amrex.StructOfArrays import register_SoA_extension
from amrex.space2d.amrex_2d_pybind import (
AlmostEqual,
@@ -472,6 +473,7 @@ __all__ = [
"register_Array4_extension",
"register_MultiFab_extension",
"register_PODVector_extension",
+ "register_ParticleContainer_extension",
"register_SoA_extension",
"size",
"ubound",
diff --git a/src/amrex/space2d/amrex_2d_pybind/__init__.pyi b/src/amrex/space2d/amrex_2d_pybind/__init__.pyi
index 0a223460..507fdf44 100644
--- a/src/amrex/space2d/amrex_2d_pybind/__init__.pyi
+++ b/src/amrex/space2d/amrex_2d_pybind/__init__.pyi
@@ -5034,6 +5034,11 @@ class ParConstIterBase_0_0_4_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_4_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5056,6 +5061,11 @@ class ParConstIterBase_0_0_4_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_4_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5078,6 +5088,11 @@ class ParConstIterBase_0_0_4_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5100,6 +5115,11 @@ class ParConstIterBase_0_0_5_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5122,6 +5142,11 @@ class ParConstIterBase_0_0_5_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5144,6 +5169,11 @@ class ParConstIterBase_0_0_5_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5166,6 +5196,11 @@ class ParConstIterBase_1_1_2_1_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5188,6 +5223,11 @@ class ParConstIterBase_1_1_2_1_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5210,6 +5250,11 @@ class ParConstIterBase_1_1_2_1_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5231,6 +5276,11 @@ class ParConstIterBase_pureSoA_8_2_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5252,6 +5302,11 @@ class ParConstIterBase_pureSoA_8_2_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5273,6 +5328,11 @@ class ParConstIterBase_pureSoA_8_2_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIter_0_0_4_0_arena(ParConstIterBase_0_0_4_0_arena):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5379,6 +5439,11 @@ class ParIterBase_0_0_4_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_4_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5401,6 +5466,11 @@ class ParIterBase_0_0_4_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_4_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5423,6 +5493,11 @@ class ParIterBase_0_0_4_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5445,6 +5520,11 @@ class ParIterBase_0_0_5_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5467,6 +5547,11 @@ class ParIterBase_0_0_5_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5489,6 +5574,11 @@ class ParIterBase_0_0_5_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5511,6 +5601,11 @@ class ParIterBase_1_1_2_1_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5533,6 +5628,11 @@ class ParIterBase_1_1_2_1_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5555,6 +5655,11 @@ class ParIterBase_1_1_2_1_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5576,6 +5681,11 @@ class ParIterBase_pureSoA_8_2_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5597,6 +5707,11 @@ class ParIterBase_pureSoA_8_2_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5618,6 +5733,11 @@ class ParIterBase_pureSoA_8_2_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIter_0_0_4_0_arena(ParIterBase_0_0_4_0_arena):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5766,6 +5886,8 @@ class ParticleContainer_0_0_4_0_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_arena
+ iterator = ParIter_0_0_4_0_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -5858,6 +5980,30 @@ class ParticleContainer_0_0_4_0_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -5867,6 +6013,8 @@ class ParticleContainer_0_0_4_0_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_default
+ iterator = ParIter_0_0_4_0_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_default, level: int, ngrow: int = 0
) -> None: ...
@@ -5959,6 +6107,30 @@ class ParticleContainer_0_0_4_0_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -5968,6 +6140,8 @@ class ParticleContainer_0_0_4_0_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_pinned
+ iterator = ParIter_0_0_4_0_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6060,6 +6234,30 @@ class ParticleContainer_0_0_4_0_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6069,6 +6267,8 @@ class ParticleContainer_0_0_5_0_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_arena
+ iterator = ParIter_0_0_5_0_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6161,6 +6361,30 @@ class ParticleContainer_0_0_5_0_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6170,6 +6394,8 @@ class ParticleContainer_0_0_5_0_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_default
+ iterator = ParIter_0_0_5_0_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6262,6 +6488,30 @@ class ParticleContainer_0_0_5_0_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6271,6 +6521,8 @@ class ParticleContainer_0_0_5_0_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_pinned
+ iterator = ParIter_0_0_5_0_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6363,6 +6615,30 @@ class ParticleContainer_0_0_5_0_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6372,6 +6648,8 @@ class ParticleContainer_1_1_2_1_arena:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_arena
+ iterator = ParIter_1_1_2_1_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6464,6 +6742,30 @@ class ParticleContainer_1_1_2_1_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6473,6 +6775,8 @@ class ParticleContainer_1_1_2_1_default:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_default
+ iterator = ParIter_1_1_2_1_default
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6565,6 +6869,30 @@ class ParticleContainer_1_1_2_1_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6574,6 +6902,8 @@ class ParticleContainer_1_1_2_1_pinned:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_pinned
+ iterator = ParIter_1_1_2_1_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6666,6 +6996,30 @@ class ParticleContainer_1_1_2_1_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6675,6 +7029,8 @@ class ParticleContainer_pureSoA_8_2_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_arena
+ iterator = ParIter_pureSoA_8_2_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6753,6 +7109,30 @@ class ParticleContainer_pureSoA_8_2_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6762,6 +7142,8 @@ class ParticleContainer_pureSoA_8_2_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_default
+ iterator = ParIter_pureSoA_8_2_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6840,6 +7222,30 @@ class ParticleContainer_pureSoA_8_2_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6849,6 +7255,8 @@ class ParticleContainer_pureSoA_8_2_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_pinned
+ iterator = ParIter_pureSoA_8_2_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6927,6 +7335,30 @@ class ParticleContainer_pureSoA_8_2_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
diff --git a/src/amrex/space3d/__init__.py b/src/amrex/space3d/__init__.py
index baa757e7..9c1b1de9 100644
--- a/src/amrex/space3d/__init__.py
+++ b/src/amrex/space3d/__init__.py
@@ -48,6 +48,7 @@ def Print(*args, **kwargs):
from ..ArrayOfStructs import register_AoS_extension
from ..MultiFab import register_MultiFab_extension
from ..PODVector import register_PODVector_extension
+from ..ParticleContainer import register_ParticleContainer_extension
from ..StructOfArrays import register_SoA_extension
register_Array4_extension(amrex_3d_pybind)
@@ -55,3 +56,4 @@ def Print(*args, **kwargs):
register_PODVector_extension(amrex_3d_pybind)
register_SoA_extension(amrex_3d_pybind)
register_AoS_extension(amrex_3d_pybind)
+register_ParticleContainer_extension(amrex_3d_pybind)
diff --git a/src/amrex/space3d/__init__.pyi b/src/amrex/space3d/__init__.pyi
index 4467496b..dc3e69b1 100644
--- a/src/amrex/space3d/__init__.pyi
+++ b/src/amrex/space3d/__init__.pyi
@@ -40,6 +40,7 @@ from amrex.Array4 import register_Array4_extension
from amrex.ArrayOfStructs import register_AoS_extension
from amrex.MultiFab import register_MultiFab_extension
from amrex.PODVector import register_PODVector_extension
+from amrex.ParticleContainer import register_ParticleContainer_extension
from amrex.StructOfArrays import register_SoA_extension
from amrex.space3d.amrex_3d_pybind import (
AlmostEqual,
@@ -472,6 +473,7 @@ __all__ = [
"register_Array4_extension",
"register_MultiFab_extension",
"register_PODVector_extension",
+ "register_ParticleContainer_extension",
"register_SoA_extension",
"size",
"ubound",
diff --git a/src/amrex/space3d/amrex_3d_pybind/__init__.pyi b/src/amrex/space3d/amrex_3d_pybind/__init__.pyi
index d2759024..743719f5 100644
--- a/src/amrex/space3d/amrex_3d_pybind/__init__.pyi
+++ b/src/amrex/space3d/amrex_3d_pybind/__init__.pyi
@@ -5037,6 +5037,11 @@ class ParConstIterBase_0_0_4_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_4_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5059,6 +5064,11 @@ class ParConstIterBase_0_0_4_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_4_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5081,6 +5091,11 @@ class ParConstIterBase_0_0_4_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5103,6 +5118,11 @@ class ParConstIterBase_0_0_5_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5125,6 +5145,11 @@ class ParConstIterBase_0_0_5_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_0_0_5_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5147,6 +5172,11 @@ class ParConstIterBase_0_0_5_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5169,6 +5199,11 @@ class ParConstIterBase_1_1_2_1_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5191,6 +5226,11 @@ class ParConstIterBase_1_1_2_1_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_1_1_2_1_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5213,6 +5253,11 @@ class ParConstIterBase_1_1_2_1_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5234,6 +5279,11 @@ class ParConstIterBase_pureSoA_8_2_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5255,6 +5305,11 @@ class ParConstIterBase_pureSoA_8_2_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIterBase_pureSoA_8_2_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5276,6 +5331,11 @@ class ParConstIterBase_pureSoA_8_2_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParConstIter_0_0_4_0_arena(ParConstIterBase_0_0_4_0_arena):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5382,6 +5442,11 @@ class ParIterBase_0_0_4_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_4_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5404,6 +5469,11 @@ class ParIterBase_0_0_4_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_4_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5426,6 +5496,11 @@ class ParIterBase_0_0_4_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5448,6 +5523,11 @@ class ParIterBase_0_0_5_0_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5470,6 +5550,11 @@ class ParIterBase_0_0_5_0_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_0_0_5_0_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5492,6 +5577,11 @@ class ParIterBase_0_0_5_0_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5514,6 +5604,11 @@ class ParIterBase_1_1_2_1_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5536,6 +5631,11 @@ class ParIterBase_1_1_2_1_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_1_1_2_1_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5558,6 +5658,11 @@ class ParIterBase_1_1_2_1_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_arena(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5579,6 +5684,11 @@ class ParIterBase_pureSoA_8_2_arena(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_default(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5600,6 +5710,11 @@ class ParIterBase_pureSoA_8_2_default(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIterBase_pureSoA_8_2_pinned(MFIter):
is_soa_particle: typing.ClassVar[bool] = True
@@ -5621,6 +5736,11 @@ class ParIterBase_pureSoA_8_2_pinned(MFIter):
def num_real_particles(self) -> int: ...
@property
def pair_index(self) -> tuple[int, int]: ...
+ @property
+ def size(self) -> int:
+ """
+ the number of particles on this tile
+ """
class ParIter_0_0_4_0_arena(ParIterBase_0_0_4_0_arena):
is_soa_particle: typing.ClassVar[bool] = False
@@ -5769,6 +5889,8 @@ class ParticleContainer_0_0_4_0_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_arena
+ iterator = ParIter_0_0_4_0_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -5861,6 +5983,30 @@ class ParticleContainer_0_0_4_0_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -5870,6 +6016,8 @@ class ParticleContainer_0_0_4_0_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_default
+ iterator = ParIter_0_0_4_0_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_default, level: int, ngrow: int = 0
) -> None: ...
@@ -5962,6 +6110,30 @@ class ParticleContainer_0_0_4_0_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -5971,6 +6143,8 @@ class ParticleContainer_0_0_4_0_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_4_0_pinned
+ iterator = ParIter_0_0_4_0_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_4_0_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6063,6 +6237,30 @@ class ParticleContainer_0_0_4_0_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6072,6 +6270,8 @@ class ParticleContainer_0_0_5_0_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_arena
+ iterator = ParIter_0_0_5_0_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6164,6 +6364,30 @@ class ParticleContainer_0_0_5_0_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6173,6 +6397,8 @@ class ParticleContainer_0_0_5_0_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_default
+ iterator = ParIter_0_0_5_0_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6265,6 +6491,30 @@ class ParticleContainer_0_0_5_0_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6274,6 +6524,8 @@ class ParticleContainer_0_0_5_0_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_0_0_5_0_pinned
+ iterator = ParIter_0_0_5_0_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_5_0_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6366,6 +6618,30 @@ class ParticleContainer_0_0_5_0_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6375,6 +6651,8 @@ class ParticleContainer_1_1_2_1_arena:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_arena
+ iterator = ParIter_1_1_2_1_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6467,6 +6745,30 @@ class ParticleContainer_1_1_2_1_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6476,6 +6778,8 @@ class ParticleContainer_1_1_2_1_default:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_default
+ iterator = ParIter_1_1_2_1_default
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6568,6 +6872,30 @@ class ParticleContainer_1_1_2_1_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6577,6 +6905,8 @@ class ParticleContainer_1_1_2_1_pinned:
NStructInt: typing.ClassVar[int] = 1
NStructReal: typing.ClassVar[int] = 1
is_soa_particle: typing.ClassVar[bool] = False
+ const_iterator = ParConstIter_1_1_2_1_pinned
+ iterator = ParIter_1_1_2_1_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_1_1_2_1_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6669,6 +6999,30 @@ class ParticleContainer_1_1_2_1_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6678,6 +7032,8 @@ class ParticleContainer_pureSoA_8_2_arena:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_arena
+ iterator = ParIter_pureSoA_8_2_arena
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_arena, level: int, ngrow: int = 0
) -> None: ...
@@ -6756,6 +7112,30 @@ class ParticleContainer_pureSoA_8_2_arena:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6765,6 +7145,8 @@ class ParticleContainer_pureSoA_8_2_default:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_default
+ iterator = ParIter_pureSoA_8_2_default
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_default, level: int, ngrow: int = 0
) -> None: ...
@@ -6843,6 +7225,30 @@ class ParticleContainer_pureSoA_8_2_default:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
@@ -6852,6 +7258,8 @@ class ParticleContainer_pureSoA_8_2_pinned:
NStructInt: typing.ClassVar[int] = 0
NStructReal: typing.ClassVar[int] = 0
is_soa_particle: typing.ClassVar[bool] = True
+ const_iterator = ParConstIter_pureSoA_8_2_pinned
+ iterator = ParIter_pureSoA_8_2_pinned
def AddParticlesAtLevel(
self, particles: ParticleTile_0_0_8_2_pinned, level: int, ngrow: int = 0
) -> None: ...
@@ -6930,6 +7338,30 @@ class ParticleContainer_pureSoA_8_2_pinned:
def numLocalTilesAtLevel(self, arg0: int) -> int: ...
def reserveData(self) -> None: ...
def resizeData(self) -> None: ...
+ def to_df(self, local=True, comm=None, root_rank=0):
+ """
+
+ Copy all particles into a pandas.DataFrame
+
+ Parameters
+ ----------
+ self : amrex.ParticleContainer_*
+ A ParticleContainer class in pyAMReX
+ local : bool
+ MPI-local particles
+ comm : MPI Communicator
+ if local is False, this defaults to mpi4py.MPI.COMM_WORLD
+ root_rank : MPI root rank to gather to
+ if local is False, this defaults to 0
+
+ Returns
+ -------
+ A concatenated pandas.DataFrame with particles from all levels.
+
+ Returns None if no particles were found.
+ If local=False, then all ranks but the root_rank will return None.
+
+ """
@property
def finest_level(self) -> int: ...
diff --git a/tests/test_particleContainer.py b/tests/test_particleContainer.py
index 668ed42c..9f1897e4 100644
--- a/tests/test_particleContainer.py
+++ b/tests/test_particleContainer.py
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
+import importlib
+
import numpy as np
import pytest
@@ -272,3 +274,38 @@ def test_per_cell(empty_particle_container, std_geometry, std_particle):
assert pc.TotalNumberOfParticles() == pc.NumberOfParticlesAtLevel(0) == ncells
print("npts * real_1", ncells * std_particle.real_array_data[1])
assert ncells * std_particle.real_array_data[1] == sum_1
+
+
+@pytest.mark.skipif(
+ importlib.util.find_spec("pandas") is None, reason="pandas is not available"
+)
+def test_pc_df(particle_container, Npart):
+ pc = particle_container
+ print(f"pc={pc}")
+ df = pc.to_df()
+ print(df.columns)
+ print(df)
+
+
+@pytest.mark.skipif(
+ importlib.util.find_spec("pandas") is None, reason="pandas is not available"
+)
+def test_pc_empty_df(empty_particle_container, Npart):
+ pc = empty_particle_container
+ print(f"pc={pc}")
+ df = pc.to_df()
+ assert df is None
+
+
+@pytest.mark.skipif(
+ importlib.util.find_spec("pandas") is None, reason="pandas is not available"
+)
+@pytest.mark.skipif(not amr.Config.have_mpi, reason="Requires AMReX_MPI=ON")
+def test_pc_df_mpi(particle_container, Npart):
+ pc = particle_container
+ print(f"pc={pc}")
+ df = pc.to_df(local=False)
+ if df is not None:
+ # only rank 0
+ print(df.columns)
+ print(df)