7#include <gtest/gtest.h>
26#include "Utility/Inform.h"
32 void setType(
const std::string& t) {
36 void setBCX(
const std::string& bc) {
39 void setBCY(
const std::string& bc) {
42 void setBCZ(
const std::string& bc) {
50 constexpr size_t kParticlesPerBeam = 32;
52 class MultiContainerPartBunchTest :
public ::testing::Test {
54 static void SetUpTestSuite() {
56 char** argv =
nullptr;
57 ippl::initialize(argc, argv);
60 gmsg =
new Inform(
nullptr, -1);
64 static void TearDownTestSuite() {
70 void SetUp()
override {
71 fsCmd = std::make_shared<TestableFieldSolverCmd>();
72 fsCmd->setType(
"NONE");
76 fsCmd->setBCX(
"PERIODIC");
77 fsCmd->setBCY(
"PERIODIC");
78 fsCmd->setBCZ(
"PERIODIC");
81 dataSink = std::make_shared<DataSink>();
82 beam = std::make_shared<Beam>();
84 ASSERT_NE(testBeam,
nullptr);
86 const double q0 = 1.0e-9;
87 const double q1 = 2.0e-9;
88 const double m0 = 0.511e-3;
89 const double m1 = 0.938;
91 bunch = std::make_shared<PartBunch_t>(
92 std::vector<double>{q0, q1}, std::vector<double>{m0, m1},
93 std::vector<Beam*>{testBeam, testBeam},
94 std::vector<size_t>{kParticlesPerBeam, kParticlesPerBeam},
96 "LF2", fsCmdBase.get(), dataSink.get());
103 void TearDown()
override {
111 void createParticlesInContainer(
112 size_t containerIndex,
size_t nPart,
double pzMin,
double pzMax) {
113 auto pc = bunch->getParticleContainer(containerIndex);
114 const int mpiRank = ippl::Comm->rank();
115 std::mt19937_64 eng(1000u + containerIndex * 97u +
static_cast<unsigned>(mpiRank));
117 pc->createParticles(nPart);
119 auto R_host = pc->R.getHostMirror();
120 auto P_host = pc->P.getHostMirror();
121 auto dt_host = pc->dt.getHostMirror();
122 auto E_host = pc->E.getHostMirror();
124 const auto rmin = bunch->rmin_m;
125 const auto rmax = bunch->rmax_m;
127 std::uniform_real_distribution<double> unifR_x(rmin[0] + 0.1, rmax[0] - 0.1);
128 std::uniform_real_distribution<double> unifR_y(rmin[1] + 0.1, rmax[1] - 0.1);
129 std::uniform_real_distribution<double> unifR_z(rmin[2] + 0.1, rmax[2] - 0.1);
130 std::uniform_real_distribution<double> unifP_z(pzMin, pzMax);
132 const double dt = bunch->getdT();
133 const double qi = (containerIndex == 0) ? q0_m : q1_m;
135 for (
size_t i = 0; i < nPart; ++i) {
136 R_host(i)[0] = unifR_x(eng);
137 R_host(i)[1] = unifR_y(eng);
138 R_host(i)[2] = unifR_z(eng);
142 P_host(i)[2] = unifP_z(eng);
151 Kokkos::deep_copy(pc->R.getView(), R_host);
152 Kokkos::deep_copy(pc->P.getView(), P_host);
153 Kokkos::deep_copy(pc->dt.getView(), dt_host);
154 Kokkos::deep_copy(pc->E.getView(), E_host);
157 ippl::Comm->barrier();
162 static std::array<Vector_t<double, 3>, 2> zeroFdPair() {
163 std::array<Vector_t<double, 3>, 2> fd{};
169 std::shared_ptr<TestableFieldSolverCmd> fsCmd;
170 std::shared_ptr<FieldSolverCmd> fsCmdBase;
171 std::shared_ptr<DataSink> dataSink;
172 std::shared_ptr<Beam> beam;
173 Beam* testBeam =
nullptr;
174 std::shared_ptr<PartBunch_t> bunch;
183 TEST_F(MultiContainerPartBunchTest, TwoContainers_CountsAndDistinctPointers) {
184 ASSERT_EQ(bunch->getNumParticleContainers(), 2u);
185 ASSERT_EQ(bunch->getParticleContainers().size(), 2u);
187 auto pc0 = bunch->getParticleContainer(0);
188 auto pc1 = bunch->getParticleContainer(1);
189 ASSERT_NE(pc0,
nullptr);
190 ASSERT_NE(pc1,
nullptr);
191 EXPECT_NE(pc0.get(), pc1.get());
193 EXPECT_EQ(bunch->getParticleContainer(0).get(), bunch->getParticleContainer().get());
196 TEST_F(MultiContainerPartBunchTest, TwoContainers_PerContainerChargeAndMass) {
197 auto pc0 = bunch->getParticleContainer(0);
198 auto pc1 = bunch->getParticleContainer(1);
200 EXPECT_DOUBLE_EQ(pc0->getChargePerParticle(), q0_m);
201 EXPECT_DOUBLE_EQ(pc1->getChargePerParticle(), q1_m);
202 EXPECT_DOUBLE_EQ(pc0->getMassPerParticle(), m0_m);
203 EXPECT_DOUBLE_EQ(pc1->getMassPerParticle(), m1_m);
206 TEST_F(MultiContainerPartBunchTest, GetParticleContainer_IndexOutOfRange) {
207 EXPECT_THROW(
static_cast<void>(bunch->getParticleContainer(2)), std::out_of_range);
210 TEST_F(MultiContainerPartBunchTest, Constructor_ThrowsOnQiSizeMismatch) {
212 static_cast<void>(std::make_shared<PartBunch_t>(
213 std::vector<double>{1.0}, std::vector<double>{1.0, 1.0},
214 std::vector<Beam*>{testBeam, testBeam},
215 std::vector<size_t>{kParticlesPerBeam, kParticlesPerBeam}, 1.0,
"LF2",
216 fsCmdBase.get(), dataSink.get())),
220 TEST_F(MultiContainerPartBunchTest, Constructor_ThrowsOnNullBeam) {
222 static_cast<void>(std::make_shared<PartBunch_t>(
223 std::vector<double>{1.0, 1.0}, std::vector<double>{1.0, 1.0},
224 std::vector<Beam*>{testBeam,
nullptr},
225 std::vector<size_t>{kParticlesPerBeam, kParticlesPerBeam}, 1.0,
"LF2",
226 fsCmdBase.get(), dataSink.get())),
230 TEST_F(MultiContainerPartBunchTest, Constructor_ThrowsOnNullDataSink) {
232 static_cast<void>(std::make_shared<PartBunch_t>(
233 std::vector<double>{1.0, 1.0}, std::vector<double>{1.0, 1.0},
234 std::vector<Beam*>{testBeam, testBeam},
235 std::vector<size_t>{kParticlesPerBeam, kParticlesPerBeam}, 1.0,
"LF2",
236 fsCmdBase.get(),
nullptr)),
240 TEST_F(MultiContainerPartBunchTest, TotalNumAllContainers_SumsBoth) {
241 const size_t n0 = 11u;
242 const size_t n1 = 7u;
243 createParticlesInContainer(0, n0, 0.1, 0.5);
244 createParticlesInContainer(1, n1, 0.2, 0.6);
246 EXPECT_EQ(bunch->getTotalNumAllContainers(), n0 + n1);
251 TEST_F(MultiContainerPartBunchTest, DiagnosticStemForContainer_SingleVsMulti) {
259 TEST_F(MultiContainerPartBunchTest, DataSink_MultiContainerInit_DoesNotThrow) {
260 EXPECT_NO_THROW(
DataSink(std::vector<H5PartWrapper*>{},
false, 2));
264 TEST_F(MultiContainerPartBunchTest, DataSink_dumpSDDS_ThrowsWhenFdextTooSmall) {
265 createParticlesInContainer(0, 8u, 0.1, 0.3);
266 createParticlesInContainer(1, 6u, 0.1, 0.3);
268 DataSink ds(std::vector<H5PartWrapper*>{},
false, 2);
269 std::vector<std::array<Vector_t<double, 3>, 2>> fdTooSmall;
270 fdTooSmall.push_back(zeroFdPair());
272 const double azimuth = 0.0;
273 EXPECT_THROW(ds.dumpSDDS(*bunch, fdTooSmall, azimuth),
OpalException);
280 TEST_F(MultiContainerPartBunchTest, DataSink_dumpSDDS_NoThrowWithMatchingFdextAndHdf5Off) {
281 createParticlesInContainer(0, 8u, 0.1, 0.3);
282 createParticlesInContainer(1, 6u, 0.1, 0.3);
284 DataSink ds(std::vector<H5PartWrapper*>{},
false, 2);
285 std::vector<std::array<Vector_t<double, 3>, 2>> fd(2);
286 fd[0] = zeroFdPair();
287 fd[1] = zeroFdPair();
289 const double azimuth = 0.0;
290 EXPECT_NO_THROW(ds.dumpSDDS(*bunch, fd, azimuth));
298 TEST_F(MultiContainerPartBunchTest, DataSink_dumpH5_NoThrowWhenHdf5OffEvenIfFdextTooSmall) {
301 createParticlesInContainer(0, 4u, 0.1, 0.2);
303 DataSink ds(std::vector<H5PartWrapper*>{},
false, 2);
304 std::vector<std::array<Vector_t<double, 3>, 2>> fdTooSmall;
305 fdTooSmall.push_back(zeroFdPair());
307 EXPECT_NO_THROW(ds.dumpH5(*bunch, fdTooSmall));
314 TEST_F(MultiContainerPartBunchTest, DataSink_dumpH5_ThrowsWhenFdextTooSmallAndHdf5On) {
315 createParticlesInContainer(0, 4u, 0.1, 0.2);
320 static int h5FileCounter = 0;
321 const int tag = ++h5FileCounter;
322 const std::string f0 = std::string(
"test_mc_h5_c0_") + std::to_string(tag) +
".h5";
323 const std::string f1 = std::string(
"test_mc_h5_c1_") + std::to_string(tag) +
".h5";
325 std::vector<H5PartWrapper*> wrappers;
331 std::vector<std::array<Vector_t<double, 3>, 2>> fdTooSmall;
332 fdTooSmall.push_back(zeroFdPair());
340 std::remove(f0.c_str());
341 std::remove(f1.c_str());
ippl::Vector< T, Dim > Vector_t
Template PIC bunch: IPPL PicManager, shared field mesh/solver, and multiple particle containers.
TEST_F(MonitorTest, GetType)
static Beam * find(const std::string &name)
Find named BEAM.
static std::string diagnosticStemForContainer(const std::string &inputBasename, size_t numContainers, size_t index)
void storeInputFn(const std::string &fn)
store opals input filename
static OpalData * getInstance()
ParticleContainer< T, Dim > ParticleContainer_t
Container for all per-particle (and per-simulation) fields tracked during OPALX tracking.
void setPredefinedString(Attribute &attr, const std::string &val)
Set predefined string value.
bool enableHDF5
If true HDF5 files are written.