OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
TestTravelingWave.cpp
Go to the documentation of this file.
1
54#include <gtest/gtest.h>
55
56#define private public
58#undef private
59
61#include "Fields/Fieldmap.h"
62
63#include <cmath>
64#include <memory>
65
66// ---------------------------------------------------------------------------
67// Fake fieldmap for deterministic tests
68// ---------------------------------------------------------------------------
69class FakeTWFieldmap : public Fieldmap {
70public:
71 FakeTWFieldmap() : Fieldmap("dummy"), outOfBounds_(false) {}
72
73 void setOutOfBounds(bool v) { outOfBounds_ = v; }
74
77 Vector_t<double, 3>& B) const override {
78 if (outOfBounds_) return true;
79
80 E = {1.0, 0.0, 0.0};
81 B = {0.0, 1.0, 0.0};
82 return false;
83 }
84
85 void getFieldDimensions(double& zBegin, double& zEnd) const override {
86 zBegin = 0.0;
87 zEnd = 2.0;
88 }
89
91 double& xIni, double& xFinal, double& yIni, double& yFinal, double& zIni,
92 double& zFinal) const override {
93 xIni = yIni = 0.0;
94 xFinal = yFinal = 0.0;
95 zIni = 0.0;
96 zFinal = 2.0;
97 }
98
99 bool isInside(const Vector_t<double, 3>&) const override { return !outOfBounds_; }
100
101 // --- required no-op implementations ---
102 void applyField(std::shared_ptr<ParticleContainer_t>, double = 1.0) override {}
105 const DiffDirection&) const override {
106 return false;
107 }
108
109 void swap() override {}
110 void getInfo(Inform*) override {}
111 double getFrequency() const override { return 1.0; }
112 void setFrequency(double) override {}
113 void readMap() override {}
114 void freeMap() override {}
115 void getOnaxisEz(std::vector<std::pair<double, double>>& F) override {
116 F.clear();
117 F.push_back({0.0, 1.0});
118 F.push_back({1.0, 1.0});
119 F.push_back({2.0, 1.0});
120 }
121
122private:
124};
125
126// ---------------------------------------------------------------------------
127// Dummy Geometry
128// ---------------------------------------------------------------------------
130public:
131 double getArcLength() const override { return 0.0; }
132 double getElementLength() const override { return length_m; }
133 void setElementLength(double length) override { length_m = length; }
134
135 Euclid3D getTransform(double, double) const override { return Euclid3D(); }
136
137private:
138 double length_m = 0.0;
139};
140
141// ---------------------------------------------------------------------------
142// Dummy Field
143// ---------------------------------------------------------------------------
144class DummyFieldTW : public EMField {
145public:
146 void scale(double) override {}
147};
148
149// ---------------------------------------------------------------------------
150// Minimal concrete TravelingWave
151// ---------------------------------------------------------------------------
153public:
155
156 double getAmplitude() const override { return amplitude_; }
157 double getFrequency() const override { return frequency_; }
158 double getPhase() const override { return phase_; }
159
160 ElementBase* clone() const override { return new TestTravelingWave(*this); }
161
163
164 BGeometryBase& getGeometry() override { return geom_; }
165 const BGeometryBase& getGeometry() const override { return geom_; }
166
167 EMField& getField() override { return field_; }
168 const EMField& getField() const override { return field_; }
169
170 void setAmplitude(double v) { amplitude_ = v; }
171 void setFrequency(double v) { frequency_ = v; }
172 void setPhase(double v) { phase_ = v; }
173
174 void setScale(double v) { scale_m = v; }
175 void setScaleError(double v) { scaleError_m = v; }
176 void setScaleCore(double v) { scaleCore_m = v; }
177 void setScaleCoreError(double v) { scaleCoreError_m = v; }
178
179 void setFrequencyInternal(double v) { frequency_m = v; }
180 void setPhaseInternal(double v) { phase_m = v; }
181 // void setPhaseErrorInternal(double v) { phaseError_m = v; }
182
183 void setFieldmap(Fieldmap* fmap) { fieldmap_m = fmap; }
184 void setStartField(double v) { startField_m = v; }
185 void setEndField(double v) { endField_m = v; }
186
187private:
188 double amplitude_ = 0.0;
189 double frequency_ = 0.0;
190 double phase_ = 0.0;
191
194};
195
196// ---------------------------------------------------------------------------
197// Fixture
198// ---------------------------------------------------------------------------
199class TravelingWaveTest : public ::testing::Test {
200protected:
201 void SetUp() override {
202 tw_ = std::make_unique<TestTravelingWave>();
203 fmap_ = std::make_unique<FakeTWFieldmap>();
204
205 tw_->setFieldmap(fmap_.get());
206
207 // Stable default TW geometry for tests
208 tw_->periodLength_m = 2.0;
209 tw_->cellLength_m = 1.0;
210 tw_->numCells_m = 3;
211 tw_->mode_m = 0.5;
212
213 tw_->setStartField(-1.0);
214 tw_->setEndField(3.0);
215 tw_->startCoreField_m = 1.0;
216 tw_->startExitField_m = 3.0;
217 tw_->mappedStartExitField_m = 1.0;
218
219 tw_->setTestElementLength(4.0);
220
221 // Stable RF defaults
222 tw_->setScale(1.0);
223 tw_->setScaleError(0.0);
224 tw_->setScaleCore(1.0);
225 tw_->setScaleCoreError(0.0);
226 tw_->setFrequencyInternal(1.0);
227 tw_->setPhaseInternal(0.0);
228 tw_->setPhaseError(0.0);
229
230 // Set internal TW phases explicitly
231 tw_->phaseCore1_m = 0.0;
232 tw_->phaseCore2_m = 0.0;
233 tw_->phaseExit_m = 0.0;
234 }
235
236 std::unique_ptr<TestTravelingWave> tw_;
237 std::unique_ptr<FakeTWFieldmap> fmap_;
238};
239
240// ---------------------------------------------------------------------------
241// Basic API
242// ---------------------------------------------------------------------------
243TEST_F(TravelingWaveTest, GetType) { EXPECT_EQ(tw_->getType(), ElementType::TRAVELINGWAVE); }
244
245TEST_F(TravelingWaveTest, Bends) { EXPECT_FALSE(tw_->bends()); }
246
247TEST_F(TravelingWaveTest, GetSetAmplitudeFrequencyPhase) {
248 tw_->setAmplitude(5.0);
249 tw_->setFrequency(2.0);
250 tw_->setPhase(0.5);
251
252 EXPECT_DOUBLE_EQ(tw_->getAmplitude(), 5.0);
253 EXPECT_DOUBLE_EQ(tw_->getFrequency(), 2.0);
254 EXPECT_DOUBLE_EQ(tw_->getPhase(), 0.5);
255}
256
257// ---------------------------------------------------------------------------
258// Geometry
259// ---------------------------------------------------------------------------
260TEST_F(TravelingWaveTest, GetDimensions) {
261 double zBegin = 0.0, zEnd = 0.0;
262 tw_->getFieldExtend(zBegin, zEnd);
263
264 EXPECT_DOUBLE_EQ(zBegin, -1.0); // -0.5 * periodLength
265 EXPECT_DOUBLE_EQ(zEnd, 3.0); // zBegin + elementLength
266}
267
268TEST_F(TravelingWaveTest, GetElementDimensions) {
269 double begin = 0.0, end = 0.0;
270 tw_->getElementDimensions(begin, end);
271
272 EXPECT_DOUBLE_EQ(begin, 0.0);
273 EXPECT_DOUBLE_EQ(end, 4.0);
274}
275
276TEST_F(TravelingWaveTest, EdgeTransforms) {
277 auto beg = tw_->getEdgeToBegin();
278 auto end = tw_->getEdgeToEnd();
279
280 EXPECT_DOUBLE_EQ(beg.getOrigin()(2), 0.0);
281 EXPECT_DOUBLE_EQ(end.getOrigin()(2), 4.0);
282}
283
284// ---------------------------------------------------------------------------
285// setPhasem updates internal TW phases
286// ---------------------------------------------------------------------------
287TEST_F(TravelingWaveTest, SetPhasemUpdatesInternalPhases) {
288 tw_->mode_m = 0.5;
289 tw_->numCells_m = 3;
290
291 tw_->setPhasem(0.2);
292
293 EXPECT_NEAR(tw_->getPhasem(), 0.2, 1e-12);
294 EXPECT_NEAR(tw_->phaseCore1_m, 0.2 + Physics::pi * 0.5 / 2.0, 1e-12);
295 EXPECT_NEAR(tw_->phaseCore2_m, 0.2 + Physics::pi * 0.5 * 1.5, 1e-12);
296
297 const double expectedExit = 0.2 - Physics::two_pi * ((3 - 1) * 0.5 - std::floor((3 - 1) * 0.5));
298 EXPECT_NEAR(tw_->phaseExit_m, expectedExit, 1e-12);
299}
300
301// ---------------------------------------------------------------------------
302// apply(): entry/core/exit/outside
303// ---------------------------------------------------------------------------
304TEST_F(TravelingWaveTest, ApplyEntryRegion) {
305 // Entry: tmpR(2) = R(2) + 1.0 < startCoreField_m (=1.0)
306 Vector_t<double, 3> R = {0.0, 0.0, -0.5};
307 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
308 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
309 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
310
311 tw_->apply(R, P, 0.0, E, B);
312
313 // entry scale = 1, phase = 0 => cos = 1, sin = 0
314 EXPECT_DOUBLE_EQ(E(0), 1.0);
315 EXPECT_DOUBLE_EQ(E(1), 0.0);
316 EXPECT_DOUBLE_EQ(E(2), 0.0);
317
318 EXPECT_DOUBLE_EQ(B(0), 0.0);
319 EXPECT_DOUBLE_EQ(B(1), 0.0);
320 EXPECT_DOUBLE_EQ(B(2), 0.0);
321}
322
323TEST_F(TravelingWaveTest, ApplyCoreRegionAccumulatesTwoContributions) {
324 // Core: tmpR(2) = R(2) + 1.0 in [1.0, 3.0)
325 Vector_t<double, 3> R = {0.0, 0.0, 0.5};
326 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
327 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
328 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
329
330 tw_->setScaleCore(1.0);
331 tw_->phaseCore1_m = 0.0;
332 tw_->phaseCore2_m = 0.0;
333
334 tw_->apply(R, P, 0.0, E, B);
335
336 // Fake fieldmap returns E=(1,0,0) each time, applied twice
337 EXPECT_DOUBLE_EQ(E(0), 2.0);
338 EXPECT_DOUBLE_EQ(E(1), 0.0);
339 EXPECT_DOUBLE_EQ(E(2), 0.0);
340
341 EXPECT_DOUBLE_EQ(B(0), 0.0);
342 EXPECT_DOUBLE_EQ(B(1), 0.0);
343 EXPECT_DOUBLE_EQ(B(2), 0.0);
344}
345
346TEST_F(TravelingWaveTest, ApplyExitRegion) {
347 // Exit: tmpR(2) = R(2) + 1.0 >= startExitField_m (=3.0)
348 Vector_t<double, 3> R = {0.0, 0.0, 2.2};
349 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
350 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
351 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
352
353 tw_->phaseExit_m = 0.0;
354
355 tw_->apply(R, P, 0.0, E, B);
356
357 EXPECT_DOUBLE_EQ(E(0), 1.0);
358 EXPECT_DOUBLE_EQ(E(1), 0.0);
359 EXPECT_DOUBLE_EQ(E(2), 0.0);
360}
361
362TEST_F(TravelingWaveTest, ApplyOutsideBefore) {
363 Vector_t<double, 3> R = {0.0, 0.0, -1.1};
364 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
365 Vector_t<double, 3> E = {1.0, 2.0, 3.0};
366 Vector_t<double, 3> B = {4.0, 5.0, 6.0};
367
368 tw_->apply(R, P, 0.0, E, B);
369
370 EXPECT_DOUBLE_EQ(E(0), 1.0);
371 EXPECT_DOUBLE_EQ(E(1), 2.0);
372 EXPECT_DOUBLE_EQ(E(2), 3.0);
373 EXPECT_DOUBLE_EQ(B(0), 4.0);
374 EXPECT_DOUBLE_EQ(B(1), 5.0);
375 EXPECT_DOUBLE_EQ(B(2), 6.0);
376}
377
378TEST_F(TravelingWaveTest, ApplyOutsideAfter) {
379 Vector_t<double, 3> R = {0.0, 0.0, 3.0};
380 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
381 Vector_t<double, 3> E = {1.0, 2.0, 3.0};
382 Vector_t<double, 3> B = {4.0, 5.0, 6.0};
383
384 tw_->apply(R, P, 0.0, E, B);
385
386 EXPECT_DOUBLE_EQ(E(0), 1.0);
387 EXPECT_DOUBLE_EQ(E(1), 2.0);
388 EXPECT_DOUBLE_EQ(E(2), 3.0);
389 EXPECT_DOUBLE_EQ(B(0), 4.0);
390 EXPECT_DOUBLE_EQ(B(1), 5.0);
391 EXPECT_DOUBLE_EQ(B(2), 6.0);
392}
393
394// ---------------------------------------------------------------------------
395// RF phase behavior
396// ---------------------------------------------------------------------------
397TEST_F(TravelingWaveTest, ApplyPhasePiOverTwoGivesMagneticField) {
398 Vector_t<double, 3> R = {0.0, 0.0, -0.5}; // entry region
399 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
400 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
401 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
402
403 tw_->setPhasem(Physics::pi / 2.0);
404 tw_->phaseCore1_m = Physics::pi / 2.0;
405 tw_->phaseCore2_m = Physics::pi / 2.0;
406 tw_->phaseExit_m = Physics::pi / 2.0;
407
408 tw_->apply(R, P, 0.0, E, B);
409
410 EXPECT_NEAR(E(0), 0.0, 1e-12);
411 EXPECT_DOUBLE_EQ(B(1), -1.0);
412}
413
414// ---------------------------------------------------------------------------
415// applyToReferenceParticle
416// ---------------------------------------------------------------------------
417TEST_F(TravelingWaveTest, ApplyToReferenceParticleEntry) {
418 Vector_t<double, 3> R = {0.0, 0.0, -0.5};
419 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
420 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
421 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
422
423 tw_->applyToReferenceParticle(R, P, 0.0, E, B);
424
425 EXPECT_DOUBLE_EQ(E(0), 1.0);
426}
427
428// ---------------------------------------------------------------------------
429// Fieldmap interaction / edge cases
430// ---------------------------------------------------------------------------
431TEST_F(TravelingWaveTest, FieldmapOutOfBounds) {
432 fmap_->setOutOfBounds(true);
433
434 Vector_t<double, 3> R = {0.0, 0.0, -0.5};
435 Vector_t<double, 3> P = {0.0, 0.0, 1.0};
436 Vector_t<double, 3> E = {0.0, 0.0, 0.0};
437 Vector_t<double, 3> B = {0.0, 0.0, 0.0};
438
439 bool out = tw_->apply(R, P, 0.0, E, B);
440 EXPECT_TRUE(out);
441}
442
444 EXPECT_TRUE(tw_->isInside({0.0, 0.0, 0.0}));
445 EXPECT_TRUE(tw_->isInside({0.0, 0.0, 2.5}));
446 EXPECT_FALSE(tw_->isInside({0.0, 0.0, -1.1}));
447 EXPECT_FALSE(tw_->isInside({0.0, 0.0, 3.0}));
448}
ippl::Vector< T, Dim > Vector_t
DiffDirection
Definition Fieldmap.h:54
TEST_F(TravelingWaveTest, GetType)
Abstract base class for accelerator geometry classes.
Definition Geometry.h:42
void scale(double) override
Scale the field.
double getArcLength() const override
Get arc length.
double getElementLength() const override
Get geometry length.
Euclid3D getTransform(double, double) const override
Get transform.
void setElementLength(double length) override
Set geometry length.
Abstract base class for electromagnetic fields.
Definition EMField.h:171
Displacement and rotation in space.
Definition Euclid3D.h:67
void getFieldDimensions(double &xIni, double &xFinal, double &yIni, double &yFinal, double &zIni, double &zFinal) const override
Get the full 3D bounding box of the field.
void getInfo(Inform *) override
Print info about the field map.
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.
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 getOnaxisEz(std::vector< std::pair< double, double > > &F) override
void freeMap() override
Pure virtual method to free the map data.
void setFrequency(double) override
Set the frequency.
void setOutOfBounds(bool v)
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) const override
Get the longitudinal dimensions of the field.
void swap() override
Swap coordinates (implementation dependent).
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.
Abstract base class for all field maps. It acts as a factory for creating specific field map types ba...
Definition Fieldmap.h:62
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 scaleError_m
Definition RFCavity.h:209
double phase_m
Definition RFCavity.h:210
double getFrequency() const override
Get RF frequency.
BGeometryBase & getGeometry() override
Get geometry.
ElementBase * clone() const override
Return clone.
void setFrequencyInternal(double v)
void setScaleCoreError(double v)
void setScaleCore(double v)
const BGeometryBase & getGeometry() const override
Get geometry.
double getPhase() const override
Get RF phase.
const EMField & getField() const override
Return field.
void setFieldmap(Fieldmap *fmap)
void setTestElementLength(double v)
void setAmplitude(double v)
void setEndField(double v)
double getAmplitude() const override
Get RF amplitude.
void setPhaseInternal(double v)
void setStartField(double v)
void setFrequency(double v)
void setScaleError(double v)
EMField & getField() override
Return field.
std::unique_ptr< FakeTWFieldmap > fmap_
std::unique_ptr< TestTravelingWave > tw_
Interface for traveling wave cavities.
double scaleCoreError_m
constexpr double two_pi
The value of.
Definition Physics.h:40
constexpr double pi
The value of.
Definition Physics.h:36