1#ifndef SEAMS_STEINHARDT_DEVICE_H_
2#define SEAMS_STEINHARDT_DEVICE_H_
14#ifdef SEAMS_HAS_OFFLOAD
15#pragma omp declare target
21inline void minImage(
double &dx,
double &dy,
double &dz,
double bx,
double by,
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;
205inline void ylmAllTrig(
int orderL,
double sinT,
double cosT,
double cphi,
206 double sphi,
double *out) {
207 const int nComp = 2 * orderL + 1;
208 for (
int k = 0; k < nComp; k++) {
210 out[2 * k + 1] = 0.0;
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];
244inline void ylmAll(
int orderL,
double theta,
double phi,
double *out) {
245 ylmAllTrig(orderL, std::sin(theta), std::cos(theta), std::cos(phi),
252inline void qlmAddBond(
int orderL,
double dx,
double dy,
double dz,
253 double *qlmInterleaved,
int row,
int nComp,
255 const double r2 = dx * dx + dy * dy + dz * dz;
259 const double r = std::sqrt(r2);
260 const double invr = 1.0 / r;
261 double cosT = dz * invr;
264 }
else if (cosT < -1.0) {
267 const double rho2 = dx * dx + dy * dy;
272 const double rho = std::sqrt(rho2);
274 const double invrho = 1.0 / rho;
279 ylmAllTrig(orderL, sinT, cosT, cphi, sphi, ylm);
280 for (
int m = 0; m < nComp; m++) {
281 qlmInterleaved[2 * (row + m)] += ylm[2 * m];
282 qlmInterleaved[2 * (row + m) + 1] += ylm[2 * m + 1];
289inline void qlmOneAtom(
int iatom,
int orderL,
const double *xyz,
290 const int *offsets,
const int *cols,
double bx,
291 double by,
double bz,
double *qlmInterleaved) {
295 const int nComp = 2 * orderL + 1;
296 const int iOff = 3 * iatom;
297 const int row = iatom * nComp;
298 for (
int m = 0; m < nComp; m++) {
299 qlmInterleaved[2 * (row + m)] = 0.0;
300 qlmInterleaved[2 * (row + m) + 1] = 0.0;
302 const int j0 = offsets[iatom];
303 const int j1 = offsets[iatom + 1];
305 for (
int p = j0; p < j1; p++) {
306 const int jatom = cols[p];
307 const double dx = xyz[iOff] - xyz[3 * jatom];
308 const double dy = xyz[iOff + 1] - xyz[3 * jatom + 1];
309 const double dz = xyz[iOff + 2] - xyz[3 * jatom + 2];
310 qlmAddBond(orderL, dx, dy, dz, qlmInterleaved, row, nComp, nUsed);
315 const double inv = 1.0 /
static_cast<double>(nUsed);
316 for (
int m = 0; m < nComp; m++) {
317 qlmInterleaved[2 * (row + m)] *= inv;
318 qlmInterleaved[2 * (row + m) + 1] *= inv;
325 const int *offsets,
const int *cols,
326 double *qlmInterleaved) {
327 const int nComp = 2 * orderL + 1;
328 const int row = iatom * nComp;
329 for (
int m = 0; m < nComp; m++) {
330 qlmInterleaved[2 * (row + m)] = 0.0;
331 qlmInterleaved[2 * (row + m) + 1] = 0.0;
333 const int j0 = offsets[iatom];
334 const int j1 = offsets[iatom + 1];
336 for (
int p = j0; p < j1; p++) {
337 qlmAddBond(orderL, dr[3 * p], dr[3 * p + 1], dr[3 * p + 2],
338 qlmInterleaved, row, nComp, nUsed);
343 const double inv = 1.0 /
static_cast<double>(nUsed);
344 for (
int m = 0; m < nComp; m++) {
345 qlmInterleaved[2 * (row + m)] *= inv;
346 qlmInterleaved[2 * (row + m) + 1] *= inv;
350inline void qlOneAtom(
int iatom,
int orderL,
const double *qlmInterleaved,
351 const int *offsets,
const int *cols,
double *ql,
353 constexpr double pi = 3.14159265358979323846;
354 const int nComp = 2 * orderL + 1;
355 const double prefactor = 4.0 * pi / (2.0 * orderL + 1.0);
356 const int row = iatom * nComp;
357 double sumLocal = 0.0;
358 for (
int m = 0; m < nComp; m++) {
359 const double re = qlmInterleaved[2 * (row + m)];
360 const double im = qlmInterleaved[2 * (row + m) + 1];
361 sumLocal += re * re + im * im;
363 ql[iatom] = std::sqrt(prefactor * sumLocal);
365 const int j0 = offsets[iatom];
366 const int j1 = offsets[iatom + 1];
368 qlBar[iatom] = ql[iatom];
373 for (
int m = 0; m < nComp; m++) {
374 barRe[m] = qlmInterleaved[2 * (row + m)];
375 barIm[m] = qlmInterleaved[2 * (row + m) + 1];
378 for (
int p = j0; p < j1; p++) {
379 const int jatom = cols[p];
380 const int jRow = jatom * nComp;
381 for (
int m = 0; m < nComp; m++) {
382 barRe[m] += qlmInterleaved[2 * (jRow + m)];
383 barIm[m] += qlmInterleaved[2 * (jRow + m) + 1];
387 const double inv = 1.0 /
static_cast<double>(nContrib);
389 for (
int m = 0; m < nComp; m++) {
390 const double re = barRe[m] * inv;
391 const double im = barIm[m] * inv;
392 sumBar += re * re + im * im;
394 qlBar[iatom] = std::sqrt(prefactor * sumBar);
400#ifdef SEAMS_HAS_OFFLOAD
401#pragma omp end declare target
void qlmOneAtom(int iatom, int orderL, const double *xyz, const int *offsets, const int *cols, double bx, double by, double bz, double *qlmInterleaved)
double legendreAmp(int orderL, int absM, const double *s, const double *c)
void minImage(double &dx, double &dy, double &dz, double bx, double by, double bz)
void qlmOneAtomDr(int iatom, int orderL, const double *dr, const int *offsets, const int *cols, double *qlmInterleaved)
void qlOneAtom(int iatom, int orderL, const double *qlmInterleaved, const int *offsets, const int *cols, double *ql, double *qlBar)
void ylmAll(int orderL, double theta, double phi, double *out)
double normLM(int orderL, int absM)
void qlmAddBond(int orderL, double dx, double dy, double dz, double *qlmInterleaved, int row, int nComp, int &nUsed)
void ylmAllTrig(int orderL, double sinT, double cosT, double cphi, double sphi, double *out)