Skip to content

Commit 848f53c

Browse files
committed
Pandas: ImpactXParticleContainer.to_df()
Copy all particles into a `pandas.DataFrame`. Supports local and MPI-gathered results.
1 parent 82200fe commit 848f53c

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

src/python/ImpactXParticleContainer.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,50 @@
1212
#include <AMReX_MFIter.H>
1313
#include <AMReX_ParticleContainer.H>
1414

15+
#include <algorithm>
16+
#include <string>
17+
#include <vector>
18+
1519
namespace py = pybind11;
1620
using namespace impactx;
1721

1822

1923
void init_impactxparticlecontainer(py::module& m)
2024
{
25+
py::class_<RealAoS>(m, "RealAoS")
26+
.def_property_readonly_static("names_s",
27+
[](py::object) {
28+
std::vector<std::string> real_aos_names(RealAoS::names_s.size());
29+
std::copy(RealAoS::names_s.begin(), RealAoS::names_s.end(), real_aos_names.begin());
30+
return real_aos_names;
31+
},
32+
"named labels for fixed s")
33+
.def_property_readonly_static("names_t",
34+
[](py::object) {
35+
std::vector<std::string> real_aos_names(RealAoS::names_t.size());
36+
std::copy(RealAoS::names_t.begin(), RealAoS::names_t.end(), real_aos_names.begin());
37+
return real_aos_names;
38+
},
39+
"named labels for fixed t")
40+
;
41+
42+
py::class_<RealSoA>(m, "RealSoA")
43+
.def_property_readonly_static("names_s",
44+
[](py::object) {
45+
std::vector<std::string> real_soa_names(RealSoA::names_s.size());
46+
std::copy(RealSoA::names_s.begin(), RealSoA::names_s.end(), real_soa_names.begin());
47+
return real_soa_names;
48+
},
49+
"named labels for fixed s")
50+
.def_property_readonly_static("names_t",
51+
[](py::object) {
52+
std::vector<std::string> real_soa_names(RealSoA::names_t.size());
53+
std::copy(RealSoA::names_t.begin(), RealSoA::names_t.end(), real_soa_names.begin());
54+
return real_soa_names;
55+
},
56+
"named labels for fixed t")
57+
;
58+
2159
py::class_<
2260
ParIter,
2361
amrex::ParIter<0, 0, RealSoA::nattribs, IntSoA::nattribs>
@@ -43,6 +81,16 @@ void init_impactxparticlecontainer(py::module& m)
4381
amrex::ParticleContainer<0, 0, RealSoA::nattribs, IntSoA::nattribs>
4482
>(m, "ImpactXParticleContainer")
4583
//.def(py::init<>())
84+
85+
.def_property_readonly_static("RealAoS",
86+
[](py::object /* pc */){ return py::type::of<RealAoS>(); },
87+
"RealAoS attribute name labels"
88+
)
89+
.def_property_readonly_static("RealSoA",
90+
[](py::object /* pc */){ return py::type::of<RealSoA>(); },
91+
"RealSoA attribute name labels"
92+
)
93+
4694
.def("add_n_particles",
4795
&ImpactXParticleContainer::AddNParticles,
4896
py::arg("lev"),
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
This file is part of ImpactX
3+
4+
Copyright 2023 ImpactX contributors
5+
Authors: Axel Huebl
6+
License: BSD-3-Clause-LBNL
7+
"""
8+
9+
10+
def ix_pc_to_df(self, local=True, comm=None, root_rank=0):
11+
"""
12+
Copy all particles into a pandas.DataFrame
13+
14+
Parameters
15+
----------
16+
self : amrex.ParticleContainer_*
17+
A ParticleContainer class in pyAMReX
18+
local : bool
19+
MPI-local particles
20+
comm : MPI Communicator
21+
if local is False, this defaults to mpi4py.MPI.COMM_WORLD
22+
root_rank : MPI root rank to gather to
23+
if local is False, this defaults to 0
24+
25+
Returns
26+
-------
27+
A concatenated pandas.DataFrame with particles from all levels.
28+
29+
Returns None if no particles were found.
30+
If local=False, then all ranks but the root_rank will return None.
31+
"""
32+
df = super().to_df(local=local, comm=comm, root_rank=root_rank)
33+
34+
# rename columns according to our attribute names
35+
if df is not None:
36+
# todo: check if currently in fixed s or fixed t and pick name accordingly
37+
38+
names = []
39+
for n in self.RealAoS.names_s:
40+
names.append(n)
41+
for n in self.RealSoA.names_s:
42+
names.append(n)
43+
44+
df.columns.values[0 : len(names)] = names
45+
46+
# todo: also rename runtime attributes (e.g., "s_lost")
47+
# https://github.com/ECP-WarpX/impactx/pull/398
48+
49+
return df
50+
51+
52+
def register_ImpactXParticleContainer_extension(ixpc):
53+
"""ImpactXParticleContainer helper methods"""
54+
55+
# register member functions for ImpactXParticleContainer
56+
ixpc.to_df = ix_pc_to_df

src/python/impactx/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
# import core bindings to C++
1919
from . import impactx_pybind as cxx
20+
from .ImpactXParticleContainer import (
21+
register_ImpactXParticleContainer_extension,
22+
)
2023
from .impactx_pybind import * # noqa
2124
from .madx_to_impactx import read_beam, read_lattice # noqa
2225

@@ -35,3 +38,6 @@
3538

3639
# MAD-X file reader for reference particle
3740
RefPart.load_file = read_beam # noqa
41+
42+
# Pure Python extensions to ImpactX types
43+
register_ImpactXParticleContainer_extension(ImpactXParticleContainer)

0 commit comments

Comments
 (0)