OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
SphericalHarmonic.cpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the following paper when you publish your work:
33 *
34 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35 *
36 * Good starting points for code and simulation methodology are:
37 *
38 * [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39 * [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40 * [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42 * [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43 * [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45 * [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46 */
47
49
50#include <config.h>
51
52#include <cmath>
53#include <cstdio>
54#include <limits>
55
56#include "utils/Constants.hpp"
57#include "utils/simError.h"
58
59using namespace OpenMD;
60
61SphericalHarmonic::SphericalHarmonic() {}
62
63ComplexType SphericalHarmonic::getValueAt(RealType costheta, RealType phi) {
64 RealType p;
65
66 // associated Legendre polynomial
67 p = Ptilde(L, M, costheta);
68 ComplexType phase(0.0, (RealType)M * phi);
69
70 return exp(phase) * (ComplexType)p;
71}
72//
73// Routine to calculate the associated Legendre polynomials for m>=0
74//
75RealType SphericalHarmonic::LegendreP(int l, int m, RealType x) {
76 RealType result;
77
78 if (fabs(x) > 1.0) {
79 printf("LegendreP: x out of range: l = %d\tm = %d\tx = %lf\n", l, m, x);
80 return std::numeric_limits<RealType>::quiet_NaN();
81 }
82
83 if (m > l) {
84 printf("LegendreP: m > l: l = %d\tm = %d\tx = %lf\n", l, m, x);
85 return std::numeric_limits<RealType>::quiet_NaN();
86 }
87
88 if (m < 0) {
89 printf("LegendreP: m < 0: l = %d\tm = %d\tx = %lf\n", l, m, x);
90 return std::numeric_limits<RealType>::quiet_NaN();
91 } else {
92 RealType temp1, temp2(0.0), temp3, temp4, temp5;
93 temp3 = 1.0;
94
95 if (m > 0) {
96 temp1 = sqrt(1.0 - pow(x, 2));
97 temp5 = 1.0;
98 for (int i = 1; i <= m; ++i) {
99 temp3 *= -temp5 * temp1;
100 temp5 += 2.0;
101 }
102 }
103 if (l == m) {
104 result = temp3;
105 } else {
106 temp4 = x * (2. * m + 1.) * temp3;
107 if (l == (m + 1)) {
108 result = temp4;
109 } else {
110 for (int ll = (m + 2); ll <= l; ++ll) {
111 temp2 = (x * (2. * ll - 1.) * temp4 - (ll + m - 1.) * temp3) /
112 (RealType)(ll - m);
113 temp3 = temp4;
114 temp4 = temp2;
115 }
116 result = temp2;
117 }
118 }
119 }
120 return result;
121}
122
123//
124// Routine to calculate the associated Legendre polynomials for all m...
125//
126RealType SphericalHarmonic::Legendre(int l, int m, RealType x) {
127 RealType result;
128 if (m > l || m < -l) {
129 printf("Legendre got a bad argument: l = %d\tm = %d\tx = %lf\n", l, m, x);
130 return std::numeric_limits<RealType>::quiet_NaN();
131 } else if (m >= 0) {
132 result = LegendreP(l, m, x);
133 } else {
134 // result = mpow(-m)*LegendreP(l,-m,x);
135 result = mpow(-m) * Fact(l + m) / Fact(l - m) * LegendreP(l, -m, x);
136 }
137 result *= mpow(m);
138 return result;
139}
140//
141// Routine to calculate the normalized associated Legendre polynomials...
142//
143RealType SphericalHarmonic::Ptilde(int l, int m, RealType x) {
144 RealType result;
145 if (m > l || m < -l) {
146 result = 0.;
147 } else {
148 RealType y = (RealType)(2. * l + 1.) * Fact(l - m) / Fact(l + m);
149 result = mpow(m) * sqrt(y) * Legendre(l, m, x) / sqrt(4.0 * Constants::PI);
150 }
151 return result;
152}
153//
154// mpow returns (-1)**m
155//
156RealType SphericalHarmonic::mpow(int m) {
157 int result;
158 if (m < 0) m = -m;
159 if (m & 0x1)
160 result = -1;
161 else
162 result = 1;
163 return result;
164}
165//
166// factorial_list is a lookup table for n!
167//
168static RealType factorial_list[171] = {1.,
169 1.,
170 2.,
171 6.,
172 24.,
173 120.,
174 720.,
175 5040.,
176 40320.,
177 362880.,
178 3.6288e6,
179 3.99168e7,
180 4.790016e8,
181 6.2270208e9,
182 8.71782912e10,
183 1.307674368e12,
184 2.0922789888e13,
185 3.55687428096e14,
186 6.402373705728e15,
187 1.21645100408832e17,
188 2.43290200817664e18,
189 5.109094217170944e19,
190 1.1240007277776077e21,
191 2.585201673888498e22,
192 6.204484017332394e23,
193 1.5511210043330986e25,
194 4.0329146112660565e26,
195 1.0888869450418352e28,
196 3.0488834461171387e29,
197 8.841761993739702e30,
198 2.6525285981219107e32,
199 8.222838654177922e33,
200 2.631308369336935e35,
201 8.683317618811886e36,
202 2.9523279903960416e38,
203 1.0333147966386145e40,
204 3.7199332678990125e41,
205 1.3763753091226346e43,
206 5.230226174666011e44,
207 2.0397882081197444e46,
208 8.159152832478977e47,
209 3.345252661316381e49,
210 1.40500611775288e51,
211 6.041526306337383e52,
212 2.658271574788449e54,
213 1.1962222086548019e56,
214 5.502622159812089e57,
215 2.5862324151116818e59,
216 1.2413915592536073e61,
217 6.082818640342675e62,
218 3.0414093201713376e64,
219 1.5511187532873822e66,
220 8.065817517094388e67,
221 4.2748832840600255e69,
222 2.308436973392414e71,
223 1.2696403353658276e73,
224 7.109985878048635e74,
225 4.0526919504877214e76,
226 2.3505613312828785e78,
227 1.3868311854568984e80,
228 8.32098711274139e81,
229 5.075802138772248e83,
230 3.146997326038794e85,
231 1.98260831540444e87,
232 1.2688693218588417e89,
233 8.247650592082472e90,
234 5.443449390774431e92,
235 3.647111091818868e94,
236 2.4800355424368305e96,
237 1.711224524281413e98,
238 1.1978571669969892e100,
239 8.504785885678623e101,
240 6.1234458376886085e103,
241 4.4701154615126844e105,
242 3.307885441519386e107,
243 2.48091408113954e109,
244 1.8854947016660504e111,
245 1.4518309202828587e113,
246 1.1324281178206297e115,
247 8.946182130782976e116,
248 7.156945704626381e118,
249 5.797126020747368e120,
250 4.753643337012842e122,
251 3.945523969720659e124,
252 3.314240134565353e126,
253 2.81710411438055e128,
254 2.4227095383672734e130,
255 2.107757298379528e132,
256 1.8548264225739844e134,
257 1.650795516090846e136,
258 1.4857159644817615e138,
259 1.352001527678403e140,
260 1.2438414054641308e142,
261 1.1567725070816416e144,
262 1.087366156656743e146,
263 1.032997848823906e148,
264 9.916779348709496e149,
265 9.619275968248212e151,
266 9.426890448883248e153,
267 9.332621544394415e155,
268 9.332621544394415e157,
269 9.42594775983836e159,
270 9.614466715035127e161,
271 9.90290071648618e163,
272 1.0299016745145628e166,
273 1.081396758240291e168,
274 1.1462805637347084e170,
275 1.226520203196138e172,
276 1.324641819451829e174,
277 1.4438595832024937e176,
278 1.588245541522743e178,
279 1.7629525510902446e180,
280 1.974506857221074e182,
281 2.2311927486598138e184,
282 2.5435597334721877e186,
283 2.925093693493016e188,
284 3.393108684451898e190,
285 3.969937160808721e192,
286 4.684525849754291e194,
287 5.574585761207606e196,
288 6.689502913449127e198,
289 8.094298525273444e200,
290 9.875044200833601e202,
291 1.214630436702533e205,
292 1.506141741511141e207,
293 1.882677176888926e209,
294 2.372173242880047e211,
295 3.0126600184576594e213,
296 3.856204823625804e215,
297 4.974504222477287e217,
298 6.466855489220474e219,
299 8.47158069087882e221,
300 1.1182486511960043e224,
301 1.4872707060906857e226,
302 1.9929427461615188e228,
303 2.6904727073180504e230,
304 3.659042881952549e232,
305 5.012888748274992e234,
306 6.917786472619489e236,
307 9.615723196941089e238,
308 1.3462012475717526e241,
309 1.898143759076171e243,
310 2.695364137888163e245,
311 3.854370717180073e247,
312 5.5502938327393044e249,
313 8.047926057471992e251,
314 1.1749972043909107e254,
315 1.727245890454639e256,
316 2.5563239178728654e258,
317 3.80892263763057e260,
318 5.713383956445855e262,
319 8.62720977423324e264,
320 1.3113358856834524e267,
321 2.0063439050956823e269,
322 3.0897696138473508e271,
323 4.789142901463394e273,
324 7.471062926282894e275,
325 1.1729568794264145e278,
326 1.853271869493735e280,
327 2.9467022724950384e282,
328 4.7147236359920616e284,
329 7.590705053947219e286,
330 1.2296942187394494e289,
331 2.0044015765453026e291,
332 3.287218585534296e293,
333 5.423910666131589e295,
334 9.003691705778438e297,
335 1.503616514864999e300,
336 2.5260757449731984e302,
337 4.269068009004705e304,
338 7.257415615307999e306};
339
340//
341// Routine to return the factorial of j
342//
343RealType SphericalHarmonic::Fact(int j) {
344 if (j <= 170 && j >= 0) return factorial_list[j];
345
346 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH, "Fact(j) for j >= 171\n");
347 painCave.isFatal = 0;
348 simError();
349 return 0.;
350}
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.