Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
potentialfield2d_tests.cpp
Go to the documentation of this file.
1/**
2 * @file potentialfield2d_tests.cpp
3 * @brief Implements regression and invariant tests for potentialfield2d tests.
4 * @ingroup qpe_tests
5 *
6 * Source: @c tests/potentialfield2d_tests.cpp. This file is part of Quantum Phenomena Explorer (QPE),
7 * maintained by Officina Turini. See LICENSE_IT.txt / LICENSE.txt for the
8 * QPE freeware source-available terms and THIRD_PARTY_NOTICES.txt for
9 * third-party components.
10 */
11
13
16
17#include <cmath>
18#include <stdexcept>
19#include <vector>
20
21namespace qpe {
22namespace tests {
23namespace {
24
25/**
26 * @brief Performs fail.
27 * @param errorMessage The error message value used by the operation.
28 * @param message The message value used by the operation.
29 */
30bool fail(std::string &errorMessage, const char *message)
31{
32 errorMessage = message;
33 return false;
34}
35
36std::size_t nearestIndexX(const PotentialField2D &p, double x)
37{
38 std::size_t best = 0;
39 double bestD = 1.0e30;
40 for (std::size_t i = 0; i < p.width(); ++i) {
41 const double d = std::abs(p.xCoordinate(i) - x);
42 if (d < bestD) {
43 bestD = d;
44 best = i;
45 }
46 }
47 return best;
48}
49
50std::size_t nearestIndexY(const PotentialField2D &p, double y)
51{
52 std::size_t best = 0;
53 double bestD = 1.0e30;
54 for (std::size_t i = 0; i < p.height(); ++i) {
55 const double d = std::abs(p.yCoordinate(i) - y);
56 if (d < bestD) {
57 bestD = d;
58 best = i;
59 }
60 }
61 return best;
62}
63
64/**
65 * @brief Samples is.
66 * @param p The p value used by the operation.
67 * @param x X coordinate/value.
68 * @param y Y coordinate/value.
69 * @param expected The expected value used by the operation.
70 */
71bool sampleIs(const PotentialField2D &p, double x, double y, float expected)
72{
73 return std::abs(p(nearestIndexX(p, x), nearestIndexY(p, y)) - expected) < 1.0e-6f;
74}
75
76} // namespace
77
78/**
79 * @brief Runs potential field2 d tests.
80 * @param errorMessage The error message value used by the operation.
81 */
82bool runPotentialField2DTests(std::string &errorMessage)
83{
84 errorMessage.clear();
85
86 try {
87 bool rejected = false;
88 try {
89 PotentialField2D invalid(8, 8, 0.0f, 1.0f);
90 } catch (const std::invalid_argument &) {
91 rejected = true;
92 }
93 if (!rejected) {
94 return fail(errorMessage, "invalid spatial step was not rejected");
95 }
96
97 PotentialField2D potential(8, 4, 0.2f, 0.3f);
98 if (potential.width() != 8 || potential.height() != 4 ||
99 potential.size() != 32 || potential.empty()) {
100 return fail(errorMessage, "potential dimensions are incorrect");
101 }
102 if (potential.minimum() != 0.0f || potential.maximum() != 0.0f) {
103 return fail(errorMessage, "new potential is not zero initialized");
104 }
105
106 const std::uint64_t revision0 = potential.revision();
107 potential.set(2, 1, 4.5f);
108 if (std::abs(potential(2, 1) - 4.5f) > 1.0e-6f ||
109 potential.revision() == revision0) {
110 return fail(errorMessage, "set/revision failed");
111 }
112 if (potential.maximum() != 4.5f) {
113 return fail(errorMessage, "potential maximum is incorrect");
114 }
115
116 potential.fill(-2.0f);
117 if (potential.minimum() != -2.0f || potential.maximum() != -2.0f) {
118 return fail(errorMessage, "fill/minimum/maximum failed");
119 }
120
121 potential.clear();
122 if (potential.minimum() != 0.0f || potential.maximum() != 0.0f) {
123 return fail(errorMessage, "clear failed");
124 }
125
126 bool boundsRejected = false;
127 try {
128 potential.setAt(99, 0, 1.0f);
129 } catch (const std::out_of_range &) {
130 boundsRejected = true;
131 }
132 if (!boundsRejected) {
133 return fail(errorMessage, "out-of-range access was not rejected");
134 }
135
136 ComplexField2D matching(8, 4, 0.2f, 0.3f);
137 ComplexField2D different(8, 4, 0.25f, 0.3f);
138 if (!potential.matchesGrid(matching) || potential.matchesGrid(different)) {
139 return fail(errorMessage, "grid compatibility check failed");
140 }
141
142 // Geometry tests use an odd grid so (0,0) is an exact sample.
143 PotentialField2D g(101, 101, 0.1f, 0.1f);
144 const std::size_t cx = nearestIndexX(g, 0.0);
145 const std::size_t cy = nearestIndexY(g, 0.0);
146 if (std::abs(g.xCoordinate(cx)) > 1.0e-9 || std::abs(g.yCoordinate(cy)) > 1.0e-9) {
147 return fail(errorMessage, "physical coordinate mapping is incorrect");
148 }
149
150 std::uint64_t r = g.revision();
151 g.addRectangle(0.0f, 0.0f, 2.0f, 1.0f, 3.0f);
152 if (g.revision() != r + 1 || !sampleIs(g, 0.0, 0.0, 3.0f) ||
153 !sampleIs(g, 0.9, 0.4, 3.0f) || !sampleIs(g, 1.4, 0.0, 0.0f)) {
154 return fail(errorMessage, "rectangle primitive failed");
155 }
156
157 g.clear();
158 r = g.revision();
159 g.addCircle(0.0f, 0.0f, 1.0f, 4.0f);
160 if (g.revision() != r + 1 || !sampleIs(g, 0.0, 0.0, 4.0f) ||
161 !sampleIs(g, 0.7, 0.7, 4.0f) || !sampleIs(g, 1.2, 0.0, 0.0f)) {
162 return fail(errorMessage, "circle primitive failed");
163 }
164
165 g.clear();
166 g.addBarrier(-2.0f, -2.0f, 2.0f, 2.0f, 0.4f, 5.0f);
167 if (!sampleIs(g, 0.0, 0.0, 5.0f) || !sampleIs(g, 0.0, 1.0, 0.0f)) {
168 return fail(errorMessage, "barrier primitive failed");
169 }
170
171 g.clear();
172 const std::vector<PotentialPoint2D> triangle = {
173 {-1.0f, -1.0f}, {1.0f, -1.0f}, {0.0f, 1.0f}
174 };
175 g.addPolygon(triangle, 6.0f);
176 if (!sampleIs(g, 0.0, 0.0, 6.0f) || !sampleIs(g, 1.5, 0.0, 0.0f)) {
177 return fail(errorMessage, "polygon primitive failed");
178 }
179
180 g.clear();
181 g.addSingleSlit(0.0f, 0.4f, 0.0f, 1.0f, 7.0f);
182 if (!sampleIs(g, 0.0, 0.0, 0.0f) || !sampleIs(g, 0.0, 1.0, 7.0f) ||
183 !sampleIs(g, 1.0, 1.0, 0.0f)) {
184 return fail(errorMessage, "single slit primitive failed");
185 }
186
187 g.clear();
188 g.addDoubleSlit(0.0f, 0.4f, 0.0f, 2.0f, 0.6f, 8.0f);
189 if (!sampleIs(g, 0.0, -1.0, 0.0f) || !sampleIs(g, 0.0, 1.0, 0.0f) ||
190 !sampleIs(g, 0.0, 0.0, 8.0f) || !sampleIs(g, 0.0, 2.0, 8.0f)) {
191 return fail(errorMessage, "double slit primitive failed");
192 }
193
194 g.clear();
195 g.addGaussian(0.0f, 0.0f, 1.0f, 2.0f, -4.0f);
196 if (!sampleIs(g, 0.0, 0.0, -4.0f) ||
197 std::abs(g(nearestIndexX(g, 1.0), nearestIndexY(g, 0.0)) -
198 static_cast<float>(-4.0 * std::exp(-0.5))) > 2.0e-3f) {
199 return fail(errorMessage, "Gaussian potential failed");
200 }
201
202 g.clear();
203 g.addHarmonic(0.0f, 0.0f, 1.0f, 2.0f, 4.0f);
204 if (!sampleIs(g, 0.0, 0.0, 1.0f) ||
205 std::abs(g(nearestIndexX(g, 1.0), nearestIndexY(g, 0.0)) - 2.0f) > 1.0e-5f ||
206 std::abs(g(nearestIndexX(g, 0.0), nearestIndexY(g, 1.0)) - 3.0f) > 1.0e-5f) {
207 return fail(errorMessage, "harmonic potential failed");
208 }
209
210 g.clear();
211 g.addLinear(0.0f, 0.0f, 0.5f, 2.0f, -1.0f);
212 if (!sampleIs(g, 0.0, 0.0, 0.5f) ||
213 std::abs(g(nearestIndexX(g, 1.0), nearestIndexY(g, 1.0)) - 1.5f) > 1.0e-5f) {
214 return fail(errorMessage, "linear potential failed");
215 }
216
217 g.clear();
218 g.addSoftenedRadial(0.0f, 0.0f, -3.0f, 0.5f);
219 if (std::abs(g(nearestIndexX(g, 0.0), nearestIndexY(g, 0.0)) + 6.0f) > 1.0e-5f ||
220 !(g(nearestIndexX(g, 2.0), nearestIndexY(g, 0.0)) > -2.0f)) {
221 return fail(errorMessage, "softened radial potential failed");
222 }
223
224 bool smoothRejected = false;
225 try {
226 g.addGaussian(0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
227 } catch (const std::invalid_argument &) {
228 smoothRejected = true;
229 }
230 if (!smoothRejected) {
231 return fail(errorMessage, "invalid smooth-potential dimensions were not rejected");
232 }
233
234 bool geometryRejected = false;
235 try {
236 g.addCircle(0.0f, 0.0f, -1.0f, 1.0f);
237 } catch (const std::invalid_argument &) {
238 geometryRejected = true;
239 }
240 if (!geometryRejected) {
241 return fail(errorMessage, "invalid geometry dimensions were not rejected");
242 }
243 } catch (const std::exception &e) {
244 errorMessage = e.what();
245 return false;
246 }
247
248 return true;
249}
250
251} // namespace tests
252} // namespace qpe
Owning Cartesian grid of complex scalar samples.
Implements the Potential Field2D component.
void addHarmonic(float centerX, float centerY, Value offset, float curvatureX, float curvatureY)
Adds harmonic.
std::size_t height() const noexcept
Returns height.
void addLinear(float centerX, float centerY, Value offset, float slopeX, float slopeY)
Adds linear.
void clear() noexcept
Performs clear.
void fill(Value value) noexcept
Performs fill.
std::uint64_t revision() const noexcept
Performs revision.
void addPolygon(const std::vector< PotentialPoint2D > &vertices, Value value)
Adds polygon.
void addRectangle(float centerX, float centerY, float width, float height, Value value)
Adds rectangle.
double xCoordinate(std::size_t x) const noexcept
Performs x coordinate.
Value minimum() const noexcept
Performs minimum.
std::size_t size() const noexcept
Returns size.
bool matchesGrid(const ComplexField2D &field) const noexcept
Performs matches grid.
void setAt(std::size_t x, std::size_t y, Value value)
Sets at.
void addCircle(float centerX, float centerY, float radius, Value value)
Adds circle.
bool empty() const noexcept
Performs empty.
void addGaussian(float centerX, float centerY, float sigmaX, float sigmaY, Value amplitude)
Adds gaussian.
std::size_t width() const noexcept
Returns width.
double yCoordinate(std::size_t y) const noexcept
Performs y coordinate.
void addBarrier(float x1, float y1, float x2, float y2, float thickness, Value value)
Adds barrier.
void set(std::size_t x, std::size_t y, Value value) noexcept
Performs set.
void addSoftenedRadial(float centerX, float centerY, Value coupling, float softening)
Adds softened radial.
void addDoubleSlit(float centerX, float barrierWidth, float slitCenterY, float slitSeparation, float slitHeight, Value value)
Adds double slit.
Value maximum() const noexcept
Performs maximum.
void addSingleSlit(float centerX, float barrierWidth, float slitCenterY, float slitHeight, Value value)
Adds single slit.
Declares the complex scalar field container representing two-dimensional wave functions.
std::size_t nearestIndexX(const PotentialField2D &p, double x)
bool sampleIs(const PotentialField2D &p, double x, double y, float expected)
Samples is.
std::size_t nearestIndexY(const PotentialField2D &p, double y)
bool runPotentialField2DTests(std::string &errorMessage)
Runs potential field2 d tests.
Declares the potentialfield2d physics/numerical component used by QPE experiments.
Declares regression and invariant tests for potentialfield2d tests.