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 return;
110 case 0:
111 ylm[0] = sph_cnsts[2] * rr * z[0];
112 return;
113 case 1:
114 ylm[0] = -sph_cnsts[3] * rr * x[0];
115 return;
116 }
117 case 2:
118 switch (m[0]) {
119 case -2:
120 ylm[0] = sph_cnsts[4] * x[0] * y[0] / r2;
121 return;
122 case -1:
123 ylm[0] = -sph_cnsts[5] * y[0] * z[0] / r2;
124 return;
125 case 0:
126 ylm[0] = sph_cnsts[6] * (3.0 * z[0] * z[0] / r2 - 1.0);
127 return;
128 case 1:
129 ylm[0] = -sph_cnsts[7] * x[0] * z[0] / r2;
130 return;
131 case 2:
132 ylm[0] = sph_cnsts[8] * (x[0] * x[0] - y[0] * y[0]) / r2;
133 return;
135 case 3:
136 r3 = r2 * r[0];
137 switch (m[0]) {
138 case -3:
139 ylm[0] = sph_cnsts[9] * ((3.0 * x[0] * x[0] - y[0] * y[0]) * y[0]) / r3;
140 return;
141 case -2:
142 ylm[0] = sph_cnsts[10] * (x[0] * y[0] * z[0]) / r3;
143 return;
144 case -1:
145 ylm[0] = sph_cnsts[11] * (y[0] * (5.0 * z[0] * z[0] - r2)) / r3;
146 return;
147 case 0:
148 ylm[0] = sph_cnsts[12] * (z[0] * (5.0 * z[0] * z[0] - 3.0 * r2)) / r3;
149 return;
150 case 1:
151 ylm[0] = sph_cnsts[13] * (x[0] * (5.0 * z[0] * z[0] - r2)) / r3;
152 return;
153 case 2:
154 ylm[0] = sph_cnsts[14] * ((x[0] * x[0] - y[0] * y[0]) * z[0]) / r3;
155 return;
156 case 3:
157 ylm[0] = sph_cnsts[15] * ((x[0] * x[0] - 3.0 * y[0] * y[0]) * x[0]) / r3;
158 return;
159 }
161
162 /* get phase */
163 rr = 1.0 / r[0];
164
165 rx = x[0] * rr;
166 ry = y[0] * rr;
167 rz = z[0] * rr;
168
169 rr = hypot(rx, ry);
170 if (rr < 1e-20) {
171 cosphi = 0.0;
172 sinphi = 0.0;
173 } else {
174 cosphi = rx / rr;
175 sinphi = ry / rr;
176 }
178 /* compute sin(mphi) and cos(mphi) by adding cos/sin */
179 cosm = 1.;
180 sinm = 0.;
181 for (i = 0; i < abs(m[0]); i++) {
182 double a = cosm, b = sinm;
183 cosm = a * cosphi - b * sinphi;
184 sinm = a * sinphi + b * cosphi;
185 }
186 phase = m[0] < 0 ? sinm : cosm;
187 phase = m[0] == 0 ? phase : sqrt(2.0) * phase;
189 /* lower bound with a small number (~= 10^-308) to avoid floating invalids */
190 rz = rz < DBL_MIN ? DBL_MIN : rz;
191
192 rr = gsl_sf_legendre_sphPlm(l[0], abs(m[0]), rz);
193
194 /* I am not sure whether we are including the Condon-Shortley factor (-1)^m */
195 ylm[0] = rr * phase;
196}
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__