Block-Structured AMR Software Framework
 
Loading...
Searching...
No Matches
AMReX_Math.H
Go to the documentation of this file.
1#ifndef AMREX_MATH_H_
2#define AMREX_MATH_H_
3#include <AMReX_Config.H>
4
6#include <AMReX_Extension.H>
7#include <AMReX_INT.H>
8#include <AMReX_SIMD.H>
9#include <AMReX_REAL.H>
10#include <cmath>
11#include <cstdlib>
12#include <limits>
13#include <type_traits>
14#include <utility>
15
16#ifdef AMREX_USE_SYCL
17# include <sycl/sycl.hpp>
18#endif
19
20namespace amrex { inline namespace disabled {
21 // If it is inside namespace amrex, or amrex namespace is imported with using namespace amrex or
22 // amrex::disabled, unqualified abs functions are disabled with a compile time error such as,
23 // call of overload abs(int&) is ambiguous, or a link time error such as, undefined reference to
24 // `amrex::disabled::abs(double)'. To fix it, one can use `std::abs` or `amrex::Math::abs`.
25 // The latter works in both host and device functions, whereas `std::abs` does not currently
26 // work on device with HIP and SYCL.
27 AMREX_GPU_HOST_DEVICE double abs (double);
29 AMREX_GPU_HOST_DEVICE long double abs (long double);
32 AMREX_GPU_HOST_DEVICE long long abs (long long);
33}}
34
35namespace amrex::Math {
36
37// Since Intel's SYCL compiler now supports the following std functions on device,
38// one no longer needs to use amrex::Math::abs, etc. They are kept here for
39// backward compatibility.
40
41using std::abs;
42using std::ceil;
43using std::copysign;
44using std::floor;
45using std::round;
46
47// However, since Intel's SYCL compiler is very aggressive with fast floating
48// point optimisations, the following must be kept, as using the std functions
49// always evaluates to false (even at -O1).
50
51#ifdef AMREX_USE_SYCL
52
53using sycl::isfinite;
54using sycl::isinf;
55
56#else
57
58using std::isfinite;
59using std::isinf;
60
61#endif
62
63template <typename T>
64constexpr std::enable_if_t<std::is_floating_point_v<T>,T> pi ()
65{
66 return T(3.1415926535897932384626433832795029L);
67}
68
71double cospi (double x)
72{
73#if defined(AMREX_USE_SYCL)
74 return sycl::cospi(x);
75#else
76 AMREX_IF_ON_DEVICE(( return ::cospi(x); ))
77 AMREX_IF_ON_HOST(( return std::cos(pi<double>()*x); ))
78#endif
79}
80
83float cospi (float x)
84{
85#if defined(AMREX_USE_SYCL)
86 return sycl::cospi(x);
87#else
88 AMREX_IF_ON_DEVICE(( return ::cospif(x); ))
89 AMREX_IF_ON_HOST(( return std::cos(pi<float>()*x); ))
90#endif
91}
92
95double sinpi (double x)
96{
97#if defined(AMREX_USE_SYCL)
98 return sycl::sinpi(x);
99#else
100 AMREX_IF_ON_DEVICE(( return ::sinpi(x); ))
101 AMREX_IF_ON_HOST(( return std::sin(pi<double>()*x); ))
102#endif
103}
104
107float sinpi (float x)
108{
109#if defined(AMREX_USE_SYCL)
110 return sycl::sinpi(x);
111#else
112 AMREX_IF_ON_DEVICE(( return ::sinpif(x); ))
113 AMREX_IF_ON_HOST(( return std::sin(pi<float>()*x); ))
114#endif
115}
116
117namespace detail {
118 AMREX_FORCE_INLINE void sincos (double x, double* sinx, double* cosx) {
119#if defined(_GNU_SOURCE) && !defined(__APPLE__)
120 ::sincos(x, sinx, cosx);
121#else
122 *sinx = std::sin(x);
123 *cosx = std::cos(x);
124#endif
125 }
126
127 AMREX_FORCE_INLINE void sincosf (float x, float* sinx, float* cosx) {
128#if defined(_GNU_SOURCE) && !defined(__APPLE__)
129 ::sincosf(x, sinx, cosx);
130#else
131 *sinx = std::sin(x);
132 *cosx = std::cos(x);
133#endif
134 }
135}
136
137#ifdef AMREX_USE_SIMD
139template<typename T_Real,
140 std::enable_if_t<amrex::simd::stdx::is_simd_v<T_Real>,int> = 0>
142std::pair<T_Real,T_Real> sincos (T_Real x)
143{
144 using namespace amrex::simd::stdx;
145 std::pair<T_Real,T_Real> r;
146 r.first = sin(x);
147 r.second = cos(x);
148 return r;
149}
150#endif
151
154std::pair<double,double> sincos (double x)
155{
156 std::pair<double,double> r;
157#if defined(AMREX_USE_SYCL)
158 r.first = sycl::sincos(x, sycl::private_ptr<double>(&r.second));
159#else
160 AMREX_IF_ON_DEVICE(( ::sincos(x, &r.first, &r.second); ))
161 AMREX_IF_ON_HOST(( detail::sincos(x, &r.first, &r.second); ))
162#endif
163 return r;
164}
165
168std::pair<float,float> sincos (float x)
169{
170 std::pair<float,float> r;
171#if defined(AMREX_USE_SYCL)
172 r.first = sycl::sincos(x, sycl::private_ptr<float>(&r.second));
173#else
174 AMREX_IF_ON_DEVICE(( ::sincosf(x, &r.first, &r.second); ))
175 AMREX_IF_ON_HOST(( detail::sincosf(x, &r.first, &r.second); ))
176#endif
177 return r;
178}
179
180#ifdef AMREX_USE_SIMD
182template<typename T_Real,
183 std::enable_if_t<amrex::simd::stdx::is_simd_v<T_Real>,int> = 0>
185std::pair<T_Real,T_Real> sincospi (T_Real x)
186{
187 using namespace amrex::simd::stdx;
188 T_Real const px = pi<typename T_Real::value_type>() * x;
189 std::pair<T_Real,T_Real> r;
190 r.first = sin(px);
191 r.second = cos(px);
192 return r;
193}
194#endif
195
198std::pair<double,double> sincospi (double x)
199{
200 std::pair<double,double> r;
201#if defined(AMREX_USE_SYCL)
202 r = sincos(pi<double>()*x);
203#else
204 AMREX_IF_ON_DEVICE(( ::sincospi(x, &r.first, &r.second); ))
205 AMREX_IF_ON_HOST(( r = sincos(pi<double>()*x); ))
206#endif
207 return r;
208}
209
212std::pair<float,float> sincospi (float x)
213{
214 std::pair<float,float> r;
215#if defined(AMREX_USE_SYCL)
216 r = sincos(pi<float>()*x);
217#else
218 AMREX_IF_ON_DEVICE(( ::sincospif(x, &r.first, &r.second); ))
219 AMREX_IF_ON_HOST(( r = sincos(pi<float>()*x); ))
220#endif
221 return r;
222}
223
225template <int Power, typename T,
226 typename = std::enable_if_t<!std::is_integral<T>() || Power>=0>>
228constexpr T powi (T x) noexcept
229{
230 if constexpr (Power < 0) {
231 return T(1)/powi<-Power>(x);
232 } else if constexpr (Power == 0) {
233 //note: 0^0 is implementation-defined, but most compilers return 1
234 return T(1);
235 } else if constexpr (Power == 1) {
236 return x;
237 } else if constexpr (Power == 2) {
238 return x*x;
239 } else if constexpr (Power%2 == 0) {
240 return powi<2>(powi<Power/2>(x));
241 } else {
242 return x*powi<Power-1>(x);
243 }
244}
245
246#if defined(AMREX_INT128_SUPPORTED)
248std::uint64_t umulhi (std::uint64_t a, std::uint64_t b)
249{
250#if defined(AMREX_USE_SYCL)
251 return sycl::mul_hi(a,b);
252#else
253 AMREX_IF_ON_DEVICE(( return __umul64hi(a, b); ))
255 auto tmp = amrex::UInt128_t(a) * amrex::UInt128_t(b);
256 return std::uint64_t(tmp >> 64);
257 ))
258#endif
259}
260#endif
261
262template <typename T>
265{
266 // Computing K based on DLMF
267 // https://dlmf.nist.gov/19.8
268 T tol = std::numeric_limits<T>::epsilon();
269
270 T a0 = 1.0;
271 T g0 = std::sqrt(1.0 - k*k);
272 T a = a0;
273 T g = g0;
274
275 // Find Arithmetic Geometric mean
276 while(std::abs(a0 - g0) > tol) {
277 a = 0.5*(a0 + g0);
278 g = std::sqrt(a0 * g0);
279
280 a0 = a;
281 g0 = g;
282 }
283
284 return 0.5*pi<T>()/a;
285}
286
287template <typename T>
290{
291 // Computing E based on DLMF
292 // https://dlmf.nist.gov/19.8
293 T Kcomp = amrex::Math::comp_ellint_1<T>(k);
294 T tol = std::numeric_limits<T>::epsilon();
295
296 // Step Zero
297 T a0 = 1.0;
298 T g0 = std::sqrt(1.0 - k*k);
299 T cn = std::sqrt(a0*a0 - g0*g0);
300
301 // Step 1
302 int n = 1;
303 T a = 0.5 * (a0 + g0);
304 T g = std::sqrt(a0*g0);
305 cn = 0.25*cn*cn/a;
306
307 T sum_val = a*a;
308 a0 = a;
309 g0 = g;
310
311 while(std::abs(cn*cn) > tol) {
312 // Compute coefficients for this iteration
313 a = 0.5 * (a0 + g0);
314 g = std::sqrt(a0*g0);
315 cn = 0.25*cn*cn/a;
316
317 n++;
318 sum_val -= std::pow(2,n-1)*cn*cn;
319
320 // Save a and g for next iteration
321 a0 = a;
322 g0 = g;
323 }
324
325 return Kcomp*sum_val;
326}
327
330double rsqrt (double x)
331{
332 double r;
333#if defined(AMREX_USE_SYCL)
334 AMREX_IF_ON_DEVICE(( r = sycl::rsqrt(x); ))
335#else
337#endif
338 AMREX_IF_ON_HOST(( r = 1. / std::sqrt(x); ))
339 return r;
340}
341
344float rsqrt (float x)
345{
346 float r;
347#if defined(AMREX_USE_SYCL)
348 AMREX_IF_ON_DEVICE(( r = sycl::rsqrt(x); ))
349#else
350 AMREX_IF_ON_DEVICE(( r = ::rsqrtf(x); ))
351#endif
352 AMREX_IF_ON_HOST(( r = 1.F / std::sqrt(x); ))
353 return r;
354}
355
356/***************************************************************************************************
357 * Copyright (c) 2017 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
358 * SPDX-License-Identifier: BSD-3-Clause
359 *
360 * Redistribution and use in source and binary forms, with or without
361 * modification, are permitted provided that the following conditions are met:
362 *
363 * 1. Redistributions of source code must retain the above copyright notice, this
364 * list of conditions and the following disclaimer.
365 *
366 * 2. Redistributions in binary form must reproduce the above copyright notice,
367 * this list of conditions and the following disclaimer in the documentation
368 * and/or other materials provided with the distribution.
369 *
370 * 3. Neither the name of the copyright holder nor the names of its
371 * contributors may be used to endorse or promote products derived from
372 * this software without specific prior written permission.
373 *
374 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
375 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
376 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
377 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
378 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
379 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
380 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
381 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
382 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
384 *
385 **************************************************************************************************/
386
388
404{
405 std::uint64_t divisor = 0;
406
407#ifdef AMREX_INT128_SUPPORTED
408 std::uint64_t multiplier = 1U;
409 unsigned int shift_right = 0;
410 unsigned int round_up = 0;
411
412 //
413 // Static methods
414 //
415
417 static std::uint32_t integer_log2 (std::uint64_t x)
418 {
419 std::uint32_t n = 0;
420 while (x >>= 1) {
421 ++n;
422 }
423 return n;
424 }
425
429 FastDivmodU64 (std::uint64_t divisor_)
430 : divisor(divisor_)
431 {
432 if (divisor) {
433 shift_right = integer_log2(divisor);
434
435 if ((divisor & (divisor - 1)) == 0) {
436 multiplier = 0;
437 }
438 else {
439 std::uint64_t power_of_two = (std::uint64_t(1) << shift_right);
440 auto n = amrex::UInt128_t(power_of_two) << 64;
441 std::uint64_t multiplier_lo = n / divisor;
442 n += power_of_two;
443 multiplier = n / divisor;
444 round_up = (multiplier_lo == multiplier ? 1 : 0);
445 }
446 }
447 }
448
449#else
450
451 FastDivmodU64 (std::uint64_t divisor_) : divisor(divisor_) {}
452
453#endif
454
456 FastDivmodU64 () = default;
457
459 [[nodiscard]] AMREX_GPU_HOST_DEVICE
460 std::uint64_t divide (std::uint64_t dividend) const
461 {
462#if defined(AMREX_INT128_SUPPORTED)
463 auto x = dividend;
464 if (multiplier) {
465 x = amrex::Math::umulhi(dividend + round_up, multiplier);
466 }
467 return (x >> shift_right);
468#else
469 return dividend / divisor;
470#endif
471 }
472
474 [[nodiscard]] AMREX_GPU_HOST_DEVICE
475 std::uint64_t modulus (std::uint64_t quotient, std::uint64_t dividend) const
476 {
477 return dividend - quotient * divisor;
478 }
479
481 [[nodiscard]] AMREX_GPU_HOST_DEVICE
482 std::uint64_t divmod (std::uint64_t &remainder, std::uint64_t dividend) const
483 {
484 auto quotient = divide(dividend);
485 remainder = modulus(quotient, dividend);
486 return quotient;
487 }
488
492 void operator() (std::uint64_t &quotient, std::uint64_t &remainder, std::uint64_t dividend) const
493 {
494 quotient = divmod(remainder, dividend);
495 }
496};
497
498}
499
500#endif
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:119
#define AMREX_IF_ON_DEVICE(CODE)
Definition AMReX_GpuQualifiers.H:56
#define AMREX_IF_ON_HOST(CODE)
Definition AMReX_GpuQualifiers.H:58
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
void sincosf(float x, float *sinx, float *cosx)
Definition AMReX_Math.H:127
void sincos(double x, double *sinx, double *cosx)
Definition AMReX_Math.H:118
Definition AMReX_Math.H:35
__host__ __device__ double sinpi(double x)
Return sin(x*pi) given x.
Definition AMReX_Math.H:95
constexpr std::enable_if_t< std::is_floating_point_v< T >, T > pi()
Definition AMReX_Math.H:64
__host__ __device__ std::pair< double, double > sincospi(double x)
Return sin(pi*x) and cos(pi*x) given x.
Definition AMReX_Math.H:198
__host__ __device__ double cospi(double x)
Return cos(x*pi) given x.
Definition AMReX_Math.H:71
__host__ __device__ T comp_ellint_1(T k)
Definition AMReX_Math.H:264
__host__ __device__ std::pair< double, double > sincos(double x)
Return sine and cosine of given number.
Definition AMReX_Math.H:154
__host__ __device__ T comp_ellint_2(T k)
Definition AMReX_Math.H:289
__host__ __device__ double rsqrt(double x)
Return inverse square root of x.
Definition AMReX_Math.H:330
constexpr T powi(T x) noexcept
Return pow(x, Power), where Power is an integer known at compile time.
Definition AMReX_Math.H:228
Definition AMReX_SIMD.H:24
Definition AMReX_Amr.cpp:49
__host__ __device__ T abs(const GpuComplex< T > &a_z) noexcept
Return the absolute value of a complex number.
Definition AMReX_GpuComplex.H:360
Definition AMReX_FabArrayCommI.H:1000
Definition AMReX_Math.H:404
__host__ __device__ std::uint64_t divide(std::uint64_t dividend) const
Returns the quotient of floor(dividend / divisor)
Definition AMReX_Math.H:460
__host__ __device__ std::uint64_t divmod(std::uint64_t &remainder, std::uint64_t dividend) const
Returns the quotient of floor(dividend / divisor) and computes the remainder.
Definition AMReX_Math.H:482
__host__ __device__ void operator()(std::uint64_t &quotient, std::uint64_t &remainder, std::uint64_t dividend) const
Definition AMReX_Math.H:492
__host__ __device__ std::uint64_t modulus(std::uint64_t quotient, std::uint64_t dividend) const
Computes the remainder given a computed quotient and dividend.
Definition AMReX_Math.H:475
std::uint64_t divisor
Definition AMReX_Math.H:405
FastDivmodU64(std::uint64_t divisor_)
Definition AMReX_Math.H:451
FastDivmodU64()=default
Default construct an invalid FastDivmodU64.