43inline double normLM(
int orderL,
int absM) {
44 constexpr double pi = 3.14159265358979323846;
48 return 0.25 * std::sqrt(7.0 / pi);
50 return 0.125 * std::sqrt(21.0 / pi);
52 return 0.25 * std::sqrt(105.0 / (2.0 * pi));
54 return 0.125 * std::sqrt(35.0 / pi);
62 return 0.1875 * std::sqrt(1.0 / pi);
64 return 0.375 * std::sqrt(5.0 / pi);
66 return 0.375 * std::sqrt(5.0 / (2.0 * pi));
68 return 0.375 * std::sqrt(35.0 / pi);
70 return 0.1875 * std::sqrt(35.0 / (2.0 * pi));
78 return 0.03125 * std::sqrt(13.0 / pi);
80 return 0.0625 * std::sqrt(273.0 / (2.0 * pi));
82 return 0.015625 * std::sqrt(1365.0 / pi);
84 return 0.03125 * std::sqrt(1365.0 / pi);
86 return 0.09375 * std::sqrt(91.0 / (2.0 * pi));
88 return 0.09375 * std::sqrt(1001.0 / pi);
90 return 0.015625 * std::sqrt(3003.0 / pi);
98 return std::sqrt(17.0 / (4.0 * pi));
100 return std::sqrt(17.0 / (288.0 * pi));
102 return std::sqrt(17.0 / (20160.0 * pi));
104 return std::sqrt(17.0 / (1330560.0 * pi));
106 return std::sqrt(17.0 / (79833600.0 * pi));
108 return std::sqrt(17.0 / (4151347200.0 * pi));
110 return std::sqrt(17.0 / (174356582400.0 * pi));
112 return std::sqrt(17.0 / (5230697472000.0 * pi));
114 return std::sqrt(17.0 / (83691159552000.0 * pi));
127 return 5.0 * c[3] - 3.0 * c[1];
129 return s[1] * (5.0 * c[2] - 1.0);
141 return 35.0 * c[4] - 30.0 * c[2] + 3.0;
143 return s[1] * (7.0 * c[3] - 3.0 * c[1]);
145 return s[2] * (7.0 * c[2] - 1.0);
157 return 231.0 * c[6] - 315.0 * c[4] + 105.0 * c[2] - 5.0;
159 return s[1] * (33.0 * c[5] - 30.0 * c[3] + 5.0 * c[1]);
161 return s[2] * (33.0 * c[4] - 18.0 * c[2] + 1.0);
163 return s[3] * (11.0 * c[3] - 3.0 * c[1]);
165 return s[4] * (11.0 * c[2] - 1.0);
177 return (35.0 + c[2] * (-1260.0 + c[2] * (6930.0 + c[2] * (-12012.0 + c[2] * 6435.0)))) / 128.0;
179 return s[1] * c[1] * (-315.0 + c[2] * (3465.0 + c[2] * (-9009.0 + c[2] * 6435.0))) / 16.0;
181 return s[2] * (-315.0 + c[2] * (10395.0 + c[2] * (-45045.0 + c[2] * 45045.0))) / 16.0;
183 return s[3] * c[1] * (10395.0 + c[2] * (-90090.0 + c[2] * 135135.0)) / 8.0;
185 return s[4] * (10395.0 + c[2] * (-270270.0 + c[2] * 675675.0)) / 8.0;
187 return s[5] * c[1] * (-135135.0 + c[2] * 675675.0) / 2.0;
189 return s[6] * (-135135.0 + c[2] * 2027025.0) / 2.0;
191 return s[7] * c[1] * 2027025.0;
193 return s[8] * 2027025.0;
202inline void ylmAll(
int orderL,
double theta,
double phi,
double *out) {
203 const int nComp = 2 * orderL + 1;
204 for (
int k = 0; k < nComp; k++) {
206 out[2 * k + 1] = 0.0;
213 const double sinT = std::sin(theta);
214 const double cosT = std::cos(theta);
215 const double cphi = std::cos(phi);
216 const double sphi = std::sin(phi);
221 for (
int k = 1; k <= orderL; k++) {
222 s[k] = s[k - 1] * sinT;
223 c[k] = c[k - 1] * cosT;
224 pr[k] = pr[k - 1] * cphi - pi[k - 1] * sphi;
225 pi[k] = pr[k - 1] * sphi + pi[k - 1] * cphi;
228 for (
int absM = 0; absM <= orderL; absM++) {
231 const double nre = amp * pr[absM];
232 const double nim = -amp * pi[absM];
233 const int ineg = orderL - absM;
235 out[2 * ineg + 1] = nim;
237 const double sign = (absM % 2 == 0) ? 1.0 : -1.0;
238 const int ipos = orderL + absM;
239 out[2 * ipos] = sign * amp * pr[absM];
240 out[2 * ipos + 1] = sign * amp * pi[absM];
245inline void qlmAddBond(
int orderL,
double dx,
double dy,
double dz,
246 double *qlmInterleaved,
int row,
int nComp,
248 const double r2 = dx * dx + dy * dy + dz * dz;
252 const double r = std::sqrt(r2);
253 const double phi = std::atan2(dx, dy);
254 const double theta = std::acos(dz / r);
256 ylmAll(orderL, theta, phi, ylm);
257 for (
int m = 0; m < nComp; m++) {
258 qlmInterleaved[2 * (row + m)] += ylm[2 * m];
259 qlmInterleaved[2 * (row + m) + 1] += ylm[2 * m + 1];
266inline void qlmOneAtom(
int iatom,
int orderL,
const double *xyz,
267 const int *offsets,
const int *cols,
double bx,
268 double by,
double bz,
double *qlmInterleaved) {
272 const int nComp = 2 * orderL + 1;
273 const int iOff = 3 * iatom;
274 const int row = iatom * nComp;
275 for (
int m = 0; m < nComp; m++) {
276 qlmInterleaved[2 * (row + m)] = 0.0;
277 qlmInterleaved[2 * (row + m) + 1] = 0.0;
279 const int j0 = offsets[iatom];
280 const int j1 = offsets[iatom + 1];
282 for (
int p = j0; p < j1; p++) {
283 const int jatom = cols[p];
284 const double dx = xyz[iOff] - xyz[3 * jatom];
285 const double dy = xyz[iOff + 1] - xyz[3 * jatom + 1];
286 const double dz = xyz[iOff + 2] - xyz[3 * jatom + 2];
287 qlmAddBond(orderL, dx, dy, dz, qlmInterleaved, row, nComp, nUsed);
292 const double inv = 1.0 /
static_cast<double>(nUsed);
293 for (
int m = 0; m < nComp; m++) {
294 qlmInterleaved[2 * (row + m)] *= inv;
295 qlmInterleaved[2 * (row + m) + 1] *= inv;
302 const int *offsets,
const int *cols,
303 double *qlmInterleaved) {
304 const int nComp = 2 * orderL + 1;
305 const int row = iatom * nComp;
306 for (
int m = 0; m < nComp; m++) {
307 qlmInterleaved[2 * (row + m)] = 0.0;
308 qlmInterleaved[2 * (row + m) + 1] = 0.0;
310 const int j0 = offsets[iatom];
311 const int j1 = offsets[iatom + 1];
313 for (
int p = j0; p < j1; p++) {
314 qlmAddBond(orderL, dr[3 * p], dr[3 * p + 1], dr[3 * p + 2],
315 qlmInterleaved, row, nComp, nUsed);
320 const double inv = 1.0 /
static_cast<double>(nUsed);
321 for (
int m = 0; m < nComp; m++) {
322 qlmInterleaved[2 * (row + m)] *= inv;
323 qlmInterleaved[2 * (row + m) + 1] *= inv;
327inline void qlOneAtom(
int iatom,
int orderL,
const double *qlmInterleaved,
328 const int *offsets,
const int *cols,
double *ql,
330 constexpr double pi = 3.14159265358979323846;
331 const int nComp = 2 * orderL + 1;
332 const double prefactor = 4.0 * pi / (2.0 * orderL + 1.0);
333 const int row = iatom * nComp;
334 double sumLocal = 0.0;
335 for (
int m = 0; m < nComp; m++) {
336 const double re = qlmInterleaved[2 * (row + m)];
337 const double im = qlmInterleaved[2 * (row + m) + 1];
338 sumLocal += re * re + im * im;
340 ql[iatom] = std::sqrt(prefactor * sumLocal);
342 const int j0 = offsets[iatom];
343 const int j1 = offsets[iatom + 1];
345 qlBar[iatom] = ql[iatom];
350 for (
int m = 0; m < nComp; m++) {
351 barRe[m] = qlmInterleaved[2 * (row + m)];
352 barIm[m] = qlmInterleaved[2 * (row + m) + 1];
355 for (
int p = j0; p < j1; p++) {
356 const int jatom = cols[p];
357 const int jRow = jatom * nComp;
358 for (
int m = 0; m < nComp; m++) {
359 barRe[m] += qlmInterleaved[2 * (jRow + m)];
360 barIm[m] += qlmInterleaved[2 * (jRow + m) + 1];
364 const double inv = 1.0 /
static_cast<double>(nContrib);
366 for (
int m = 0; m < nComp; m++) {
367 const double re = barRe[m] * inv;
368 const double im = barIm[m] * inv;
369 sumBar += re * re + im * im;
371 qlBar[iatom] = std::sqrt(prefactor * sumBar);