QMCPACK
KContainer.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
8 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
9 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
10 //
11 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
12 //////////////////////////////////////////////////////////////////////////////////////
13 
14 
15 #include "KContainer.h"
16 #include <map>
17 #include <cstdint>
18 #include "Message/Communicate.h"
19 #include "LRCoulombSingleton.h"
20 #include "Utilities/qmc_common.h"
21 
22 namespace qmcplusplus
23 {
25  RealType kc,
26  unsigned ndim,
27  const PosType& twist,
28  bool useSphere)
29 {
30  kcutoff = kc;
31  if (kcutoff <= 0.0)
32  {
33  APP_ABORT(" Illegal cutoff for KContainer");
34  }
35  findApproxMMax(lattice, ndim);
36  BuildKLists(lattice, twist, useSphere);
37 
38  app_log() << " KContainer initialised with cutoff " << kcutoff << std::endl;
39  app_log() << " # of K-shell = " << kshell.size() << std::endl;
40  app_log() << " # of K points = " << kpts.size() << std::endl;
41  app_log() << std::endl;
42 }
43 
45 {
46  //Estimate the size of the parallelpiped that encompasses a sphere of kcutoff.
47  //mmax is stored as integer translations of the reciprocal cell vectors.
48  //Does not require an orthorhombic cell.
49  /* Old method.
50  //2pi is not included in lattice.b
51  Matrix<RealType> mmat;
52  mmat.resize(3,3);
53  for(int j=0;j<3;j++)
54  for(int i=0;i<3;i++){
55  mmat[i][j] = 0.0;
56  for(int k=0;k<3;k++)
57  mmat[i][j] = mmat[i][j] + 4.0*M_PI*M_PI*lattice.b(k)[i]*lattice.b(j)[k];
58  }
59 
60  TinyVector<RealType,3> x,temp;
61  RealType tempr;
62  for(int idim=0;idim<3;idim++){
63  int i = ((idim)%3);
64  int j = ((idim+1)%3);
65  int k = ((idim+2)%3);
66 
67  x[i] = 1.0;
68  x[j] = (mmat[j][k]*mmat[k][i] - mmat[k][k]*mmat[i][j]);
69  x[j]/= (mmat[j][j]*mmat[k][k] - mmat[j][k]*mmat[j][k]);
70  x[k] = -(mmat[k][i] + mmat[j][k]*x[j])/mmat[k][k];
71 
72  for(i=0;i<3;i++){
73  temp[i] = 0.0;
74  for(j=0;j<3;j++)
75  temp[i] += mmat[i][j]*x[j];
76  }
77 
78  tempr = dot(x,temp);
79  mmax[idim] = static_cast<int>(sqrt(4.0*kcut2/tempr)) + 1;
80  }
81  */
82  // see rmm, Electronic Structure, p. 85 for details
83  for (int i = 0; i < DIM; i++)
84  mmax[i] = static_cast<int>(std::floor(std::sqrt(dot(lattice.a(i), lattice.a(i))) * kcutoff / (2 * M_PI))) + 1;
85 
86  mmax[DIM] = mmax[0];
87  for (int i = 1; i < DIM; ++i)
88  mmax[DIM] = std::max(mmax[i], mmax[DIM]);
89 
90  //overwrite the non-periodic directon to be zero
92  {
93  app_log() << " No kspace sum perpendicular to slab " << std::endl;
94  mmax[2] = 0;
95  }
96  if (ndim < 3)
97  {
98  app_log() << " No kspace sum along z " << std::endl;
99  mmax[2] = 0;
100  }
101  if (ndim < 2)
102  mmax[1] = 0;
103 }
104 
105 void KContainer::BuildKLists(const ParticleLayout& lattice, const PosType& twist, bool useSphere)
106 {
107  TinyVector<int, DIM + 1> TempActualMax;
109  TinyVector<RealType, DIM> kvec_cart;
110  RealType modk2;
111  std::vector<TinyVector<int, DIM>> kpts_tmp;
112  std::vector<PosType> kpts_cart_tmp;
113  std::vector<RealType> ksq_tmp;
114  // reserve the space for memory efficiency
115  if (useSphere)
116  {
117  const RealType kcut2 = kcutoff * kcutoff;
118  //Loop over guesses for valid k-points.
119  for (int i = -mmax[0]; i <= mmax[0]; i++)
120  {
121  kvec[0] = i;
122  for (int j = -mmax[1]; j <= mmax[1]; j++)
123  {
124  kvec[1] = j;
125  for (int k = -mmax[2]; k <= mmax[2]; k++)
126  {
127  kvec[2] = k;
128  //Do not include k=0 in evaluations.
129  if (i == 0 && j == 0 && k == 0)
130  continue;
131  //Convert kvec to Cartesian
132  kvec_cart = lattice.k_cart(kvec + twist);
133  //Find modk
134  modk2 = dot(kvec_cart, kvec_cart);
135  if (modk2 > kcut2)
136  continue; //Inside cutoff?
137  //This k-point should be added to the list
138  kpts_tmp.push_back(kvec);
139  kpts_cart_tmp.push_back(kvec_cart);
140  ksq_tmp.push_back(modk2);
141  //Update record of the allowed maximum translation.
142  for (int idim = 0; idim < 3; idim++)
143  if (std::abs(kvec[idim]) > TempActualMax[idim])
144  TempActualMax[idim] = std::abs(kvec[idim]);
145  }
146  }
147  }
148  }
149  else
150  {
151  // Loop over all k-points in the parallelpiped and add them to kcontainer
152  // note layout is for interfacing with fft, so for each dimension, the
153  // positive indexes come first then the negative indexes backwards
154  // e.g. 0, 1, .... mmax, -mmax+1, -mmax+2, ... -1
155  const int idimsize = mmax[0] * 2;
156  const int jdimsize = mmax[1] * 2;
157  const int kdimsize = mmax[2] * 2;
158  for (int i = 0; i < idimsize; i++)
159  {
160  kvec[0] = i;
161  if (kvec[0] > mmax[0])
162  kvec[0] -= idimsize;
163  for (int j = 0; j < jdimsize; j++)
164  {
165  kvec[1] = j;
166  if (kvec[1] > mmax[1])
167  kvec[1] -= jdimsize;
168  for (int k = 0; k < kdimsize; k++)
169  {
170  kvec[2] = k;
171  if (kvec[2] > mmax[2])
172  kvec[2] -= kdimsize;
173  // get cartesian location and modk2
174  kvec_cart = lattice.k_cart(kvec);
175  modk2 = dot(kvec_cart, kvec_cart);
176  // add k-point to lists
177  kpts_tmp.push_back(kvec);
178  kpts_cart_tmp.push_back(kvec_cart);
179  ksq_tmp.push_back(modk2);
180  }
181  }
182  }
183  // set allowed maximum translation
184  TempActualMax[0] = mmax[0];
185  TempActualMax[1] = mmax[1];
186  TempActualMax[2] = mmax[2];
187  }
188 
189  //Update a record of the number of k vectors
190  numk = kpts_tmp.size();
191  std::map<int64_t, std::vector<int>*> kpts_sorted;
192  //create the map: use simple integer with resolution of 0.00000001 in ksq
193  for (int ik = 0; ik < numk; ik++)
194  {
195  //This is a workaround for ewald bug (Issue #2105). Basically, 1e-7 is the resolution of |k|^2 for doubles,
196  //so we jack up the tolerance to match that.
197  const int64_t k_ind = static_cast<int64_t>(ksq_tmp[ik] * 10000000);
198  auto it(kpts_sorted.find(k_ind));
199  if (it == kpts_sorted.end())
200  {
201  std::vector<int>* newSet = new std::vector<int>;
202  kpts_sorted[k_ind] = newSet;
203  newSet->push_back(ik);
204  }
205  else
206  {
207  (*it).second->push_back(ik);
208  }
209  }
210  std::map<int64_t, std::vector<int>*>::iterator it(kpts_sorted.begin());
211  kpts.resize(numk);
212  kpts_cart.resize(numk);
213  kpts_cart_soa_.resize(numk);
214  ksq.resize(numk);
215  kshell.resize(kpts_sorted.size() + 1, 0);
216  int ok = 0, ish = 0;
217  while (it != kpts_sorted.end())
218  {
219  std::vector<int>::iterator vit((*it).second->begin());
220  while (vit != (*it).second->end())
221  {
222  int ik = (*vit);
223  kpts[ok] = kpts_tmp[ik];
224  kpts_cart[ok] = kpts_cart_tmp[ik];
225  kpts_cart_soa_(ok) = kpts_cart_tmp[ik];
226  ksq[ok] = ksq_tmp[ik];
227  ++vit;
228  ++ok;
229  }
230  kshell[ish + 1] = kshell[ish] + (*it).second->size();
231  ++it;
232  ++ish;
233  }
234  kpts_cart_soa_.updateTo();
235  it = kpts_sorted.begin();
236  std::map<int64_t, std::vector<int>*>::iterator e_it(kpts_sorted.end());
237  while (it != e_it)
238  {
239  delete it->second;
240  it++;
241  }
242  //Finished searching k-points. Copy list of maximum translations.
243  mmax[DIM] = 0;
244  for (int idim = 0; idim < DIM; idim++)
245  {
246  mmax[idim] = TempActualMax[idim];
247  mmax[DIM] = std::max(mmax[idim], mmax[DIM]);
248  //if(mmax[idim] > mmax[DIM]) mmax[DIM] = mmax[idim];
249  }
250  //Now fill the array that returns the index of -k when given the index of k.
251  minusk.resize(numk);
252 
253  //Assigns a unique hash value to each kpoint.
254  auto getHashOfVec = [](const auto& inpv, int hashparam) -> int64_t {
255  int64_t hash = 0; // this will cause integral promotion below
256  for (int i = 0; i < inpv.Size; ++i)
257  hash += inpv[i] + hash * hashparam;
258  return hash;
259  };
260 
261  // Create a map from the hash value for each k vector to the index
262  std::map<int64_t, int> hashToIndex;
263  for (int ki = 0; ki < numk; ki++)
264  {
265  hashToIndex[getHashOfVec(kpts[ki], numk)] = ki;
266  }
267  // Use the map to find the index of -k from the index of k
268  for (int ki = 0; ki < numk; ki++)
269  {
270  minusk[ki] = hashToIndex[getHashOfVec(-1 * kpts[ki], numk)];
271  }
272 }
273 
274 } // namespace qmcplusplus
a class that defines a supercell in D-dimensional Euclean space.
std::vector< PosType > kpts_cart
K-vector in Cartesian coordinates.
Definition: KContainer.h:53
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
VectorSoaContainer< RealType, DIM, OffloadAllocator< RealType > > kpts_cart_soa_
K-vector in Cartesian coordinates in SoA layout.
Definition: KContainer.h:94
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
std::ostream & app_log()
Definition: OutputManager.h:65
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > lattice
RealType kcutoff
The cutoff up to which k-vectors are generated.
Definition: KContainer.h:33
TinyVector< int, DIM+1 > mmax
maximum integer translations of reciprocal cell within kc.
Definition: KContainer.h:46
#define APP_ABORT(msg)
Widely used but deprecated fatal error macros from legacy code.
Definition: AppAbort.h:27
std::vector< int > kshell
kpts which belong to the ith-shell [kshell[i], kshell[i+1])
Definition: KContainer.h:61
void findApproxMMax(const ParticleLayout &lattice, unsigned ndim)
compute approximate parallelpiped that surrounds kc
Definition: KContainer.cpp:44
std::vector< int > minusk
Given a k index, return index to -k.
Definition: KContainer.h:59
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
std::vector< RealType > ksq
squre of kpts in Cartesian coordniates
Definition: KContainer.h:56
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
Define a LRHandler with two template parameters.
void updateKLists(const ParticleLayout &lattice, RealType kc, unsigned ndim, const PosType &twist=PosType(), bool useSphere=true)
k points sorted by the |k| excluding |k|=0
Definition: KContainer.cpp:24
std::vector< TinyVector< int, DIM > > kpts
K-vector in reduced coordinates.
Definition: KContainer.h:50
int numk
number of k-points
Definition: KContainer.h:40
static bool isQuasi2D()
return true if quasi 2D is selected
void BuildKLists(const ParticleLayout &lattice, const PosType &twist, bool useSphere)
construct the container for k-vectors
Definition: KContainer.cpp:105
MakeReturn< UnaryNode< FnFloor, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t floor(const Vector< T1, C1 > &l)