Move M_PI definition to math/units.h
[alexxy/gromacs.git] / src / gromacs / simd / tests / scalar_math.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
5  * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
6  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7  * and including many others, as listed in the AUTHORS file in the
8  * top-level source directory and at http://www.gromacs.org.
9  *
10  * GROMACS is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1
13  * of the License, or (at your option) any later version.
14  *
15  * GROMACS is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with GROMACS; if not, see
22  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24  *
25  * If you want to redistribute modifications to GROMACS, please
26  * consider that scientific software is very special. Version
27  * control is crucial - bugs must be traceable. We will be happy to
28  * consider code for inclusion in the official distribution, but
29  * derived work must not be called official GROMACS. Details are found
30  * in the README & COPYING files - if they are missing, get the
31  * official version at http://www.gromacs.org.
32  *
33  * To help us fund GROMACS development, we humbly ask that you cite
34  * the research papers on the package. Check out http://www.gromacs.org.
35  */
36 #include "gmxpre.h"
37
38 #include <cmath>
39
40 #include <gtest/gtest.h>
41
42 #include "gromacs/math/units.h"
43 #include "gromacs/math/utilities.h"
44 #include "gromacs/simd/simd.h"
45 #include "gromacs/utility/basedefinitions.h"
46
47 #include "testutils/testasserts.h"
48
49 #include "data.h"
50
51 namespace gmx
52 {
53 namespace test
54 {
55
56 namespace
57 {
58
59 /*! \cond internal */
60 /*! \addtogroup module_simd */
61 /*! \{ */
62
63 // Since these functions are mostly wrappers for similar standard library
64 // functions, we typically just test 1-2 values to make sure we call the right
65 // function.
66
67 /******************************************
68  * Default floating-point precision tests *
69  ******************************************/
70
71 TEST(SimdScalarMathTest, copysign)
72 {
73     EXPECT_EQ(real(-c1), copysign(real(c1), real(-c2)));
74     EXPECT_EQ(real(c2), copysign(real(c2), real(c3)));
75 }
76
77 TEST(SimdScalarMathTest, invsqrtPair)
78 {
79     real x0 = c1;
80     real x1 = c2;
81
82     real out0, out1;
83
84     invsqrtPair(x0, x1, &out0, &out1);
85
86     EXPECT_EQ(invsqrt(x0), out0);
87     EXPECT_EQ(invsqrt(x1), out1);
88 }
89
90 TEST(SimdScalarMathTest, inv)
91 {
92     real x0 = c0;
93
94     EXPECT_EQ(real(1.0) / x0, inv(x0));
95 }
96
97 TEST(SimdScalarMathTest, maskzInvsqrt)
98 {
99     real x0 = c0;
100
101     EXPECT_EQ(invsqrt(x0), maskzInvsqrt(x0, true));
102     EXPECT_EQ(real(0), maskzInvsqrt(x0, false));
103 }
104
105 TEST(SimdScalarMathTest, log)
106 {
107     real x0 = c0;
108
109     EXPECT_EQ(std::log(x0), log(x0));
110 }
111
112 TEST(SimdScalarMathTest, exp2)
113 {
114     real x0 = c0;
115
116     EXPECT_EQ(std::exp2(x0), exp2(x0));
117 }
118
119 TEST(SimdScalarMathTest, exp)
120 {
121     real x0 = c0;
122
123     EXPECT_EQ(std::exp(x0), exp(x0));
124 }
125
126 TEST(SimdScalarMathTest, erf)
127 {
128     real x0 = c0;
129
130     EXPECT_EQ(std::erf(x0), erf(x0));
131 }
132
133 TEST(SimdScalarMathTest, erfc)
134 {
135     real x0 = c0;
136
137     EXPECT_EQ(std::erfc(x0), erfc(x0));
138 }
139
140 TEST(SimdScalarMathTest, sincos)
141 {
142     real x0 = c0;
143     real s, c;
144
145     sincos(x0, &s, &c);
146
147     EXPECT_EQ(std::sin(x0), s);
148     EXPECT_EQ(std::cos(x0), c);
149 }
150
151 TEST(SimdScalarMathTest, sin)
152 {
153     real x0 = c0;
154
155     EXPECT_EQ(std::sin(x0), sin(x0));
156 }
157
158 TEST(SimdScalarMathTest, cos)
159 {
160     real x0 = c0;
161
162     EXPECT_EQ(std::cos(x0), cos(x0));
163 }
164
165 TEST(SimdScalarMathTest, tan)
166 {
167     real x0 = c0;
168
169     EXPECT_EQ(std::tan(x0), tan(x0));
170 }
171
172
173 TEST(SimdScalarMathTest, asin)
174 {
175     real x0 = c0;
176
177     EXPECT_EQ(std::asin(x0), asin(x0));
178 }
179
180 TEST(SimdScalarMathTest, acos)
181 {
182     real x0 = c0;
183
184     EXPECT_EQ(std::acos(x0), acos(x0));
185 }
186
187 TEST(SimdScalarMathTest, atan)
188 {
189     real x0 = c0;
190
191     EXPECT_EQ(std::atan(x0), atan(x0));
192 }
193
194 TEST(SimdScalarMathTest, atan2)
195 {
196     real x = c0;
197     real y = std::sqrt(c0);
198
199
200     EXPECT_EQ(std::atan2(y, x), atan2(y, x));
201 }
202
203 TEST(SimdScalarMathTest, pmeForceCorrection)
204 {
205     real z2 = c0;
206
207     // Calculate reference value for z2!=0
208     real z   = std::sqrt(z2);
209     real ref = 2.0 * std::exp(-z2) / (std::sqrt(M_PI) * z2) - std::erf(z) / (z2 * z);
210
211     // Pme correction only needs to be ~1e-6 accuracy single, 1e-10 double
212 #if GMX_DOUBLE
213     FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-10));
214 #else
215     FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
216 #endif
217
218     EXPECT_REAL_EQ_TOL(ref, pmeForceCorrection(z2), tolerance);
219 }
220
221 TEST(SimdScalarMathTest, pmePotentialCorrection)
222 {
223     real z2 = c0;
224
225     // Calculate reference value for z2!=0
226     real z   = std::sqrt(z2);
227     real ref = std::erf(z) / z;
228
229     // Pme correction only needs to be ~1e-6 accuracy single, 1e-10 double
230 #if GMX_DOUBLE
231     FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-10));
232 #else
233     FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
234 #endif
235
236     EXPECT_REAL_EQ_TOL(ref, pmePotentialCorrection(z2), tolerance);
237 }
238
239 /*******************************************
240  * Double precision, single accuracy tests *
241  *******************************************/
242
243 TEST(SimdScalarMathTest, invsqrtPairSingleAccuracy)
244 {
245     double x0 = c1;
246     double x1 = c2;
247
248     double out0, out1;
249
250     invsqrtPairSingleAccuracy(x0, x1, &out0, &out1);
251
252     EXPECT_EQ(invsqrt(static_cast<float>(x0)), static_cast<float>(out0));
253     EXPECT_EQ(invsqrt(static_cast<float>(x1)), static_cast<float>(out1));
254 }
255
256 TEST(SimdScalarMathTest, invSingleAccuracy)
257 {
258     double x0 = c1;
259
260     EXPECT_EQ(1.0F / static_cast<float>(x0), static_cast<float>(invSingleAccuracy(x0)));
261 }
262
263 TEST(SimdScalarMathTest, maskzInvsqrtSingleAccuracy)
264 {
265     double x0 = c1;
266
267     EXPECT_EQ(invsqrt(static_cast<float>(x0)), static_cast<float>(maskzInvsqrtSingleAccuracy(x0, true)));
268     EXPECT_EQ(0.0F, static_cast<float>(maskzInvsqrtSingleAccuracy(x0, false)));
269 }
270
271 TEST(SimdScalarMathTest, logSingleAccuracy)
272 {
273     double x0 = c1;
274
275     EXPECT_EQ(std::log(static_cast<float>(x0)), static_cast<float>(logSingleAccuracy(x0)));
276 }
277
278 TEST(SimdScalarMathTest, exp2SingleAccuracy)
279 {
280     double x0 = c1;
281
282     EXPECT_EQ(std::exp2(static_cast<float>(x0)), static_cast<float>(exp2SingleAccuracy(x0)));
283 }
284
285 TEST(SimdScalarMathTest, expSingleAccuracy)
286 {
287     double x0 = c1;
288
289     EXPECT_EQ(std::exp(static_cast<float>(x0)), static_cast<float>(expSingleAccuracy(x0)));
290 }
291
292 TEST(SimdScalarMathTest, erfSingleAccuracy)
293 {
294     double x0 = c0;
295
296     EXPECT_EQ(std::erf(static_cast<float>(x0)), static_cast<float>(erfSingleAccuracy(x0)));
297 }
298
299 TEST(SimdScalarMathTest, erfcSingleAccuracy)
300 {
301     double x0 = c0;
302
303     EXPECT_EQ(std::erfc(static_cast<float>(x0)), static_cast<float>(erfcSingleAccuracy(x0)));
304 }
305
306 TEST(SimdScalarMathTest, sincosSingleAccuracy)
307 {
308     double x0 = c0;
309     double s, c;
310
311     sincosSingleAccuracy(x0, &s, &c);
312
313     EXPECT_EQ(std::sin(static_cast<float>(x0)), static_cast<float>(s));
314     EXPECT_EQ(std::cos(static_cast<float>(x0)), static_cast<float>(c));
315 }
316
317 TEST(SimdScalarMathTest, sinSingleAccuracy)
318 {
319     double x0 = c0;
320
321     EXPECT_EQ(std::sin(static_cast<float>(x0)), static_cast<float>(sinSingleAccuracy(x0)));
322 }
323
324 TEST(SimdScalarMathTest, cosSingleAccuracy)
325 {
326     double x0 = c0;
327
328     EXPECT_EQ(std::cos(static_cast<float>(x0)), static_cast<float>(cosSingleAccuracy(x0)));
329 }
330
331 TEST(SimdScalarMathTest, tanSingleAccuracy)
332 {
333     double x0 = c0;
334
335     EXPECT_EQ(std::tan(static_cast<float>(x0)), static_cast<float>(tanSingleAccuracy(x0)));
336 }
337
338
339 TEST(SimdScalarMathTest, asinSingleAccuracy)
340 {
341     double x0 = c0;
342
343     EXPECT_EQ(std::asin(static_cast<float>(x0)), static_cast<float>(asinSingleAccuracy(x0)));
344 }
345
346 TEST(SimdScalarMathTest, acosSingleAccuracy)
347 {
348     double x0 = c0;
349
350     EXPECT_EQ(std::acos(static_cast<float>(x0)), static_cast<float>(acosSingleAccuracy(x0)));
351 }
352
353 TEST(SimdScalarMathTest, atanSingleAccuracy)
354 {
355     double x0 = c0;
356
357     EXPECT_EQ(std::atan(static_cast<float>(x0)), static_cast<float>(atanSingleAccuracy(x0)));
358 }
359
360 TEST(SimdScalarMathTest, atan2SingleAccuracy)
361 {
362     double x = c0;
363     double y = std::sqrt(c0);
364
365
366     EXPECT_EQ(std::atan2(static_cast<float>(y), static_cast<float>(x)),
367               static_cast<float>(atan2SingleAccuracy(y, x)));
368 }
369
370 TEST(SimdScalarMathTest, pmeForceCorrectionSingleAccuracy)
371 {
372     double z2 = c0;
373
374     // Calculate reference value for z2!=0 in single precision
375     float z   = std::sqrt(static_cast<float>(z2));
376     float ref = 2.0 * std::exp(static_cast<float>(-z2)) / (std::sqrt(static_cast<float>(M_PI)) * z2)
377                 - std::erf(z) / (z2 * z);
378
379     // Pme correction only needs to be ~1e-6 accuracy single
380     FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
381
382     EXPECT_REAL_EQ_TOL(ref, static_cast<float>(pmeForceCorrectionSingleAccuracy(z2)), tolerance);
383 }
384
385 TEST(SimdScalarMathTest, pmePotentialCorrectionSingleAccuracy)
386 {
387     double z2 = c0;
388
389     // Calculate reference value for z2!=0 in single precision
390     float z   = std::sqrt(static_cast<float>(z2));
391     float ref = std::erf(z) / z;
392
393     // Pme correction only needs to be ~1e-6 accuracy single
394     FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
395
396     EXPECT_REAL_EQ_TOL(ref, static_cast<float>(pmePotentialCorrectionSingleAccuracy(z2)), tolerance);
397 }
398
399 /*! \} */
400 /*! \endcond internal */
401
402 } // namespace
403 } // namespace test
404 } // namespace gmx