SDDSlib
Loading...
Searching...
No Matches
wofz.c
Go to the documentation of this file.
1/**
2 * @file wofz.c
3 * @brief Computes the complex error function \f$ W(z) \f$ for a given complex number \f$ z \f$.
4 *
5 * @copyright
6 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
7 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
8 *
9 * @license
10 * This file is distributed under the terms of the Software License Agreement
11 * found in the file LICENSE included with this distribution.
12 *
13 * @author H. Shang, M. Borland, R. Soliday
14 */
15
16#include "mdb.h"
17#include "f2c.h"
18
19double pow_di(doublereal *ap, integer *bp) {
20 double pow, x;
21 integer n;
22 unsigned long u;
23
24 pow = 1;
25 x = *ap;
26 n = *bp;
27
28 if (n != 0) {
29 if (n < 0) {
30 n = -n;
31 x = 1 / x;
32 }
33 for (u = n;;) {
34 if (u & 01)
35 pow *= x;
36 if (u >>= 1)
37 x *= x;
38 else
39 break;
40 }
41 }
42 return (pow);
43}
44
45#undef abs
46#define abs(x) ((x) >= 0 ? (x) : -(x))
47
48integer i_dnnt(doublereal *x) {
49 return (integer)(*x >= 0. ? floor(*x + .5) : -floor(.5 - *x));
50}
51
52/* ALGORITHM 680, COLLECTED ALGORITHMS FROM ACM. */
53/* THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE, */
54/* VOL. 16, NO. 1, PP. 47. */
55/* Subroutine */
56
57/**
58 * @brief Computes the complex error function \f$ W(z) \f$ for a given complex number \f$ z \f$.
59 *
60 * Given a complex number \f$ z = (\text{xi}, \text{yi}) \f$, this function computes the value of the
61 * Faddeeva function \f$ W(z) = \exp(-z^2) \cdot \text{ERFC}(-i z) \f$, where \f$ \text{ERFC} \f$ is the
62 * complex complementary error function and \f$ i = \sqrt{-1} \f$.
63 *
64 * The accuracy of the algorithm is:
65 * - 14 significant digits for \f$ z \f$ in the 1st and 2nd quadrants.
66 * - 13 significant digits for \f$ z \f$ in the 3rd and 4th quadrants, outside a circular region with
67 * a radius of 0.126 around a zero of the function.
68 *
69 * @param xi Pointer to the real part of the input complex number \f$ z \f$.
70 * @param yi Pointer to the imaginary part of the input complex number \f$ z \f$.
71 * @param u Pointer to store the real part of the computed \f$ W(z) \f$.
72 * @param v Pointer to store the imaginary part of the computed \f$ W(z) \f$.
73 * @param flag__ Pointer to a logical flag indicating whether an overflow has occurred.
74 * - \c false: No error condition.
75 * - \c true: Overflow has occurred; the routine becomes inactive.
76 *
77 * @return Returns \c 0 on successful computation. If an overflow is detected, \p flag__ is set to \c true.
78 */
79int wofz(xi, yi, u, v, flag__)
80 doublereal *xi,
81 *yi, *u, *v;
82logical *flag__;
83{
84 /* System generated locals */
85 doublereal d__1, d__2;
86
87 /* Builtin functions */
88 /*
89 double sqrt();
90 integer i_dnnt();
91 double exp(), cos(), sin(), pow_di();
92 */
93 /* Local variables */
94 static integer kapn;
95 static doublereal xabs, yabs, daux, qrho, xaux, xsum, ysum;
96 static logical a, b;
97 static doublereal c__, h__;
98 static integer i__, j, n;
99 static doublereal x, y, xabsq, xquad, yquad, h2, u1, v1, u2, v2, w1;
100 static integer nu;
101 static doublereal rx, ry, sx, sy, tx, ty;
102 static integer np1;
103 static doublereal qlambda;
104
105 /* GIVEN A COMPLEX NUMBER Z = (XI,YI), THIS SUBROUTINE COMPUTES */
106 /* THE VALUE OF THE FADDEEVA-FUNCTION W(Z) = EXP(-Z**2)*ERFC(-I*Z), */
107 /* WHERE ERFC IS THE COMPLEX COMPLEMENTARY ERROR-FUNCTION AND I */
108 /* MEANS SQRT(-1). */
109 /* THE ACCURACY OF THE ALGORITHM FOR Z IN THE 1ST AND 2ND QUADRANT */
110 /* IS 14 SIGNIFICANT DIGITS; IN THE 3RD AND 4TH IT IS 13 SIGNIFICANT */
111 /* DIGITS OUTSIDE A CIRCULAR REGION WITH RADIUS 0.126 AROUND A ZERO */
112 /* OF THE FUNCTION. */
113 /* ALL REAL VARIABLES IN THE PROGRAM ARE DOUBLE PRECISION. */
114
115 /* THE CODE CONTAINS A FEW COMPILER-DEPENDENT PARAMETERS : */
116 /* RMAXREAL = THE MAXIMUM VALUE OF RMAXREAL EQUALS THE ROOT OF */
117 /* RMAX = THE LARGEST NUMBER WHICH CAN STILL BE */
118 /* IMPLEMENTED ON THE COMPUTER IN DOUBLE PRECISION */
119 /* FLOATING-POINT ARITHMETIC */
120 /* RMAXEXP = LN(RMAX) - LN(2) */
121 /* RMAXGONI = THE LARGEST POSSIBLE ARGUMENT OF A DOUBLE PRECISION */
122 /* GONIOMETRIC FUNCTION (DCOS, DSIN, ...) */
123 /* THE REASON WHY THESE PARAMETERS ARE NEEDED AS THEY ARE DEFINED WILL */
124 /* BE EXPLAINED IN THE CODE BY MEANS OF COMMENTS */
125
126 /* PARAMETER LIST */
127 /* XI = REAL PART OF Z */
128 /* YI = IMAGINARY PART OF Z */
129 /* U = REAL PART OF W(Z) */
130 /* V = IMAGINARY PART OF W(Z) */
131 /* FLAG = AN ERROR FLAG INDICATING WHETHER OVERFLOW WILL */
132 /* OCCUR OR NOT; TYPE LOGICAL; */
133 /* THE VALUES OF THIS VARIABLE HAVE THE FOLLOWING */
134 /* MEANING : */
135 /* FLAG=.FALSE. : NO ERROR CONDITION */
136 /* FLAG=.TRUE. : OVERFLOW WILL OCCUR, THE ROUTINE */
137 /* BECOMES INACTIVE */
138 /* XI, YI ARE THE INPUT-PARAMETERS */
139 /* U, V, FLAG ARE THE OUTPUT-PARAMETERS */
140
141 /* FURTHERMORE THE PARAMETER FACTOR EQUALS 2/SQRT(PI) */
142
143 /* THE ROUTINE IS NOT UNDERFLOW-PROTECTED BUT ANY VARIABLE CAN BE */
144 /* PUT TO 0 UPON UNDERFLOW; */
145
146 /* REFERENCE - GPM POPPE, CMJ WIJERS; MORE EFFICIENT COMPUTATION OF */
147 /* THE COMPLEX ERROR-FUNCTION, ACM TRANS. MATH. SOFTWARE. */
148
149 *flag__ = FALSE_;
150
151 xabs = abs(*xi);
152 yabs = abs(*yi);
153 x = xabs / (float)6.3;
154 y = yabs / (float)4.4;
155
156 /* THE FOLLOWING IF-STATEMENT PROTECTS */
157 /* QRHO = (X**2 + Y**2) AGAINST OVERFLOW */
158
159 if (xabs > 5e153 || yabs > 5e153) {
160 goto L100;
161 }
162
163 /* Computing 2nd power */
164 d__1 = x;
165 /* Computing 2nd power */
166 d__2 = y;
167 qrho = d__1 * d__1 + d__2 * d__2;
168
169 /* Computing 2nd power */
170 d__1 = xabs;
171 xabsq = d__1 * d__1;
172 /* Computing 2nd power */
173 d__1 = yabs;
174 xquad = xabsq - d__1 * d__1;
175 yquad = xabs * 2 * yabs;
176
177 a = qrho < .085264;
178
179 if (a) {
180
181 /* IF (QRHO.LT.0.085264D0) THEN THE FADDEEVA-FUNCTION IS EVALUATED */
182 /* USING A POWER-SERIES (ABRAMOWITZ/STEGUN, EQUATION (7.1.5), P.297)
183*/
184 /* N IS THE MINIMUM NUMBER OF TERMS NEEDED TO OBTAIN THE REQUIRED */
185 /* ACCURACY */
186
187 qrho = (1 - y * (float).85) * sqrt(qrho);
188 d__1 = qrho * 72 + 6;
189 n = i_dnnt(&d__1);
190 j = (n << 1) + 1;
191 xsum = (float)1. / j;
192 ysum = 0.;
193 for (i__ = n; i__ >= 1; --i__) {
194 j += -2;
195 xaux = (xsum * xquad - ysum * yquad) / i__;
196 ysum = (xsum * yquad + ysum * xquad) / i__;
197 xsum = xaux + (float)1. / j;
198 /* L10: */
199 }
200 u1 = (xsum * yabs + ysum * xabs) * -1.12837916709551257388 + (float)1.;
201 v1 = (xsum * xabs - ysum * yabs) * 1.12837916709551257388;
202 daux = exp(-xquad);
203 u2 = daux * cos(yquad);
204 v2 = -daux * sin(yquad);
205
206 *u = u1 * u2 - v1 * v2;
207 *v = u1 * v2 + v1 * u2;
208
209 } else {
210
211 /* IF (QRHO.GT.1.O) THEN W(Z) IS EVALUATED USING THE LAPLACE */
212 /* CONTINUED FRACTION */
213 /* NU IS THE MINIMUM NUMBER OF TERMS NEEDED TO OBTAIN THE REQUIRED */
214 /* ACCURACY */
215
216 /* IF ((QRHO.GT.0.085264D0).AND.(QRHO.LT.1.0)) THEN W(Z) IS EVALUATED
217 */
218 /* BY A TRUNCATED TAYLOR EXPANSION, WHERE THE LAPLACE CONTINUED FRACT
219ION */
220 /* IS USED TO CALCULATE THE DERIVATIVES OF W(Z) */
221 /* KAPN IS THE MINIMUM NUMBER OF TERMS IN THE TAYLOR EXPANSION NEEDED
222 */
223 /* TO OBTAIN THE REQUIRED ACCURACY */
224 /* NU IS THE MINIMUM NUMBER OF TERMS OF THE CONTINUED FRACTION NEEDED
225 */
226 /* TO CALCULATE THE DERIVATIVES WITH THE REQUIRED ACCURACY */
227
228 if (qrho > (float)1.) {
229 h__ = 0.;
230 kapn = 0;
231 qrho = sqrt(qrho);
232 nu = (integer)(1442 / (qrho * 26 + 77) + 3);
233 } else {
234 qrho = (1 - y) * sqrt(1 - qrho);
235 h__ = qrho * (float)1.88;
236 h2 = h__ * 2;
237 d__1 = qrho * 34 + 7;
238 kapn = i_dnnt(&d__1);
239 d__1 = qrho * 26 + 16;
240 nu = i_dnnt(&d__1);
241 }
242
243 b = h__ > (float)0.;
244
245 if (b) {
246 qlambda = pow_di(&h2, &kapn);
247 }
248
249 rx = (float)0.;
250 ry = (float)0.;
251 sx = (float)0.;
252 sy = (float)0.;
253
254 for (n = nu; n >= 0; --n) {
255 np1 = n + 1;
256 tx = yabs + h__ + np1 * rx;
257 ty = xabs - np1 * ry;
258 /* Computing 2nd power */
259 d__1 = tx;
260 /* Computing 2nd power */
261 d__2 = ty;
262 c__ = (float).5 / (d__1 * d__1 + d__2 * d__2);
263 rx = c__ * tx;
264 ry = c__ * ty;
265 if (b && n <= kapn) {
266 tx = qlambda + sx;
267 sx = rx * tx - ry * sy;
268 sy = ry * tx + rx * sy;
269 qlambda /= h2;
270 }
271 /* L11: */
272 }
273
274 if (h__ == (float)0.) {
275 *u = rx * 1.12837916709551257388;
276 *v = ry * 1.12837916709551257388;
277 } else {
278 *u = sx * 1.12837916709551257388;
279 *v = sy * 1.12837916709551257388;
280 }
281
282 if (yabs == (float)0.) {
283 /* Computing 2nd power */
284 d__1 = xabs;
285 *u = exp(-(d__1 * d__1));
286 }
287 }
288
289 /* EVALUATION OF W(Z) IN THE OTHER QUADRANTS */
290
291 if (*yi < (float)0.) {
292
293 if (a) {
294 u2 *= 2;
295 v2 *= 2;
296 } else {
297 xquad = -xquad;
298
299 /* THE FOLLOWING IF-STATEMENT PROTECTS 2*EXP(-Z**2) */
300 /* AGAINST OVERFLOW */
301
302 if (yquad > 3537118876014220. || xquad > 708.503061461606) {
303 goto L100;
304 }
305
306 w1 = exp(xquad) * 2;
307 u2 = w1 * cos(yquad);
308 v2 = -w1 * sin(yquad);
309 }
310
311 *u = u2 - *u;
312 *v = v2 - *v;
313 if (*xi > (float)0.) {
314 *v = -(*v);
315 }
316 } else {
317 if (*xi < (float)0.) {
318 *v = -(*v);
319 }
320 }
321
322 return 0;
323
324L100:
325 *flag__ = TRUE_;
326 return 0;
327
328} /* wofz */
int wofz(doublereal *xi, doublereal *yi, doublereal *u, doublereal *v, logical *flag__)
Computes the complex error function for a given complex number .
Definition wofz.c:79