Octopus
ylm.c
Go to the documentation of this file.
1/*
2 Copyright (C) 2002 M. Marques, A. Castro, A. Rubio, G. Bertsch
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18
19*/
21#include <config.h>
22#include <float.h>
23#include <fortran_types.h>
24#include <math.h>
25#include <stdlib.h>
26
27#include <gsl/gsl_sf_legendre.h>
28
29/* normalization constants for the spherical harmonics */
30static double sph_cnsts[16] = {
31 /* l = 0 */
32 0.28209479177387814347403972578,
33 /* l = 1 */
34 0.48860251190291992158638462283, 0.48860251190291992158638462283,
35 0.48860251190291992158638462283,
36 /* l = 2 */
37 1.09254843059207907054338570580, 1.09254843059207907054338570580,
38 0.31539156525252000603089369029, 1.09254843059207907054338570580,
39 0.54627421529603953527169285290,
40 /* l = 3 */
41 0.59004358992664351034561027754, 2.89061144264055405538938015439,
42 0.45704579946446573615802069691, 0.37317633259011539141439591319,
43 0.45704579946446573615802069691, 1.44530572132027702769469007719,
44 0.59004358992664351034561027754};
45
46void oct_ylm_base(const double *r, const double *x, const double *y,
47 const double *z, const fint *l, const fint *m, double *ylm);
48
49/* Computes real spherical harmonics ylm in the direction of vector r:
50 ylm = c * plm( cos(theta) ) * sin(m*phi) for m < 0
51 ylm = c * plm( cos(theta) ) * cos(m*phi) for m >= 0
52 with (theta,phi) the polar angles of r, c a positive normalization
53 constant and plm associated legendre polynomials. */
54
55void FC_FUNC_(oct_ylm, OCT_YLM)(const fint *np, const double *x,
56 const double *y, const double *z, const fint *l,
57 const fint *m, double *restrict ylm) {
58 if (l[0] == 0) {
59 for (int ip = 0; ip < np[0]; ip++)
60 ylm[ip] = sph_cnsts[0];
61 return;
62 }
63
64 for (int ip = 0; ip < np[0]; ip++) {
65
66 double rr = sqrt(x[ip] * x[ip] + y[ip] * y[ip] + z[ip] * z[ip]);
67
68 oct_ylm_base(&rr, &x[ip], &y[ip], &z[ip], l, m, &ylm[ip]);
69 }
70}
71
72void FC_FUNC_(oct_ylm_vector, OCT_YLM_VECTOR)(const fint *np, const double *xx,
73 const double *rr, const fint *l,
74 const fint *m,
75 double *restrict ylm) {
76 if (l[0] == 0) {
77 for (int ip = 0; ip < np[0]; ip++)
78 ylm[ip] = sph_cnsts[0];
79 return;
80 }
82 for (int ip = 0; ip < np[0]; ip++) {
84 oct_ylm_base(&rr[ip], &xx[ip * 3], &xx[ip * 3 + 1], &xx[ip * 3 + 2], l, m,
85 &ylm[ip]);
86 }
89void oct_ylm_base(const double *r, const double *x, const double *y,
90 const double *z, const fint *l, const fint *m, double *ylm) {
92 double r2, r3, rr, rx, ry, rz, cosphi, sinphi, cosm, sinm, phase;
93 int i;
95 r2 = r[0] * r[0];
96
97 /* if r=0, direction is undefined => make ylm=0 except for l=0 */
98 if (r2 < 1.0e-30) {
99 ylm[0] = 0.0;
100 return;
103 switch (l[0]) {
104 case 1:
105 rr = 1.0 / r[0];
106 switch (m[0]) {
107 case -1:
108 ylm[0] = -sph_cnsts[1] * rr * y[0];
109 break;
110 case 0:
111 ylm[0] = sph_cnsts[2] * rr * z[0];
112 break;
113 case 1:
114 ylm[0] = -sph_cnsts[3] * rr * x[0];
115 break;
116 }
117 return;
118 case 2:
119 switch (m[0]) {
120 case -2:
121 ylm[0] = sph_cnsts[4] * x[0] * y[0] / r2;
122 break;
123 case -1:
124 ylm[0] = -sph_cnsts[5] * y[0] * z[0] / r2;
125 break;
126 case 0:
127 ylm[0] = sph_cnsts[6] * (3.0 * z[0] * z[0] / r2 - 1.0);
128 break;
129 case 1:
130 ylm[0] = -sph_cnsts[7] * x[0] * z[0] / r2;
131 break;
132 case 2:
133 ylm[0] = sph_cnsts[8] * (x[0] * x[0] - y[0] * y[0]) / r2;
134 break;
136 return;
137 case 3:
138 r3 = r2 * r[0];
139 switch (m[0]) {
140 case -3:
141 ylm[0] = sph_cnsts[9] * ((3.0 * x[0] * x[0] - y[0] * y[0]) * y[0]) / r3;
142 break;
143 case -2:
144 ylm[0] = sph_cnsts[10] * (x[0] * y[0] * z[0]) / r3;
145 break;
146 case -1:
147 ylm[0] = sph_cnsts[11] * (y[0] * (5.0 * z[0] * z[0] - r2)) / r3;
148 break;
149 case 0:
150 ylm[0] = sph_cnsts[12] * (z[0] * (5.0 * z[0] * z[0] - 3.0 * r2)) / r3;
151 break;
152 case 1:
153 ylm[0] = sph_cnsts[13] * (x[0] * (5.0 * z[0] * z[0] - r2)) / r3;
154 break;
155 case 2:
156 ylm[0] = sph_cnsts[14] * ((x[0] * x[0] - y[0] * y[0]) * z[0]) / r3;
157 break;
158 case 3:
159 ylm[0] = sph_cnsts[15] * ((x[0] * x[0] - 3.0 * y[0] * y[0]) * x[0]) / r3;
160 break;
161 }
162 return;
163 }
164
165 /* get phase */
166 rr = 1.0 / r[0];
167
168 rx = x[0] * rr;
169 ry = y[0] * rr;
170 rz = z[0] * rr;
171
172 rr = hypot(rx, ry);
173 if (rr < 1e-20) {
174 cosphi = 0.0;
175 sinphi = 0.0;
176 } else {
177 cosphi = rx / rr;
178 sinphi = ry / rr;
180
181 /* compute sin(mphi) and cos(mphi) by adding cos/sin */
182 cosm = 1.;
183 sinm = 0.;
184 for (i = 0; i < abs(m[0]); i++) {
185 double a = cosm, b = sinm;
186 cosm = a * cosphi - b * sinphi;
187 sinm = a * sinphi + b * cosphi;
189 phase = m[0] < 0 ? sinm : cosm;
190 phase = m[0] == 0 ? phase : sqrt(2.0) * phase;
191
192 /* lower bound with a small number (~= 10^-308) to avoid floating invalids */
193 rz = rz < DBL_MIN ? DBL_MIN : rz;
194
195 rr = gsl_sf_legendre_sphPlm(l[0], abs(m[0]), rz);
196
197 /* I am not sure whether we are including the Condon-Shortley factor (-1)^m */
198 ylm[0] = rr * phase;
199}
int fint
Definition: fortran_types.h:14
ptrdiff_t l
Definition: operate_inc.c:12
ptrdiff_t i
Definition: operate_inc.c:12
double hypot(double __x, double __y) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__