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 {
22inline namespace disabled {
23 // If it is inside namespace amrex, or amrex namespace is imported with using namespace amrex or
24 // amrex::disabled, unqualified abs functions are disabled with a compile time error such as,
25 // call of overload abs(int&) is ambiguous, or a link time error such as, undefined reference to
26 // `amrex::disabled::abs(double)'. To fix it, one can use `std::abs` or `amrex::Math::abs`.
27 // The latter works in both host and device functions, whereas `std::abs` does not currently
28 // work on device with HIP and SYCL.
29 AMREX_GPU_HOST_DEVICE double abs (double);
30 AMREX_GPU_HOST_DEVICE float abs (float);
31 AMREX_GPU_HOST_DEVICE long double abs (long double);
32 AMREX_GPU_HOST_DEVICE int abs (int);
33 AMREX_GPU_HOST_DEVICE long abs (long);
34 AMREX_GPU_HOST_DEVICE long long abs (long long);
35}
37}
38
39namespace amrex::Math {
40
41// Since Intel's SYCL compiler now supports the following std functions on device,
42// one no longer needs to use amrex::Math::abs, etc. They are kept here for
43// backward compatibility.
44
45using std::abs;
46using std::ceil;
47using std::copysign;
48using std::floor;
49using std::round;
50
51// However, since Intel's SYCL compiler is very aggressive with fast floating
52// point optimisations, the following must be kept, as using the std functions
53// always evaluates to false (even at -O1).
54
55#ifdef AMREX_USE_SYCL
56
57using sycl::isfinite;
58using sycl::isinf;
59
60#else
61
62using std::isfinite;
63using std::isinf;
64
65#endif
66
67template <typename T>
68constexpr std::enable_if_t<std::is_floating_point_v<T>,T> pi ()
69{
70 return T(3.1415926535897932384626433832795029L);
71}
72
75double cospi (double x)
76{
77#if defined(AMREX_USE_SYCL)
78 return sycl::cospi(x);
79#else
80 AMREX_IF_ON_DEVICE(( return ::cospi(x); ))
81 AMREX_IF_ON_HOST(( return std::cos(pi<double>()*x); ))
82#endif
83}
84
87float cospi (float x)
88{
89#if defined(AMREX_USE_SYCL)
90 return sycl::cospi(x);
91#else
92 AMREX_IF_ON_DEVICE(( return ::cospif(x); ))
93 AMREX_IF_ON_HOST(( return std::cos(pi<float>()*x); ))
94#endif
95}
96
99double sinpi (double x)
100{
101#if defined(AMREX_USE_SYCL)
102 return sycl::sinpi(x);
103#else
104 AMREX_IF_ON_DEVICE(( return ::sinpi(x); ))
105 AMREX_IF_ON_HOST(( return std::sin(pi<double>()*x); ))
106#endif
107}
108
111float sinpi (float x)
112{
113#if defined(AMREX_USE_SYCL)
114 return sycl::sinpi(x);
115#else
116 AMREX_IF_ON_DEVICE(( return ::sinpif(x); ))
117 AMREX_IF_ON_HOST(( return std::sin(pi<float>()*x); ))
118#endif
119}
120
122namespace detail {
123 AMREX_FORCE_INLINE void sincos (double x, double* sinx, double* cosx) {
124#if defined(_GNU_SOURCE) && !defined(__APPLE__)
125 ::sincos(x, sinx, cosx);
126#else
127 *sinx = std::sin(x);
128 *cosx = std::cos(x);
129#endif
130 }
131
132 AMREX_FORCE_INLINE void sincosf (float x, float* sinx, float* cosx) {
133#if defined(_GNU_SOURCE) && !defined(__APPLE__)
134 ::sincosf(x, sinx, cosx);
135#else
136 *sinx = std::sin(x);
137 *cosx = std::cos(x);
138#endif
139 }
140}
142
143#ifdef AMREX_USE_SIMD
145template<typename T_Real,
146 std::enable_if_t<amrex::simd::stdx::is_simd_v<T_Real>,int> = 0>
148std::pair<T_Real,T_Real> sincos (T_Real x)
149{
150 using namespace amrex::simd::stdx;
151 std::pair<T_Real,T_Real> r;
152 r.first = sin(x);
153 r.second = cos(x);
154 return r;
155}
156#endif
157
160std::pair<double,double> sincos (double x)
161{
162 std::pair<double,double> r;
163#if defined(AMREX_USE_SYCL)
164 r.first = sycl::sincos(x, sycl::private_ptr<double>(&r.second));
165#else
166 AMREX_IF_ON_DEVICE(( ::sincos(x, &r.first, &r.second); ))
167 AMREX_IF_ON_HOST(( detail::sincos(x, &r.first, &r.second); ))
168#endif
169 return r;
170}
171
174std::pair<float,float> sincos (float x)
175{
176 std::pair<float,float> r;
177#if defined(AMREX_USE_SYCL)
178 r.first = sycl::sincos(x, sycl::private_ptr<float>(&r.second));
179#else
180 AMREX_IF_ON_DEVICE(( ::sincosf(x, &r.first, &r.second); ))
181 AMREX_IF_ON_HOST(( detail::sincosf(x, &r.first, &r.second); ))
182#endif
183 return r;
184}
185
186#ifdef AMREX_USE_SIMD
188template<typename T_Real,
189 std::enable_if_t<amrex::simd::stdx::is_simd_v<T_Real>,int> = 0>
191std::pair<T_Real,T_Real> sincospi (T_Real x)
192{
193 using namespace amrex::simd::stdx;
194 T_Real const px = pi<typename T_Real::value_type>() * x;
195 std::pair<T_Real,T_Real> r;
196 r.first = sin(px);
197 r.second = cos(px);
198 return r;
199}
200#endif
201
204std::pair<double,double> sincospi (double x)
205{
206 std::pair<double,double> r;
207#if defined(AMREX_USE_SYCL)
208 r = sincos(pi<double>()*x);
209#else
210 AMREX_IF_ON_DEVICE(( ::sincospi(x, &r.first, &r.second); ))
211 AMREX_IF_ON_HOST(( r = sincos(pi<double>()*x); ))
212#endif
213 return r;
214}
215
218std::pair<float,float> sincospi (float x)
219{
220 std::pair<float,float> r;
221#if defined(AMREX_USE_SYCL)
222 r = sincos(pi<float>()*x);
223#else
224 AMREX_IF_ON_DEVICE(( ::sincospif(x, &r.first, &r.second); ))
225 AMREX_IF_ON_HOST(( r = sincos(pi<float>()*x); ))
226#endif
227 return r;
228}
229
231template <int Power, typename T,
232 typename = std::enable_if_t<!std::is_integral<T>() || Power>=0>>
234constexpr T powi (T x) noexcept
235{
236 if constexpr (Power < 0) {
237 return T(1)/powi<-Power>(x);
238 } else if constexpr (Power == 0) {
239 //note: 0^0 is implementation-defined, but most compilers return 1
240 return T(1);
241 } else if constexpr (Power == 1) {
242 return x;
243 } else if constexpr (Power == 2) {
244 return x*x;
245 } else if constexpr (Power%2 == 0) {
246 return powi<2>(powi<Power/2>(x));
247 } else {
248 return x*powi<Power-1>(x);
249 }
250}
251
252#if defined(AMREX_INT128_SUPPORTED)
254std::uint64_t umulhi (std::uint64_t a, std::uint64_t b)
255{
256#if defined(AMREX_USE_SYCL)
257 return sycl::mul_hi(a,b);
258#else
259 AMREX_IF_ON_DEVICE(( return __umul64hi(a, b); ))
261 auto tmp = amrex::UInt128_t(a) * amrex::UInt128_t(b);
262 return std::uint64_t(tmp >> 64);
263 ))
264#endif
265}
266#endif
267
268template <typename T>
271{
272 // Computing K based on DLMF
273 // https://dlmf.nist.gov/19.8
274 T tol = std::numeric_limits<T>::epsilon();
275
276 T a0 = 1.0;
277 T g0 = std::sqrt(1.0 - k*k);
278 T a = a0;
279 T g = g0;
280
281 // Find Arithmetic Geometric mean
282 while(std::abs(a0 - g0) > tol) {
283 a = 0.5*(a0 + g0);
284 g = std::sqrt(a0 * g0);
285
286 a0 = a;
287 g0 = g;
288 }
289
290 return 0.5*pi<T>()/a;
291}
292
293template <typename T>
296{
297 // Computing E based on DLMF
298 // https://dlmf.nist.gov/19.8
299 T Kcomp = amrex::Math::comp_ellint_1<T>(k);
300 T tol = std::numeric_limits<T>::epsilon();
301
302 // Step Zero
303 T a0 = 1.0;
304 T g0 = std::sqrt(1.0 - k*k);
305 T cn = std::sqrt(a0*a0 - g0*g0);
306
307 // Step 1
308 int n = 1;
309 T a = 0.5 * (a0 + g0);
310 T g = std::sqrt(a0*g0);
311 cn = 0.25*cn*cn/a;
312
313 T sum_val = a*a;
314 a0 = a;
315 g0 = g;
316
317 while(std::abs(cn*cn) > tol) {
318 // Compute coefficients for this iteration
319 a = 0.5 * (a0 + g0);
320 g = std::sqrt(a0*g0);
321 cn = 0.25*cn*cn/a;
322
323 n++;
324 sum_val -= std::pow(2,n-1)*cn*cn;
325
326 // Save a and g for next iteration
327 a0 = a;
328 g0 = g;
329 }
330
331 return Kcomp*sum_val;
332}
333
336double rsqrt (double x)
337{
338 double r;
339#if defined(AMREX_USE_SYCL)
340 AMREX_IF_ON_DEVICE(( r = sycl::rsqrt(x); ))
341#else
342 AMREX_IF_ON_DEVICE(( r = ::rsqrt(x); ))
343#endif
344 AMREX_IF_ON_HOST(( r = 1. / std::sqrt(x); ))
345 return r;
346}
347
350float rsqrt (float x)
351{
352 float r;
353#if defined(AMREX_USE_SYCL)
354 AMREX_IF_ON_DEVICE(( r = sycl::rsqrt(x); ))
355#else
356 AMREX_IF_ON_DEVICE(( r = ::rsqrtf(x); ))
357#endif
358 AMREX_IF_ON_HOST(( r = 1.F / std::sqrt(x); ))
359 return r;
360}
361
364double exp10 (double x)
365{
366 double r;
367#if defined(AMREX_USE_SYCL)
368 AMREX_IF_ON_DEVICE(( r = sycl::exp10(x); ))
369#else
370 AMREX_IF_ON_DEVICE(( r = ::exp10(x); ))
371#endif
372 AMREX_IF_ON_HOST(( r = std::pow(10.0, x); ))
373 return r;
374}
375
378float exp10 (float x)
379{
380 float r;
381#if defined(AMREX_USE_SYCL)
382 AMREX_IF_ON_DEVICE(( r = sycl::exp10(x); ))
383#else
384 AMREX_IF_ON_DEVICE(( r = ::exp10f(x); ))
385#endif
386 AMREX_IF_ON_HOST(( r = std::pow(10.0F, x); ))
387 return r;
388}
389
390/***************************************************************************************************
391 * Copyright (c) 2017 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
392 * SPDX-License-Identifier: BSD-3-Clause
393 *
394 * Redistribution and use in source and binary forms, with or without
395 * modification, are permitted provided that the following conditions are met:
396 *
397 * 1. Redistributions of source code must retain the above copyright notice, this
398 * list of conditions and the following disclaimer.
399 *
400 * 2. Redistributions in binary form must reproduce the above copyright notice,
401 * this list of conditions and the following disclaimer in the documentation
402 * and/or other materials provided with the distribution.
403 *
404 * 3. Neither the name of the copyright holder nor the names of its
405 * contributors may be used to endorse or promote products derived from
406 * this software without specific prior written permission.
407 *
408 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
409 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
410 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
411 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
412 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
413 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
414 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
415 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
416 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
417 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
418 *
419 **************************************************************************************************/
420
422
438{
439 std::uint64_t divisor = 0;
440
441#ifdef AMREX_INT128_SUPPORTED
442 std::uint64_t multiplier = 1U;
443 unsigned int shift_right = 0;
444 unsigned int round_up = 0;
445
446 //
447 // Static methods
448 //
449
451 static std::uint32_t integer_log2 (std::uint64_t x)
452 {
453 std::uint32_t n = 0;
454 while (x >>= 1) {
455 ++n;
456 }
457 return n;
458 }
459
463 FastDivmodU64 (std::uint64_t divisor_)
464 : divisor(divisor_)
465 {
466 if (divisor) {
467 shift_right = integer_log2(divisor);
468
469 if ((divisor & (divisor - 1)) == 0) {
470 multiplier = 0;
471 }
472 else {
473 std::uint64_t power_of_two = (std::uint64_t(1) << shift_right);
474 auto n = amrex::UInt128_t(power_of_two) << 64;
475 std::uint64_t multiplier_lo = n / divisor;
476 n += power_of_two;
477 multiplier = n / divisor;
478 round_up = (multiplier_lo == multiplier ? 1 : 0);
479 }
480 }
481 }
482
483#else
484
485 FastDivmodU64 (std::uint64_t divisor_) : divisor(divisor_) {}
486
487#endif
488
490 FastDivmodU64 () = default;
491
493 [[nodiscard]] AMREX_GPU_HOST_DEVICE
494 std::uint64_t divide (std::uint64_t dividend) const
495 {
496#if defined(AMREX_INT128_SUPPORTED)
497 auto x = dividend;
498 if (multiplier) {
499 x = amrex::Math::umulhi(dividend + round_up, multiplier);
500 }
501 return (x >> shift_right);
502#else
503 return dividend / divisor;
504#endif
505 }
506
508 [[nodiscard]] AMREX_GPU_HOST_DEVICE
509 std::uint64_t modulus (std::uint64_t quotient, std::uint64_t dividend) const
510 {
511 return dividend - quotient * divisor;
512 }
513
515 [[nodiscard]] AMREX_GPU_HOST_DEVICE
516 std::uint64_t divmod (std::uint64_t &remainder, std::uint64_t dividend) const
517 {
518 auto quotient = divide(dividend);
519 remainder = modulus(quotient, dividend);
520 return quotient;
521 }
522
526 void operator() (std::uint64_t &quotient, std::uint64_t &remainder, std::uint64_t dividend) const
527 {
528 quotient = divmod(remainder, dividend);
529 }
530};
531
532}
533
534#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
Definition AMReX_Math.H:39
__host__ __device__ double sinpi(double x)
Return sin(x*pi) given x.
Definition AMReX_Math.H:99
constexpr std::enable_if_t< std::is_floating_point_v< T >, T > pi()
Definition AMReX_Math.H:68
__host__ __device__ std::pair< double, double > sincospi(double x)
Return sin(pi*x) and cos(pi*x) given x.
Definition AMReX_Math.H:204
__host__ __device__ double cospi(double x)
Return cos(x*pi) given x.
Definition AMReX_Math.H:75
__host__ __device__ double exp10(double x)
Return 10**x.
Definition AMReX_Math.H:364
__host__ __device__ T comp_ellint_1(T k)
Definition AMReX_Math.H:270
__host__ __device__ std::pair< double, double > sincos(double x)
Return sine and cosine of given number.
Definition AMReX_Math.H:160
__host__ __device__ T comp_ellint_2(T k)
Definition AMReX_Math.H:295
__host__ __device__ double rsqrt(double x)
Return inverse square root of x.
Definition AMReX_Math.H:336
constexpr T powi(T x) noexcept
Return pow(x, Power), where Power is an integer known at compile time.
Definition AMReX_Math.H:234
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:361
Definition AMReX_Math.H:438
__host__ __device__ std::uint64_t divide(std::uint64_t dividend) const
Returns the quotient of floor(dividend / divisor)
Definition AMReX_Math.H:494
__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:516
__host__ __device__ void operator()(std::uint64_t &quotient, std::uint64_t &remainder, std::uint64_t dividend) const
Definition AMReX_Math.H:526
__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:509
std::uint64_t divisor
Definition AMReX_Math.H:439
FastDivmodU64(std::uint64_t divisor_)
Definition AMReX_Math.H:485
FastDivmodU64()=default
Default construct an invalid FastDivmodU64.