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