SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
elliptic.c
Go to the documentation of this file.
1/**
2 * @file elliptic.c
3 * @brief Functions for evaluating complete elliptic integrals of the first and second kind (K and E),
4 * as well as their total derivatives with respect to the modulus k.
5 *
6 * @copyright
7 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
8 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
9 *
10 * @license
11 * This file is distributed under the terms of the Software License Agreement
12 * found in the file LICENSE included with this distribution.
13 *
14 * @author M. Borland, C. Saunders, R. Soliday
15 */
16
17#include "mdb.h"
18#include "mdb_thread.h"
19
20static double ceiAccuracy = 1e-14;
21static MDB_THREAD_LOCK cei_accuracy_lock = MDB_THREAD_LOCK_INITIALIZER;
22
23static double getCeiAccuracy(void) {
24 double accuracy;
25 mdb_thread_lock(&cei_accuracy_lock);
26 accuracy = ceiAccuracy;
27 mdb_thread_unlock(&cei_accuracy_lock);
28 return accuracy;
29}
30
31void setCeiAccuracy(double newAccuracy) {
32 mdb_thread_lock(&cei_accuracy_lock);
33 ceiAccuracy = newAccuracy;
34 mdb_thread_unlock(&cei_accuracy_lock);
35}
36
37/**
38 * @brief Compute the complete elliptic integral of the first kind, K(k).
39 *
40 * K(k) = ∫_0^(π/2) dθ / √(1 - k² sin² θ)
41 *
42 * @param[in] k The modulus of the elliptic integral.
43 * @return The value of K(k).
44 */
45double K_cei(double k) {
46 double a0, b0, c0, a1, b1;
47 double accuracy = getCeiAccuracy();
48
49 a0 = 1;
50 b0 = sqrt(1 - sqr(k));
51 c0 = k;
52
53 do {
54 /* do two steps of recurrence per pass in the loop */
55 a1 = (a0 + b0) / 2;
56 b1 = sqrt(a0 * b0);
57 a0 = (a1 + b1) / 2;
58 b0 = sqrt(a1 * b1);
59 c0 = (a1 - b1) / 2;
60 } while (fabs(c0) > accuracy);
61 return PI / (2 * a0);
62}
63
64/**
65 * @brief Compute the complete elliptic integral of the second kind, E(k).
66 *
67 * E(k) = ∫_0^(π/2) √(1 - k² sin² θ) dθ
68 *
69 * @param[in] k The modulus of the elliptic integral.
70 * @return The value of E(k).
71 */
72double E_cei(double k) {
73 double a0, b0, c0, a1, b1, c1, K, sum, powerOf2;
74 double accuracy = getCeiAccuracy();
75
76 a0 = 1;
77 b0 = sqrt(1 - sqr(k));
78 c0 = k;
79 sum = sqr(c0);
80 powerOf2 = 1;
81
82 do {
83 /* do two steps of recurrence per pass in the loop */
84 a1 = (a0 + b0) / 2;
85 b1 = sqrt(a0 * b0);
86 c1 = (a0 - b0) / 2;
87 sum += sqr(c1) * (powerOf2 *= 2);
88 ;
89
90 a0 = (a1 + b1) / 2;
91 b0 = sqrt(a1 * b1);
92 c0 = (a1 - b1) / 2;
93 sum += sqr(c0) * (powerOf2 *= 2);
94 } while (fabs(c0) > accuracy);
95
96 K = PI / (2 * a0);
97 return K * (1 - sum / 2);
98}
99
100double *KE_cei(double k, double *buffer) {
101 double a0, b0, c0, a1, b1, c1, K, sum, powerOf2;
102 double accuracy = getCeiAccuracy();
103
104 if (!buffer)
105 buffer = tmalloc(sizeof(*buffer) * 2);
106
107 a0 = 1;
108 b0 = sqrt(1 - sqr(k));
109 c0 = k;
110 sum = sqr(c0);
111 powerOf2 = 1;
112
113 do {
114 /* do two steps of recurrence per pass in the loop */
115 a1 = (a0 + b0) / 2;
116 b1 = sqrt(a0 * b0);
117 c1 = (a0 - b0) / 2;
118 sum += sqr(c1) * (powerOf2 *= 2);
119 ;
120
121 a0 = (a1 + b1) / 2;
122 b0 = sqrt(a1 * b1);
123 c0 = (a1 - b1) / 2;
124 sum += sqr(c0) * (powerOf2 *= 2);
125 } while (fabs(c0) > accuracy);
126
127 buffer[0] = K = PI / (2 * a0);
128 buffer[1] = K * (1 - sum / 2);
129 return buffer;
130}
131
132/* These two functions rely on formulae quoted in Landau and Lifshitz,
133 ELECTRODYNAMICS OF CONTINUOUS MEDIA, pg 112.
134 */
135
136/**
137 * @brief Compute the total derivative dK/dk of the complete elliptic integral of the first kind.
138 *
139 * Uses K(k) and E(k) to determine the derivative with respect to k.
140 *
141 * @param[in] k The modulus of the elliptic integral.
142 * @return The value of dK/dk.
143 */
144double dK_cei(double k) {
145 double buffer[2];
146 KE_cei(k, buffer);
147 return (buffer[1] / (1 - k * k) - buffer[0]) / k;
148}
149
150/**
151 * @brief Compute the total derivative dE/dk of the complete elliptic integral of the second kind.
152 *
153 * Uses K(k) and E(k) to determine the derivative with respect to k.
154 *
155 * @param[in] k The modulus of the elliptic integral.
156 * @return The value of dE/dk.
157 */
158double dE_cei(k) double k;
159{
160 double buffer[2];
161 KE_cei(k, buffer);
162 return (buffer[1] - buffer[0]) / k;
163}
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:65
double dK_cei(double k)
Compute the total derivative dK/dk of the complete elliptic integral of the first kind.
Definition elliptic.c:144
double E_cei(double k)
Compute the complete elliptic integral of the second kind, E(k).
Definition elliptic.c:72
double K_cei(double k)
Compute the complete elliptic integral of the first kind, K(k).
Definition elliptic.c:45
double dE_cei(double k)
Compute the total derivative dE/dk of the complete elliptic integral of the second kind.
Definition elliptic.c:158