File: EllipticUtilities.h

package info (click to toggle)
vecgeom 1.2.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 23,928 kB
  • sloc: cpp: 88,717; ansic: 6,894; python: 1,035; sh: 582; sql: 538; makefile: 29
file content (141 lines) | stat: -rw-r--r-- 4,296 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// This file is part of VecGeom and is distributed under the
// conditions in the file LICENSE.txt in the top directory.
// For the full list of authors see CONTRIBUTORS.txt and `git log`.

/// Collection of auxiliary utilities for elliptical shapes
/// @file volumes/EllipticUtilities.h
/// @author Original implementation by Evgueni Tcherniaev (evc)

#ifndef VECGEOM_ELLIPTICUTILITIES_H_
#define VECGEOM_ELLIPTICUTILITIES_H_

#include "VecGeom/base/Global.h"
#include "VecGeom/base/RNG.h"
#include "VecGeom/base/Vector2D.h"
#include "VecGeom/base/Vector3D.h"

namespace vecgeom {

inline namespace VECGEOM_IMPL_NAMESPACE {

namespace EllipticUtilities {

/// Computes the Complete Elliptical Integral of the Second Kind
/// @param e eccentricity
//
VECCORE_ATT_HOST_DEVICE
VECGEOM_FORCE_INLINE
Precision comp_ellint_2(Precision e)
{
  // The algorithm is based upon Carlson B.C., "Computation of real
  // or complex elliptic integrals", Numerical Algorithms,
  // Volume 10, Issue 1, 1995 (see equations 2.36 - 2.39)
  //
  const Precision eps = 1. / 134217728.; // 1 / 2^27

  Precision a = 1.;
  Precision b = vecCore::math::Sqrt((1. - e) * (1. + e));
  if (b == 1.) return kHalfPi;
  if (b == 0.) return 1.;

  Precision x = 1.;
  Precision y = b;
  Precision S = 0.;
  Precision M = 1.;
  while (x - y > eps * y) {
    Precision tmp = (x + y) * 0.5;

    y = vecCore::math::Sqrt(x * y);
    x = tmp;
    M += M;
    S += M * (x - y) * (x - y);
  }
  return 0.5 * kHalfPi * ((a + b) * (a + b) - S) / (x + y);
}

/// Computes perimeter of ellipse (X/A)^2 + (Y/B)^2 = 1
/// @param A X semi-axis
/// @param B Y semi-axis
//
VECCORE_ATT_HOST_DEVICE
VECGEOM_FORCE_INLINE
Precision EllipsePerimeter(Precision A, Precision B)
{
  Precision dx  = vecCore::math::Abs(A);
  Precision dy  = vecCore::math::Abs(B);
  Precision a   = vecCore::math::Max(dx, dy);
  Precision b   = vecCore::math::Min(dx, dy);
  Precision b_a = b / a;
  Precision e   = vecCore::math::Sqrt((1. - b_a) * (1. + b_a));
  return 4. * a * comp_ellint_2(e);
}

/// Computes the lateral surface area of elliptic cone
/// @param pA X semi-axis of ellipse at base (Z = 0)
/// @param pB Y semi-axis of ellipse at base (Z = 0)
/// @param pH height
//
VECCORE_ATT_HOST_DEVICE
VECGEOM_FORCE_INLINE
Precision EllipticalConeLateralArea(Precision pA, Precision pB, Precision pH)
{
  Precision x  = vecCore::math::Abs(pA);
  Precision y  = vecCore::math::Abs(pB);
  Precision h  = vecCore::math::Abs(pH);
  Precision a  = vecCore::math::Max(x, y);
  Precision b  = vecCore::math::Min(x, y);
  Precision aa = a * a;
  Precision bb = b * b;
  Precision hh = h * h;
  Precision e  = vecCore::math::Sqrt(((a - b) * (a + b) * hh) / ((hh + bb) * aa));
  return 2. * a * vecCore::math::Sqrt(hh + bb) * comp_ellint_2(e);
}

/// Picks random point inside ellipse (x/a)^2 + (y/b)^2 = 1
/// @param a X semi-axis
/// @param b Y semi-axis
//
VECCORE_ATT_HOST_DEVICE
VECGEOM_FORCE_INLINE
Vector2D<Precision> RandomPointInEllipse(Precision a, Precision b)
{
  Precision aa = (a * a == 0.) ? 0. : 1. / (a * a);
  Precision bb = (b * b == 0.) ? 0. : 1. / (b * b);
  for (int i = 0; i < 1000; ++i) {
    Precision x = a * (2. * RNG::Instance().uniform() - 1.);
    Precision y = b * (2. * RNG::Instance().uniform() - 1.);
    if (x * x * aa + y * y * bb <= 1.) return Vector2D<Precision>(x, y);
  }
  return Vector2D<Precision>(0., 0.);
}

/// Picks random point on ellipse (x/a)^2 + (y/b)^2 = 1
/// @param a X semi-axis
/// @param b Y semi-axis
//
VECCORE_ATT_HOST_DEVICE
VECGEOM_FORCE_INLINE
Vector2D<Precision> RandomPointOnEllipse(Precision a, Precision b)
{
  Precision A      = vecCore::math::Abs(a);
  Precision B      = vecCore::math::Abs(b);
  Precision mu_max = vecCore::math::Max(A, B);

  Precision x, y;
  for (int i = 0; i < 1000; ++i) {
    Precision phi = kTwoPi * RNG::Instance().uniform();
    x             = vecCore::math::Cos(phi);
    y             = vecCore::math::Sin(phi);
    Precision Bx  = B * x;
    Precision Ay  = A * y;
    Precision mu  = vecCore::math::Sqrt(Bx * Bx + Ay * Ay);
    if (mu_max * RNG::Instance().uniform() <= mu) break;
  }
  return Vector2D<Precision>(A * x, B * y);
}

} // namespace EllipticUtilities
} // namespace VECGEOM_IMPL_NAMESPACE
} // namespace vecgeom

#endif /* VECGEOM_ELLIPTICUTILITIES_H_ */