forked from abacusmodeling/abacus-develop
-
Notifications
You must be signed in to change notification settings - Fork 245
Expand file tree
/
Copy pathphi_operator_kernel.cuh
More file actions
372 lines (345 loc) · 14.2 KB
/
Copy pathphi_operator_kernel.cuh
File metadata and controls
372 lines (345 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#pragma once
#include <cuda_runtime.h>
#include "gint_helper.cuh"
#include "sph.cuh"
#include "source_base/module_device/kernel_compat.h"
// The template kernels below are defined in this header (not in the .cu) on
// purpose: in whole-program compilation mode (-rdc=false, the default), nvcc
// gives the host-side stubs of __global__ function templates internal linkage
// (forced since CUDA 13 via -static-global-template-stub=true), so every
// <<<...>>> launch of a template kernel must see its definition in the same
// translation unit. Non-template kernels keep external linkage and stay in
// phi_operator_kernel.cu.
namespace ModuleGint
{
// Templated version: internal computation in double, output cast to Real
template<typename Real>
__global__ void set_phi_kernel(
const int nwmax,
const int mgrids_num,
const int nrmax,
const double dr_uniform,
const int* __restrict__ ucell_atom_nwl,
const bool* __restrict__ atom_iw2_new,
const int* __restrict__ atom_iw2_ylm,
const int* __restrict__ atom_nw,
const int* __restrict__ iat2it,
const double* __restrict__ rcut,
const double* __restrict__ psi_u,
const double* __restrict__ dpsi_u,
const double3* __restrict__ mgrids_pos,
const int* __restrict__ atoms_iat,
const double3* __restrict__ atom_rcoords,
const int2* __restrict__ atoms_num_info,
const int* __restrict__ atom_phi_start,
const int* __restrict__ bgrid_phi_len,
Real* __restrict__ phi)
{
const int bgrid_id = blockIdx.y;
const int mgrid_id = blockIdx.x;
const int atoms_num = atoms_num_info[bgrid_id].x;
const int pre_atoms_num = atoms_num_info[bgrid_id].y;
const double3 mgrid_pos = mgrids_pos[mgrid_id];
for (int atom_id = threadIdx.x; atom_id < atoms_num; atom_id += blockDim.x)
{
const int atom_type = iat2it[atoms_iat[atom_id + pre_atoms_num]];
const double3 rcoord = atom_rcoords[atom_id + pre_atoms_num]; // rcoord is the ralative coordinate of an atom and a biggrid
const double3 coord = make_double3(mgrid_pos.x-rcoord.x, // coord is the relative coordinate of an atom and a meshgrid
mgrid_pos.y-rcoord.y,
mgrid_pos.z-rcoord.z);
// Preserve the existing near-origin behavior. Only the exact
// atomic grid point follows the CPU direct-recurrence semantics.
const bool exact_origin
= (coord.x == 0.0 && coord.y == 0.0 && coord.z == 0.0);
double dist = norm3d(coord.x, coord.y, coord.z);
if (dist < rcut[atom_type])
{
if (dist < 1.0E-9)
{ dist += 1.0E-9; }
// since nwl is less or equal than 5, the size of ylma is (5+1)^2
double ylma[36];
const int nwl = ucell_atom_nwl[atom_type];
if (exact_origin)
{
ModuleBase::sph_harm_direct(
nwl, 0.0, 0.0, 0.0, ylma);
}
else
{
sph_harm(
nwl,
coord.x/dist,
coord.y/dist,
coord.z/dist,
ylma);
}
const double pos = dist / dr_uniform;
const int ip = static_cast<int>(pos);
const double dx = pos - ip;
const double dx2 = dx * dx;
const double dx3 = dx2 * dx;
const double c3 = 3.0 * dx2 - 2.0 * dx3;
const double c1 = 1.0 - c3;
const double c2 = (dx - 2.0 * dx2 + dx3) * dr_uniform;
const double c4 = (dx3 - dx2) * dr_uniform;
double psi = 0;
const int it_nw = atom_type * nwmax;
int iw_nr = it_nw * nrmax + ip;
int phi_idx = atom_phi_start[atom_id + pre_atoms_num] +
bgrid_phi_len[bgrid_id] * mgrid_id;
for (int iw = 0; iw < atom_nw[atom_type]; iw++, iw_nr += nrmax)
{
if (atom_iw2_new[it_nw + iw])
{
psi = c1 * psi_u[iw_nr] + c2 * dpsi_u[iw_nr]
+ c3 * psi_u[iw_nr + 1] + c4 * dpsi_u[iw_nr + 1];
}
phi[phi_idx + iw] = static_cast<Real>(psi * ylma[atom_iw2_ylm[it_nw + iw]]);
}
}
else
{
int phi_idx = atom_phi_start[atom_id + pre_atoms_num] +
bgrid_phi_len[bgrid_id] * mgrid_id;
for (int iw = 0; iw < atom_nw[atom_type]; iw++)
{
phi[phi_idx + iw] = Real(0.0);
}
}
}
}
// WantPhi == false: skip phi[] writes entirely (callers like gint_tau pass nullptr).
template<bool WantPhi>
__global__ void set_phi_dphi_kernel(
const int nwmax,
const int mgrids_num,
const int nrmax,
const double dr_uniform,
const int* __restrict__ ucell_atom_nwl,
const bool* __restrict__ atom_iw2_new,
const int* __restrict__ atom_iw2_ylm,
const int* __restrict__ atom_iw2_l,
const int* __restrict__ atom_nw,
const int* __restrict__ iat2it,
const double* __restrict__ rcut,
const double* __restrict__ psi_u,
const double* __restrict__ dpsi_u,
const double3* __restrict__ mgrids_pos,
const int* __restrict__ atoms_iat,
const double3* __restrict__ atom_rcoords,
const int2* __restrict__ atoms_num_info,
const int* __restrict__ atom_phi_start,
const int* __restrict__ bgrid_phi_len,
double* __restrict__ phi,
double* __restrict__ dphi_x,
double* __restrict__ dphi_y,
double* __restrict__ dphi_z)
{
const int bgrid_id = blockIdx.y;
const int mgrid_id = blockIdx.x;
const int atoms_num = atoms_num_info[bgrid_id].x;
const int pre_atoms_num = atoms_num_info[bgrid_id].y;
const double3 mgrid_pos = mgrids_pos[mgrid_id];
for (int atom_id = threadIdx.x; atom_id < atoms_num; atom_id += blockDim.x)
{
const int atom_type = iat2it[atoms_iat[atom_id + pre_atoms_num]];
const double3 rcoord = atom_rcoords[atom_id + pre_atoms_num];
const double3 coord = make_double3(mgrid_pos.x-rcoord.x,
mgrid_pos.y-rcoord.y,
mgrid_pos.z-rcoord.z);
double dist = norm3d(coord.x, coord.y, coord.z);
if (dist < rcut[atom_type])
{
if (dist < 1.0E-9)
{ dist += 1.0E-9; }
// since nwl is less or equal than 5, the size of rly is (5+1)^2
// size of grly = 36 * 3
double rly[36];
double grly[36 * 3];
const int nwl = ucell_atom_nwl[atom_type];
grad_rl_sph_harm(nwl, coord.x, coord.y, coord.z, rly, grly);
// interpolation
const double inv_dist = 1.0 / dist; // hoisted: re-used by every iw below
const double pos = dist / dr_uniform;
const int ip = static_cast<int>(pos);
const double x0 = pos - ip;
const double x1 = 1.0 - x0;
const double x2 = 2.0 - x0;
const double x3 = 3.0 - x0;
const double x12 = x1 * x2 / 6;
const double x03 = x0 * x3 / 2;
double tmp = 0;
double dtmp = 0;
const int it_nw = atom_type * nwmax;
int iw_nr = it_nw * nrmax + ip;
int phi_idx = atom_phi_start[atom_id + pre_atoms_num] +
bgrid_phi_len[bgrid_id] * mgrid_id;
for (int iw = 0; iw < atom_nw[atom_type]; iw++, iw_nr += nrmax)
{
if (atom_iw2_new[it_nw + iw])
{
tmp = x12 * (psi_u[iw_nr] * x3 + psi_u[iw_nr + 3] * x0)
+ x03 * (psi_u[iw_nr + 1] * x2 - psi_u[iw_nr + 2] * x1);
dtmp = x12 * (dpsi_u[iw_nr] * x3 + dpsi_u[iw_nr + 3] * x0)
+ x03 * (dpsi_u[iw_nr + 1] * x2 - dpsi_u[iw_nr + 2] * x1);
}
const int iw_l = atom_iw2_l[it_nw + iw];
const int idx_ylm = atom_iw2_ylm [it_nw + iw];
const double rl = ::pow_int(dist, iw_l);
const double inv_rl = 1.0 / rl;
const double tmprl = tmp * inv_rl;
if (WantPhi)
{
phi[phi_idx + iw] = tmprl * rly[idx_ylm];
}
// derivative of wave functions with respect to atom positions.
// (dtmp - tmp*iw_l/dist) / rl * rly / dist == (dtmp*inv_dist - tmp*iw_l*inv_dist^2) * inv_rl * rly
const double tmpdphi_rly = (dtmp * inv_dist - tmp * iw_l * inv_dist * inv_dist)
* inv_rl * rly[idx_ylm];
dphi_x[phi_idx + iw] = tmpdphi_rly * coord.x + tmprl * grly[idx_ylm * 3 + 0];
dphi_y[phi_idx + iw] = tmpdphi_rly * coord.y + tmprl * grly[idx_ylm * 3 + 1];
dphi_z[phi_idx + iw] = tmpdphi_rly * coord.z + tmprl * grly[idx_ylm * 3 + 2];
}
}
else
{
int phi_idx = atom_phi_start[atom_id + pre_atoms_num] +
bgrid_phi_len[bgrid_id] * mgrid_id;
for (int iw = 0; iw < atom_nw[atom_type]; iw++)
{
if (WantPhi)
{
phi[phi_idx + iw] = 0.0;
}
dphi_x[phi_idx + iw] = 0.0;
dphi_y[phi_idx + iw] = 0.0;
dphi_z[phi_idx + iw] = 0.0;
}
}
}
}
__global__ void set_ddphi_kernel(
const int nwmax,
const int mgrids_num,
const int nrmax,
const double dr_uniform,
const int* __restrict__ ucell_atom_nwl,
const bool* __restrict__ atom_iw2_new,
const int* __restrict__ atom_iw2_ylm,
const int* __restrict__ atom_iw2_l,
const int* __restrict__ atom_nw,
const int* __restrict__ iat2it,
const double* __restrict__ rcut,
const double* __restrict__ psi_u,
const double* __restrict__ dpsi_u,
const double3* __restrict__ mgrids_pos,
const int* __restrict__ atoms_iat,
const double3* __restrict__ atom_rcoords,
const int2* __restrict__ atoms_num_info,
const int* __restrict__ atom_phi_start,
const int* __restrict__ bgrid_phi_len,
double* __restrict__ ddphi_xx,
double* __restrict__ ddphi_xy,
double* __restrict__ ddphi_xz,
double* __restrict__ ddphi_yy,
double* __restrict__ ddphi_yz,
double* __restrict__ ddphi_zz);
template<typename Real>
__global__ void phi_mul_vldr3_kernel(
const Real* __restrict__ vl,
const Real dr3,
const Real* __restrict__ phi,
const int mgrids_per_bgrid,
const int* __restrict__ mgrid_lidx,
const int* __restrict__ bgrid_phi_len,
const int* __restrict__ bgrid_phi_start,
Real* __restrict__ result)
{
const int bgrid_id = blockIdx.y;
const int mgrid_id = blockIdx.x;
const int phi_len = bgrid_phi_len[bgrid_id];
const int phi_start = bgrid_phi_start[bgrid_id] + mgrid_id * phi_len;
const int batch_mgrid_id = bgrid_id * mgrids_per_bgrid + mgrid_id;
const Real vldr3 = vl[mgrid_lidx[batch_mgrid_id]] * dr3;
for(int i = threadIdx.x; i < phi_len; i += blockDim.x)
{
result[phi_start + i] = phi[phi_start + i] * vldr3;
}
}
// rho(ir) = \sum_{iwt} \phi_i(ir,iwt) * \phi_j^*(ir,iwt)
// each block calculate the dot product of phi_i and phi_j of a meshgrid.
// Inputs phi_i and phi_j can have different element types: in the rho path
// phi_i is fp32 (Real) while phi_j (phi_dm) is fp64; in the tau path both are
// fp64. The per-block reduction and atomicAdd to rho run in fp64 regardless.
template<typename Tin_a, typename Tin_b>
__global__ void phi_dot_phi_kernel(
const Tin_a* __restrict__ phi_i, // phi_i(ir,iwt)
const Tin_b* __restrict__ phi_j, // phi_j(ir,iwt)
const int mgrids_per_bgrid, // the number of mgrids of each biggrid
const int* __restrict__ mgrid_lidx, // the idx of mgrid in local cell
const int* __restrict__ bgrid_phi_len, // the length of phi on a mgrid of a biggrid
const int* __restrict__ bgrid_phi_start, // the start idx in phi of each biggrid
double* __restrict__ rho) // rho(ir)
{
__shared__ double s_data[32]; // the length of s_data equals the max warp num of a block
const int bgrid_id = blockIdx.y;
const int mgrid_id = blockIdx.x;
const int phi_len = bgrid_phi_len[bgrid_id];
const int phi_start = bgrid_phi_start[bgrid_id] + mgrid_id * phi_len;
const Tin_a* phi_i_mgrid = phi_i + phi_start;
const Tin_b* phi_j_mgrid = phi_j + phi_start;
const int batch_mgrid_id = bgrid_id * mgrids_per_bgrid + mgrid_id;
const int mgrid_local_idx = mgrid_lidx[batch_mgrid_id];
const int tid = threadIdx.x;
const int warp_id = tid / 32;
const int lane_id = tid % 32;
double tmp_sum = 0.0;
for (int i = tid; i < phi_len; i += blockDim.x)
{
tmp_sum += phi_i_mgrid[i] * phi_j_mgrid[i];
}
tmp_sum = warpReduceSum(tmp_sum);
if (lane_id == 0)
{
s_data[warp_id] = tmp_sum;
}
__syncthreads();
tmp_sum = (tid < blockDim.x / 32) ? s_data[tid] : 0.0;
if(warp_id == 0)
{
tmp_sum = warpReduceSum(tmp_sum);
}
if(tid == 0)
{
atomicAdd(&rho[mgrid_local_idx], tmp_sum);
}
}
__global__ void phi_dot_dphi_kernel(
const double* __restrict__ phi,
const double* __restrict__ dphi_x,
const double* __restrict__ dphi_y,
const double* __restrict__ dphi_z,
const int mgrids_per_bgrid,
const int* __restrict__ bgrid_phi_len,
const int2* __restrict__ atoms_num_info,
const int* __restrict__ atom_phi_start,
const int* __restrict__ atoms_iat,
const int* __restrict__ iat2it,
const int* __restrict__ atom_nw,
double* force);
__global__ void phi_dot_dphi_r_kernel(
const double* __restrict__ phi,
const double* __restrict__ dphi_x,
const double* __restrict__ dphi_y,
const double* __restrict__ dphi_z,
const int mgrids_per_bgrid,
const int* __restrict__ bgrid_phi_len,
const int2* __restrict__ atoms_num_info,
const int* __restrict__ atom_phi_start,
const int* __restrict__ atoms_iat,
const double3* __restrict__ atom_rcoords,
const double3* __restrict__ mgrids_pos,
const int* __restrict__ iat2it,
const int* __restrict__ atom_nw,
double* __restrict__ svl);
}