-
Notifications
You must be signed in to change notification settings - Fork 150
Expand file tree
/
Copy pathKContainer.cpp
More file actions
272 lines (256 loc) · 8.59 KB
/
KContainer.cpp
File metadata and controls
272 lines (256 loc) · 8.59 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
//////////////////////////////////////////////////////////////////////////////////////
// This file is distributed under the University of Illinois/NCSA Open Source License.
// See LICENSE file in top directory for details.
//
// Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
//
// File developed by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
// Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
// Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
//
// File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
//////////////////////////////////////////////////////////////////////////////////////
#include "KContainer.h"
#include <map>
#include <cstdint>
#include "Message/Communicate.h"
#include "LRCoulombSingleton.h"
#include "Utilities/qmc_common.h"
namespace qmcplusplus
{
void KContainer::updateKLists(const ParticleLayout& lattice,
RealType kc,
unsigned ndim,
const PosType& twist,
bool useSphere)
{
kcutoff = kc;
if (kcutoff <= 0.0)
{
APP_ABORT(" Illegal cutoff for KContainer");
}
findApproxMMax(lattice, ndim);
BuildKLists(lattice, twist, useSphere);
app_log() << " KContainer initialised with cutoff " << kcutoff << std::endl;
app_log() << " # of K-shell = " << kshell.size() << std::endl;
app_log() << " # of K points = " << kpts.size() << std::endl;
app_log() << std::endl;
}
void KContainer::findApproxMMax(const ParticleLayout& lattice, unsigned ndim)
{
//Estimate the size of the parallelpiped that encompasses a sphere of kcutoff.
//mmax is stored as integer translations of the reciprocal cell vectors.
//Does not require an orthorhombic cell.
/* Old method.
//2pi is not included in lattice.b
Matrix<RealType> mmat;
mmat.resize(3,3);
for(int j=0;j<3;j++)
for(int i=0;i<3;i++){
mmat[i][j] = 0.0;
for(int k=0;k<3;k++)
mmat[i][j] = mmat[i][j] + 4.0*M_PI*M_PI*lattice.b(k)[i]*lattice.b(j)[k];
}
TinyVector<RealType,3> x,temp;
RealType tempr;
for(int idim=0;idim<3;idim++){
int i = ((idim)%3);
int j = ((idim+1)%3);
int k = ((idim+2)%3);
x[i] = 1.0;
x[j] = (mmat[j][k]*mmat[k][i] - mmat[k][k]*mmat[i][j]);
x[j]/= (mmat[j][j]*mmat[k][k] - mmat[j][k]*mmat[j][k]);
x[k] = -(mmat[k][i] + mmat[j][k]*x[j])/mmat[k][k];
for(i=0;i<3;i++){
temp[i] = 0.0;
for(j=0;j<3;j++)
temp[i] += mmat[i][j]*x[j];
}
tempr = dot(x,temp);
mmax[idim] = static_cast<int>(sqrt(4.0*kcut2/tempr)) + 1;
}
*/
// see rmm, Electronic Structure, p. 85 for details
for (int i = 0; i < DIM; i++)
mmax[i] = static_cast<int>(std::floor(std::sqrt(dot(lattice.a(i), lattice.a(i))) * kcutoff / (2 * M_PI))) + 1;
mmax[DIM] = mmax[0];
for (int i = 1; i < DIM; ++i)
mmax[DIM] = std::max(mmax[i], mmax[DIM]);
//overwrite the non-periodic directon to be zero
if (LRCoulombSingleton::isQuasi2D())
{
app_log() << " No kspace sum perpendicular to slab " << std::endl;
mmax[2] = 0;
}
if (ndim < 3)
{
app_log() << " No kspace sum along z " << std::endl;
mmax[2] = 0;
}
if (ndim < 2)
mmax[1] = 0;
}
void KContainer::BuildKLists(const ParticleLayout& lattice, const PosType& twist, bool useSphere)
{
TinyVector<int, DIM + 1> TempActualMax;
TinyVector<int, DIM> kvec;
std::vector<TinyVector<int, DIM>> kpts_tmp;
std::vector<PosType> kpts_cart_tmp;
std::vector<RealType> ksq_tmp;
// reserve the space for memory efficiency
if (useSphere)
{
const RealType kcut2 = kcutoff * kcutoff;
//Loop over guesses for valid k-points.
for (int i = -mmax[0]; i <= mmax[0]; i++)
{
kvec[0] = i;
for (int j = -mmax[1]; j <= mmax[1]; j++)
{
kvec[1] = j;
for (int k = -mmax[2]; k <= mmax[2]; k++)
{
kvec[2] = k;
//Do not include k=0 in evaluations.
if (i == 0 && j == 0 && k == 0)
continue;
//Convert kvec to Cartesian
auto kvec_cart = lattice.k_cart(kvec + twist);
//Find modk
const auto modk2 = dot(kvec_cart, kvec_cart);
if (modk2 > kcut2)
continue; //Inside cutoff?
//This k-point should be added to the list
kpts_tmp.push_back(kvec);
kpts_cart_tmp.push_back(kvec_cart);
ksq_tmp.push_back(modk2);
//Update record of the allowed maximum translation.
for (int idim = 0; idim < 3; idim++)
if (std::abs(kvec[idim]) > TempActualMax[idim])
TempActualMax[idim] = std::abs(kvec[idim]);
}
}
}
}
else
{
// Loop over all k-points in the parallelpiped and add them to kcontainer
// note layout is for interfacing with fft, so for each dimension, the
// positive indexes come first then the negative indexes backwards
// e.g. 0, 1, .... mmax, -mmax+1, -mmax+2, ... -1
const int idimsize = mmax[0] * 2;
const int jdimsize = mmax[1] * 2;
const int kdimsize = mmax[2] * 2;
for (int i = 0; i < idimsize; i++)
{
kvec[0] = i;
if (kvec[0] > mmax[0])
kvec[0] -= idimsize;
for (int j = 0; j < jdimsize; j++)
{
kvec[1] = j;
if (kvec[1] > mmax[1])
kvec[1] -= jdimsize;
for (int k = 0; k < kdimsize; k++)
{
kvec[2] = k;
if (kvec[2] > mmax[2])
kvec[2] -= kdimsize;
// get cartesian location and modk2
auto kvec_cart = lattice.k_cart(kvec);
const auto modk2 = dot(kvec_cart, kvec_cart);
// add k-point to lists
kpts_tmp.push_back(kvec);
kpts_cart_tmp.push_back(kvec_cart);
ksq_tmp.push_back(modk2);
}
}
}
// set allowed maximum translation
TempActualMax[0] = mmax[0];
TempActualMax[1] = mmax[1];
TempActualMax[2] = mmax[2];
}
//Update a record of the number of k vectors
numk = kpts_tmp.size();
std::map<int64_t, std::vector<int>*> kpts_sorted;
//create the map: use simple integer with resolution of 0.00000001 in ksq
for (int ik = 0; ik < numk; ik++)
{
//This is a workaround for ewald bug (Issue #2105). Basically, 1e-7 is the resolution of |k|^2 for doubles,
//so we jack up the tolerance to match that.
const int64_t k_ind = static_cast<int64_t>(ksq_tmp[ik] * 10000000);
auto it(kpts_sorted.find(k_ind));
if (it == kpts_sorted.end())
{
std::vector<int>* newSet = new std::vector<int>;
kpts_sorted[k_ind] = newSet;
newSet->push_back(ik);
}
else
{
(*it).second->push_back(ik);
}
}
std::map<int64_t, std::vector<int>*>::iterator it(kpts_sorted.begin());
kpts.resize(numk);
kpts_cart.resize(numk);
kpts_cart_soa_.resize(numk);
ksq.resize(numk);
kshell.resize(kpts_sorted.size() + 1, 0);
int ok = 0, ish = 0;
while (it != kpts_sorted.end())
{
std::vector<int>::iterator vit((*it).second->begin());
while (vit != (*it).second->end())
{
int ik = (*vit);
kpts[ok] = kpts_tmp[ik];
kpts_cart[ok] = kpts_cart_tmp[ik];
kpts_cart_soa_(ok) = kpts_cart_tmp[ik];
ksq[ok] = ksq_tmp[ik];
++vit;
++ok;
}
kshell[ish + 1] = kshell[ish] + (*it).second->size();
++it;
++ish;
}
kpts_cart_soa_.updateTo();
it = kpts_sorted.begin();
std::map<int64_t, std::vector<int>*>::iterator e_it(kpts_sorted.end());
while (it != e_it)
{
delete it->second;
it++;
}
//Finished searching k-points. Copy list of maximum translations.
mmax[DIM] = 0;
for (int idim = 0; idim < DIM; idim++)
{
mmax[idim] = TempActualMax[idim];
mmax[DIM] = std::max(mmax[idim], mmax[DIM]);
//if(mmax[idim] > mmax[DIM]) mmax[DIM] = mmax[idim];
}
//Now fill the array that returns the index of -k when given the index of k.
minusk.resize(numk);
//Assigns a unique hash value to each kpoint.
auto getHashOfVec = [](const auto& inpv, int hashparam) -> int64_t {
int64_t hash = 0; // this will cause integral promotion below
for (int i = 0; i < inpv.Size; ++i)
hash += inpv[i] + hash * hashparam;
return hash;
};
// Create a map from the hash value for each k vector to the index
std::map<int64_t, int> hashToIndex;
for (int ki = 0; ki < numk; ki++)
{
hashToIndex[getHashOfVec(kpts[ki], numk)] = ki;
}
// Use the map to find the index of -k from the index of k
for (int ki = 0; ki < numk; ki++)
{
minusk[ki] = hashToIndex[getHashOfVec(-1 * kpts[ki], numk)];
}
}
} // namespace qmcplusplus