OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestRFCavity.cpp
Go to the documentation of this file.
1
58#include <gtest/gtest.h>
59
62#include "Fields/Fieldmap.h"
63
64#include <cmath>
65#include <memory>
66
67class FakeFieldmap : public Fieldmap {
68public:
69 FakeFieldmap() : Fieldmap("dummy"), outOfBounds_(false) {}
70
71 void setOutOfBounds(bool v) { outOfBounds_ = v; }
72
75 Vector_t<double, 3>& B) const override {
76 if (outOfBounds_) return true;
77
78 E = {1.0, 0.0, 0.0};
79 B = {0.0, 1.0, 0.0};
80 return false; // inside
81 }
82
83 void getFieldDimensions(double& zBegin, double& zEnd) const override {
84 zBegin = 0.0;
85 zEnd = 1.0;
86 }
87
89 double& zBegin, double& zEnd, double&, double&, double&, double&) const override {
90 zBegin = 0.0;
91 zEnd = 1.0;
92 }
93
94 bool isInside(const Vector_t<double, 3>&) const override { return true; }
95
96 // --- required no-op implementations ---
97 void applyField(std::shared_ptr<ParticleContainer_t>, double = 1.0) override {}
100 const DiffDirection&) const override {
101 return false;
102 }
103
104 void swap() override {}
105 void getInfo(Inform*) override {}
106 double getFrequency() const override { return 1.0; }
107 void setFrequency(double) override {}
108 void readMap() override {}
109 void freeMap() override {}
110
111private:
113};
114
115// ---------------------------------------------------------------------------
116// Dummy Geometry (fully concrete)
117// ---------------------------------------------------------------------------
119public:
120 double getArcLength() const override { return 0.0; }
121 double getElementLength() const override { return length_m; }
122 void setElementLength(double length) override { length_m = length; }
123
124 Euclid3D getTransform(double, double) const override { return Euclid3D(); }
125
126private:
127 double length_m = 0.0;
128};
129
130// ---------------------------------------------------------------------------
131// Dummy Field (fully concrete)
132// ---------------------------------------------------------------------------
133class DummyField : public EMField {
134public:
135 void scale(double) override {}
136};
137
138// ---------------------------------------------------------------------------
139// Minimal concrete RFCavity
140// ---------------------------------------------------------------------------
141class TestRFCavity : public RFCavity {
142public:
143 TestRFCavity() : RFCavity("test") {}
144
145 // ---- REQUIRED PURE VIRTUALS ----
146 double getAmplitude() const override { return amplitude_; }
147 double getFrequency() const override { return frequency_; }
148 double getPhase() const override { return phase_; }
149
150 ElementBase* clone() const override { return new TestRFCavity(*this); }
151
152 BGeometryBase& getGeometry() override { return geom_; }
153 const BGeometryBase& getGeometry() const override { return geom_; }
154
155 EMField& getField() override { return field_; }
156 const EMField& getField() const override { return field_; }
157
158 // ---- Simple setters for testing ----
159 void setAmplitude(double v) { amplitude_ = v; }
160 void setFrequency(double v) { frequency_ = v; }
161 void setPhase(double v) { phase_ = v; }
162
163 void setScale(double v) { scale_m = v; }
164 void setPhaseInternal(double v) { phase_m = v; }
165 void setFrequencyInternal(double v) { frequency_m = v; }
166
167 void setFieldmap(Fieldmap* fmap) { fieldmap_m = fmap; }
168 void setStartField(double val) { startField_m = val; }
169 void setEndField(double val) { endField_m = val; }
170
171private:
172 double amplitude_ = 0.0;
173 double frequency_ = 0.0;
174 double phase_ = 0.0;
175
178};
179
180// ---------------------------------------------------------------------------
181// Test Fixture
182// ---------------------------------------------------------------------------
183class RFCavityTest : public ::testing::Test {
184protected:
185 void SetUp() override {
186 cav_ = std::make_unique<TestRFCavity>();
187 fmap_ = std::make_unique<FakeFieldmap>();
188
189 // --- Geometry ---
190 cav_->setFieldmap(fmap_.get());
191 cav_->setStartField(0.0);
192 cav_->setEndField(1.0);
193 cav_->setElementLength(1.0);
194
195 // --- RF defaults ---
196 cav_->setScale(1.0);
197 cav_->setFrequencyInternal(1.0);
198 cav_->setPhaseInternal(0.0);
199 }
200 std::unique_ptr<TestRFCavity> cav_;
201 std::unique_ptr<FakeFieldmap> fmap_;
202};
203
204// ---------------------------------------------------------------------------
205// Basic API
206// ---------------------------------------------------------------------------
207TEST_F(RFCavityTest, GetType) { EXPECT_EQ(cav_->getType(), ElementType::RFCAVITY); }
208
209TEST_F(RFCavityTest, Bends) { EXPECT_FALSE(cav_->bends()); }
210
211TEST_F(RFCavityTest, GetSetAmplitudeFrequencyPhase) {
212 cav_->setAmplitude(5.0);
213 cav_->setFrequency(2.0);
214 cav_->setPhase(0.5);
215
216 EXPECT_DOUBLE_EQ(cav_->getAmplitude(), 5.0);
217 EXPECT_DOUBLE_EQ(cav_->getFrequency(), 2.0);
218 EXPECT_DOUBLE_EQ(cav_->getPhase(), 0.5);
219}
220
221// ---------------------------------------------------------------------------
222// Geometry / dimensions
223// ---------------------------------------------------------------------------
224TEST_F(RFCavityTest, GetDimensions) {
225 double zBegin = -1.0, zEnd = -1.0;
226
227 cav_->getFieldExtend(zBegin, zEnd);
228
229 EXPECT_EQ(zBegin, 0.0);
230 EXPECT_EQ(zEnd, 1.0);
231}
232
233TEST_F(RFCavityTest, BodyExtentCanDifferFromFieldSupport) {
234 cav_->setStartField(0.2);
235 cav_->setEndField(0.8);
236 cav_->setElementLength(1.0);
237
238 double bodyBegin = -1.0, bodyEnd = -1.0;
239 cav_->getElementDimensions(bodyBegin, bodyEnd);
240 EXPECT_EQ(bodyBegin, 0.0);
241 EXPECT_EQ(bodyEnd, 1.0);
242
243 const auto entry = cav_->getEdgeToBegin();
244 const auto exit = cav_->getEdgeToEnd();
245 EXPECT_EQ(entry.getOrigin()(2), 0.0);
246 EXPECT_EQ(exit.getOrigin()(2), 1.0);
247
248 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
249 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
250 EXPECT_FALSE(cav_->apply({0.0, 0.0, 0.1}, {0.0, 0.0, 1.0}, 0.0, E, B));
251 EXPECT_DOUBLE_EQ(E(0), 0.0);
252
253 EXPECT_FALSE(cav_->apply({0.0, 0.0, 0.5}, {0.0, 0.0, 1.0}, 0.0, E, B));
254 EXPECT_DOUBLE_EQ(E(0), 1.0);
255}
256
257TEST_F(RFCavityTest, ZeroBodyLengthDoesNotFallBackToFieldmapLength) {
258 cav_->setElementLength(0.0);
259
260 EXPECT_DOUBLE_EQ(cav_->getElementLength(), 0.0);
261
262 double bodyBegin = -1.0, bodyEnd = -1.0;
263 cav_->getElementDimensions(bodyBegin, bodyEnd);
264 EXPECT_DOUBLE_EQ(bodyBegin, 0.0);
265 EXPECT_DOUBLE_EQ(bodyEnd, 0.0);
266
267 double fieldBegin = -1.0, fieldEnd = -1.0;
268 cav_->getFieldExtend(fieldBegin, fieldEnd);
269 EXPECT_DOUBLE_EQ(fieldBegin, 0.0);
270 EXPECT_DOUBLE_EQ(fieldEnd, 1.0);
271}
272
273// ---------------------------------------------------------------------------
274// apply(): spatial behavior
275// ---------------------------------------------------------------------------
276TEST_F(RFCavityTest, ApplyInside) {
277 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
278 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
279 Vector_t<double, 3> E = {1.0, 2.0, 3.0};
280 Vector_t<double, 3> B = {1.0, 2.0, 3.0};
281
282 cav_->apply(R, P, 0.0, E, B);
283
284 // cos(0) = 1 → E += scale * E_map
285 EXPECT_DOUBLE_EQ(E(0), 1.0 + 1.0);
286 EXPECT_DOUBLE_EQ(E(1), 2.0);
287 EXPECT_DOUBLE_EQ(E(2), 3.0);
288
289 // sin(0) = 0 → no B contribution
290 EXPECT_DOUBLE_EQ(B(0), 1.0);
291 EXPECT_DOUBLE_EQ(B(1), 2.0);
292 EXPECT_DOUBLE_EQ(B(2), 3.0);
293}
294
295TEST_F(RFCavityTest, ApplyBefore) {
296 Vector_t<double, 3> R = {0.0, 0.0, -0.1};
297 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
298 Vector_t<double, 3> E = {1.0, 2.0, 3.0};
299 Vector_t<double, 3> B = {1.0, 2.0, 3.0};
300
301 cav_->apply(R, P, 0.0, E, B);
302
303 // No expected contribution
304 EXPECT_DOUBLE_EQ(E(0), 1.0);
305 EXPECT_DOUBLE_EQ(E(1), 2.0);
306 EXPECT_DOUBLE_EQ(E(2), 3.0);
307
308 EXPECT_DOUBLE_EQ(B(0), 1.0);
309 EXPECT_DOUBLE_EQ(B(1), 2.0);
310 EXPECT_DOUBLE_EQ(B(2), 3.0);
311}
312
313TEST_F(RFCavityTest, ApplyAfter) {
314 Vector_t<double, 3> R = {0.0, 0.0, 1.5};
315 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
316 Vector_t<double, 3> E = {1.0, 2.0, 3.0};
317 Vector_t<double, 3> B = {1.0, 2.0, 3.0};
318
319 cav_->apply(R, P, 0.0, E, B);
320
321 // No expected contribution
322 EXPECT_DOUBLE_EQ(E(0), 1.0);
323 EXPECT_DOUBLE_EQ(E(1), 2.0);
324 EXPECT_DOUBLE_EQ(E(2), 3.0);
325
326 EXPECT_DOUBLE_EQ(B(0), 1.0);
327 EXPECT_DOUBLE_EQ(B(1), 2.0);
328 EXPECT_DOUBLE_EQ(B(2), 3.0);
329}
330
331// ---------------------------------------------------------------------------
332// RF phase behavior (cos/sin physics)
333// ---------------------------------------------------------------------------
334// E ∝ cos(ωt + φ)
335// B ∝ -sin(ωt + φ)
336TEST_F(RFCavityTest, ApplyPhaseZero) {
337 // φ = 0 → cos = 1, sin = 0
338 cav_->setPhasem(0.0);
339 cav_->setFrequencym(1.0);
340
341 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
342 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
343 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
344 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
345
346 cav_->apply(R, P, 0.0, E, B);
347
348 EXPECT_NE(E(0), 0.0); // x-component exists
349 EXPECT_DOUBLE_EQ(E(1), 0.0);
350 EXPECT_DOUBLE_EQ(E(2), 0.0);
351
352 // No magnetic field at phase = 0
353 EXPECT_DOUBLE_EQ(B(0), 0.0);
354 EXPECT_DOUBLE_EQ(B(1), 0.0);
355 EXPECT_DOUBLE_EQ(B(2), 0.0);
356}
357
358TEST_F(RFCavityTest, ApplyPhaseShift) {
359 // φ = π/2 → cos = 0, sin = 1
360 cav_->setPhasem(M_PI / 2.0);
361
362 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
363 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
364 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
365 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
366
367 cav_->apply(R, P, 0.0, E, B);
368
369 // cos(pi/2) = 0 → no E
370 EXPECT_NEAR(E(0), 0.0, 1e-12);
371
372 // sin(pi/2) = 1 → B -= scale * B_map
373 EXPECT_DOUBLE_EQ(B(1), -1.0);
374}
375
376TEST_F(RFCavityTest, ApplyPhasePi) {
377 // φ = π → cos = -1, sin = 0
378 cav_->setPhasem(M_PI);
379 cav_->setFrequencym(1.0);
380
381 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
382 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
383 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
384 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
385
386 cav_->apply(R, P, 0.0, E, B);
387
388 // cos(π) = -1 → E flipped
389 EXPECT_NEAR(E(0), -1.0, 1e-12);
390 EXPECT_DOUBLE_EQ(E(1), 0.0);
391 EXPECT_DOUBLE_EQ(E(2), 0.0);
392
393 // sin(π)=0 → no B
394 EXPECT_DOUBLE_EQ(B(0), 0.0);
395 EXPECT_NEAR(B(1), 0.0, 1e-12);
396 EXPECT_DOUBLE_EQ(B(2), 0.0);
397}
398
399TEST_F(RFCavityTest, PhaseIndependentOfFrequencyAtT0) {
400 cav_->setPhasem(M_PI / 2.0);
401
402 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
403 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
404
405 Vector_t<double, 3> E1 = {0.0, 0.0, 0.0};
406 Vector_t<double, 3> B1 = {0.0, 0.0, 0.0};
407
408 cav_->setFrequencym(1.0);
409 cav_->apply(R, P, 0.0, E1, B1);
410
411 Vector_t<double, 3> E2 = {0.0, 0.0, 0.0};
412 Vector_t<double, 3> B2 = {0.0, 0.0, 0.0};
413
414 cav_->setFrequencym(10.0);
415 cav_->apply(R, P, 0.0, E2, B2);
416
417 EXPECT_NEAR(E1(0), 0.0, 1e-12);
418 EXPECT_NEAR(E2(0), 0.0, 1e-12);
419
420 EXPECT_NEAR(B1(1), -1.0, 1e-12);
421 EXPECT_NEAR(B2(1), -1.0, 1e-12);
422}
423
424// ---------------------------------------------------------------------------
425// Scaling behavior
426// ---------------------------------------------------------------------------
427TEST_F(RFCavityTest, ApplyScaling) {
428 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
429 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
430
431 // Baseline
432 Vector_t<double, 3> E1 = {0, 0, 0}, B1 = {0, 0, 0};
433 cav_->apply(R, P, 0.0, E1, B1);
434
435 // Scaled
436 Vector_t<double, 3> E2 = {0, 0, 0}, B2 = {0, 0, 0};
437 cav_->setScale(2.0);
438 cav_->apply(R, P, 0.0, E2, B2);
439
440 // compare
441 EXPECT_NEAR(E2(0), 2.0 * E1(0), 1e-12);
442 EXPECT_NEAR(E2(1), 2.0 * E1(1), 1e-12);
443 EXPECT_NEAR(E2(2), 2.0 * E1(2), 1e-12);
444}
445
446// ---------------------------------------------------------------------------
447// Time dependence
448// ---------------------------------------------------------------------------
449TEST_F(RFCavityTest, TimeDependence) {
450 cav_->setPhasem(0.0);
451 cav_->setFrequencym(1.0);
452
453 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
454 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
455
456 Vector_t<double, 3> E0 = {0.0, 0.0, 0.0};
457 Vector_t<double, 3> B0 = {0.0, 0.0, 0.0};
458
459 cav_->apply(R, P, 0.0, E0, B0); // phi = 0
460
461 Vector_t<double, 3> E1 = {0.0, 0.0, 0.0};
462 Vector_t<double, 3> B1 = {0.0, 0.0, 0.0};
463
464 cav_->apply(R, P, M_PI / 2.0, E1, B1); // phi = pi/2
465
466 EXPECT_NEAR(E0(0), 1.0, 1e-12); // cos(0)
467 EXPECT_NEAR(E1(0), 0.0, 1e-12); // cos(pi/2)
468}
469
470// ---------------------------------------------------------------------------
471// Fieldmap interaction
472// ---------------------------------------------------------------------------
473TEST_F(RFCavityTest, ApplyToReferenceParticle) {
474 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
475 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
476 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
477 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
478
479 // Should behave like apply() for reference particle
480 cav_->applyToReferenceParticle(R, P, 0.0, E, B);
481
482 EXPECT_DOUBLE_EQ(E(0), 1.0);
483}
484
485TEST_F(RFCavityTest, FieldmapOutOfBounds) {
486 // Make fake fieldmap return true
487 fmap_->setOutOfBounds(true);
488
489 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
490 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
491 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
492 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
493
494 bool out = cav_->apply(R, P, 0.0, E, B);
495
496 EXPECT_TRUE(out);
497}
ippl::Vector< T, Dim > Vector_t
DiffDirection
Definition Fieldmap.h:54
TEST_F(RFCavityTest, GetType)
Abstract base class for accelerator geometry classes.
Definition Geometry.h:42
void scale(double) override
Scale the field.
Euclid3D getTransform(double, double) const override
Get transform.
double getElementLength() const override
Get geometry length.
void setElementLength(double length) override
Set geometry length.
double getArcLength() const override
Get arc length.
Abstract base class for electromagnetic fields.
Definition EMField.h:171
Displacement and rotation in space.
Definition Euclid3D.h:67
void getFieldDimensions(double &zBegin, double &zEnd) const override
Get the longitudinal dimensions of the field.
bool getFieldDerivative(const Vector_t< double, 3 > &, Vector_t< double, 3 > &, Vector_t< double, 3 > &, const DiffDirection &) const override
Get the field derivative with respect to a direction.
void setFrequency(double) override
Set the frequency.
double getFrequency() const override
Get the frequency.
bool isInside(const Vector_t< double, 3 > &) const override
Check if a point is inside the field map.
void getInfo(Inform *) override
Print info about the field map.
bool getFieldstrength(const Vector_t< double, 3 > &, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) const override
Get the field strength at a given point.
void applyField(std::shared_ptr< ParticleContainer_t >, double=1.0) override
Apply the FM to all the particles.
void readMap() override
Pure virtual method to read the map data. Called by the public static readMap().
void getFieldDimensions(double &zBegin, double &zEnd, double &, double &, double &, double &) const override
Get the full 3D bounding box of the field.
void swap() override
Swap coordinates (implementation dependent).
void freeMap() override
Pure virtual method to free the map data.
void setOutOfBounds(bool v)
Abstract base class for all field maps. It acts as a factory for creating specific field map types ba...
Definition Fieldmap.h:62
std::unique_ptr< FakeFieldmap > fmap_
std::unique_ptr< TestRFCavity > cav_
void SetUp() override
Interface for standing wave cavities.
Definition RFCavity.h:34
Fieldmap * fieldmap_m
Definition RFCavity.h:219
double endField_m
Definition RFCavity.h:221
double scale_m
Definition RFCavity.h:208
double frequency_m
Definition RFCavity.h:212
double startField_m
Definition RFCavity.h:220
double phase_m
Definition RFCavity.h:210
double getFrequency() const override
Get RF frequency.
const BGeometryBase & getGeometry() const override
Get geometry.
DummyField field_
void setFrequencyInternal(double v)
void setPhase(double v)
void setFieldmap(Fieldmap *fmap)
void setStartField(double val)
void setEndField(double val)
const EMField & getField() const override
Return field.
void setScale(double v)
DummyGeometry geom_
void setFrequency(double v)
BGeometryBase & getGeometry() override
Get geometry.
double getPhase() const override
Get RF phase.
void setPhaseInternal(double v)
ElementBase * clone() const override
Return clone.
double getAmplitude() const override
Get RF amplitude.
void setAmplitude(double v)
EMField & getField() override
Return field.