QMCPACK
LatticeAnalyzer.h
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: Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
11 //
12 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
13 //////////////////////////////////////////////////////////////////////////////////////
14 
15 
16 #ifndef QMCPLUSPLUS_LATTICE_ANALYZER_H
17 #define QMCPLUSPLUS_LATTICE_ANALYZER_H
18 #include "OhmmsPETE/TinyVector.h"
19 namespace qmcplusplus
20 {
21 /** enumeration for DTD_BConds specialization
22  *
23  * G = general cell with image-cell checks
24  * S = special treatment of a general cell with Wigner-cell radius == Simulation cell
25  * O = orthogonal cell
26  * X = exhaustive search (reference implementation)
27  */
28 enum
29 {
38 };
39 
40 
41 ///generic class to analyze a Lattice
42 template<typename T, unsigned D>
44 {};
45 
46 /** specialization for 3D lattice
47 */
48 template<typename T>
49 struct LatticeAnalyzer<T, 3>
50 {
53  ///SuperCell type
54  int mySC;
55 
56  inline int operator()(const TinyVector<int, 3>& box) { return mySC = box[0] + 2 * (box[1] + box[2] * 2); }
57 
58  inline bool isDiagonalOnly(const Tensor_t& R) const
59  {
60  T offdiag = std::abs(R(0, 1)) + std::abs(R(0, 2)) + std::abs(R(1, 0)) + std::abs(R(1, 2)) + std::abs(R(2, 0)) +
61  std::abs(R(2, 1));
62  return (offdiag < std::numeric_limits<T>::epsilon());
63  }
64 
66  const SingleParticlePos& OneOverLength)
67  {
68  const T rad_to_deg = 180.0 / M_PI;
69  return SingleParticlePos(rad_to_deg * std::acos(dot(Rv[0], Rv[1]) * OneOverLength[0] * OneOverLength[1]),
70  rad_to_deg * std::acos(dot(Rv[1], Rv[2]) * OneOverLength[1] * OneOverLength[2]),
71  rad_to_deg * std::acos(dot(Rv[2], Rv[0]) * OneOverLength[2] * OneOverLength[0]));
72  }
73 
75  {
76  T rMin = 0.5 * std::numeric_limits<T>::max();
77  if (mySC == SUPERCELL_BULK || mySC == SUPERCELL_BULK + SOA_OFFSET) //bulk type
78  {
79  for (int i = -1; i <= 1; i++)
80  for (int j = -1; j <= 1; j++)
81  for (int k = -1; k <= 1; k++)
82  if (i || j || k)
83  {
84  SingleParticlePos L = (static_cast<T>(i) * a[0] + static_cast<T>(j) * a[1] + static_cast<T>(k) * a[2]);
85  rMin = std::min(rMin, dot(L, L));
86  }
87  }
88  else if (mySC == SUPERCELL_SLAB || mySC == SUPERCELL_SLAB + SOA_OFFSET) //slab type
89  {
90  for (int i = -1; i <= 1; i++)
91  for (int j = -1; j <= 1; j++)
92  if (i || j)
93  {
94  SingleParticlePos L = (static_cast<T>(i) * a[0] + static_cast<T>(j) * a[1]);
95  rMin = std::min(rMin, dot(L, L));
96  }
97  }
98  else if (mySC == SUPERCELL_WIRE || mySC == SUPERCELL_WIRE + SOA_OFFSET) //wire
99  {
100  rMin = dot(a[0], a[0]);
101  }
102  return 0.5 * std::sqrt(rMin);
103  }
104 
106  {
107  T scr = 0.5 * std::numeric_limits<T>::max();
108  //if(mySC == SUPERCELL_BULK)
109  //{
110  for (int i = 0; i < 3; ++i)
111  {
112  SingleParticlePos A = a[i];
113  SingleParticlePos B = a[(i + 1) % 3];
114  SingleParticlePos C = a[(i + 2) % 3];
115  SingleParticlePos BxC = cross(B, C);
116  T dist = 0.5 * std::abs(dot(A, BxC)) / std::sqrt(dot(BxC, BxC));
117  scr = std::min(scr, dist);
118  }
119  //}
120  //else if(mySC == SUPERCELL_SLAB)
121  //{
122  // T a0mag = std::sqrt(dot(a[0],a[0]));
123  // T a1mag = std::sqrt(dot(a[1],a[1]));
124  // scr=0.5*std::min(a0mag,a1mag);
125  // //T dist = 0.5*std::abs(dot(A,BxC))/std::sqrt(dot(BxC,BxC));
126  // //T theta1 = dot (a[0], a[1])/(a0mag*a1mag);
127  // //T theta2 = M_PI - theta1;
128  // //T theta = std::min (theta1, theta2);
129  // //T dist = std::min (a0mag, a1mag);
130  // //scr=0.5*std::sin(theta)*dist;
131  // std::cout << " calcSimulationCellRadius for Slab" << std::endl;
132  //}
133  //else if(mySC == SUPERCELL_WIRE)
134  //{
135  // scr=0.5*std::sqrt(dot(a[0],a[0]));
136  //}
137  return scr;
138  }
139 };
140 
141 /** specialization for 2D lattice
142 */
143 template<typename T>
144 struct LatticeAnalyzer<T, 2>
145 {
148 
149  /** return supercell enum
150  * @param[in] box[2] if box[i]==1, PBC
151  * @return SUPERCELL_OPEN or SUPERCELL_BULK
152  */
153  inline int operator()(const TinyVector<int, 2>& box)
154  {
155  return (box[0] + 2 * box[1]) ? SUPERCELL_BULK : SUPERCELL_OPEN;
156  }
157 
158  inline bool isDiagonalOnly(const Tensor<T, 2>& R) const
159  {
160  T offdiag = std::abs(R(0, 1)) + std::abs(R(1, 0));
161  return (offdiag < std::numeric_limits<T>::epsilon());
162  }
163 
165  const SingleParticlePos& OneOverLength)
166  {
167  const T rad_to_deg = 180.0 / M_PI;
168  return SingleParticlePos(rad_to_deg * std::acos(dot(Rv[0], Rv[1]) * OneOverLength[0] * OneOverLength[1]), 0.0);
169  }
170 
172  {
173  T rMin;
174  T dotP = dot(a[0], a[1]);
175  SingleParticlePos L0 = a[0] - dotP * a[1];
176  SingleParticlePos L1 = a[1] - dotP * a[0];
177  rMin = 0.5 * std::min(std::sqrt(dot(L0, L0)), std::sqrt(dot(L1, L1)));
178  return rMin;
179  }
180 
182  {
183  T a0mag = std::sqrt(dot(a[0], a[0]));
184  T a1mag = std::sqrt(dot(a[1], a[1]));
185  T theta1 = std::acos(dot(a[0], a[1]) / (a0mag * a1mag));
186  T theta2 = M_PI - theta1;
187  T theta = std::min(theta1, theta2);
188  T dist = std::min(a0mag, a1mag);
189  return 0.5 * std::sin(theta) * dist;
190  // return calcWignerSeitzRadius(a);
191  }
192 };
193 
194 /** specialization for 1D lattice
195 */
196 template<typename T>
197 struct LatticeAnalyzer<T, 1>
198 {
200  inline bool isDiagonalOnly(const Tensor<T, 1>& R) const { return true; }
201 
202  inline int operator()(const TinyVector<int, 1>& box) { return (box[0]) ? SUPERCELL_BULK : SUPERCELL_OPEN; }
203 
204  inline T calcWignerSeitzRadius(TinyVector<SingleParticlePos, 1>& a) { return a[0] * 0.5; }
205 };
206 
207 template<typename T>
209 {
210  const T eps = 10.0 * std::numeric_limits<T>::epsilon();
211  int imax = 0;
212  T r2max = dot(rb[0], rb[0]);
213  for (int i = 1; i < 3; i++)
214  {
215  T r2 = dot(rb[i], rb[i]);
216  if ((r2 - r2max) > eps)
217  {
218  r2max = r2;
219  imax = i;
220  }
221  }
222 
223  T rmax = std::sqrt(r2max);
224  T tol = 4.0 * rmax * eps; // Error propagation for x^2
225 
226  TinyVector<TinyVector<T, 3>, 4> rb_new;
227  rb_new[0] = rb[0] + rb[1] - rb[2];
228  rb_new[1] = rb[0] + rb[2] - rb[1];
229  rb_new[2] = rb[1] + rb[2] - rb[0];
230  rb_new[3] = rb[0] + rb[1] + rb[2];
231  for (int i = 0; i < 4; ++i)
232  {
233  T r2 = dot(rb_new[i], rb_new[i]);
234  if ((r2 - r2max) < -tol)
235  {
236  rb[imax] = rb_new[i];
237  return true;
238  }
239  }
240  return false;
241 }
242 template<typename T>
244 {
245  int maxIter = 10000;
246 
247  for (int count = 0; count < maxIter; count++)
248  {
249  TinyVector<TinyVector<T, 3>, 3> saved(rb);
250  bool changed = false;
251  for (int i = 0; i < 3; ++i)
252  {
253  rb[i] = 0.0;
254  changed = found_shorter_base(rb);
255  rb[i] = saved[i];
256  if (changed)
257  break;
258  }
259  if (!changed && !found_shorter_base(rb))
260  return;
261  }
262 
263  throw std::runtime_error("Reduced basis not found in allowed number of iterations. "
264  "Check unit cell or contact a developer.");
265 }
266 
267 } // namespace qmcplusplus
268 #endif
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
bool isDiagonalOnly(const Tensor< T, 2 > &R) const
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
MakeReturn< UnaryNode< FnSin, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sin(const Vector< T1, C1 > &l)
T calcWignerSeitzRadius(TinyVector< SingleParticlePos, 3 > &a)
T calcSimulationCellRadius(TinyVector< SingleParticlePos, 2 > &a)
int operator()(const TinyVector< int, 3 > &box)
T calcSimulationCellRadius(TinyVector< SingleParticlePos, 3 > &a)
T calcWignerSeitzRadius(TinyVector< SingleParticlePos, 2 > &a)
bool found_shorter_base(TinyVector< TinyVector< T, 3 >, 3 > &rb)
bool isDiagonalOnly(const Tensor_t &R) const
T min(T a, T b)
bool isDiagonalOnly(const Tensor< T, 1 > &R) const
SingleParticlePos calcSolidAngles(const TinyVector< SingleParticlePos, 2 > &Rv, const SingleParticlePos &OneOverLength)
Tensor<T,D> class for D by D tensor.
Definition: OhmmsTinyMeta.h:32
MakeReturn< UnaryNode< FnArcCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t acos(const Vector< T1, C1 > &l)
int operator()(const TinyVector< int, 2 > &box)
return supercell enum
T calcWignerSeitzRadius(TinyVector< SingleParticlePos, 1 > &a)
void find_reduced_basis(TinyVector< TinyVector< T, 3 >, 3 > &rb)
TinyVector< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > cross(const TinyVector< T1, D > &lhs, const TinyVector< T2, D > &rhs)
Definition: TinyVector.h:200
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
generic class to analyze a Lattice
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
double B(double x, int k, int i, const std::vector< double > &t)
SingleParticlePos calcSolidAngles(const TinyVector< SingleParticlePos, 3 > &Rv, const SingleParticlePos &OneOverLength)
int operator()(const TinyVector< int, 1 > &box)