QMCPACK
MomentumDistribution.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) 2021 QMCPACK developers.
6 //
7 // File developed by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
8 //
9 // File refactored from: MomentumEstimator.cpp
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 #include "MomentumDistribution.h"
13 #include "CPU/e2iphi.h"
14 #include "TrialWaveFunction.h"
15 
16 #include <iostream>
17 #include <numeric>
18 
19 
20 namespace qmcplusplus
21 {
23  size_t np,
24  const PosType& twist_in,
25  const LatticeType& lattice,
26  DataLocality dl)
27  : OperatorEstBase(dl),
28  input_(std::move(mdi)),
29  twist(twist_in),
31  norm_nofK(1.0 / RealType(mdi.get_samples()))
32 {
33  psi_ratios.resize(np);
34 
36 
37  //dims of a grid for generating k points (obtained below)
38  int kgrid = 0;
39  // minimal length as 2 x WS radius.
40  RealType min_Length = Lattice.WignerSeitzRadius_G * 4.0 * M_PI;
41  PosType vec_length;
42  //length of reciprocal lattice vector
43  for (int i = 0; i < OHMMS_DIM; i++)
44  vec_length[i] = 2.0 * M_PI * std::sqrt(dot(Lattice.Gv[i], Lattice.Gv[i]));
45  RealType kmax = input_.get_kmax();
46  auto realCast = [](auto& real) { return static_cast<RealType>(real); };
47  PosType kmaxs = {realCast(input_.get_kmax0()), realCast(input_.get_kmax1()), realCast(input_.get_kmax2())};
48  RealType sum_kmaxs = kmaxs[0] + kmaxs[1] + kmaxs[2];
49  RealType sphere_kmax;
50  bool sphere = input_.get_kmax() > 0.0 ? true : false;
51  bool directional = sum_kmaxs > 0.0 ? true : false;
52  if (!sphere && !directional)
53  {
54  // default: kmax = 2 x k_F of polarized non-interacting electron system
55  kmax = 2.0 * std::pow(6.0 * M_PI * M_PI * np / Lattice.Volume, 1.0 / 3);
56  sphere = true;
57  }
58  sphere_kmax = kmax;
59  for (int i = 0; i < OHMMS_DIM; i++)
60  {
61  if (kmaxs[i] > kmax)
62  kmax = kmaxs[i];
63  }
64  kgrid = int(kmax / min_Length) + 1;
65  RealType kgrid_squared[OHMMS_DIM];
66  for (int i = 0; i < OHMMS_DIM; i++)
67  kgrid_squared[i] = kmaxs[i] * kmaxs[i] / vec_length[i] / vec_length[i];
68  RealType kmax_squared = sphere_kmax * sphere_kmax;
69  std::vector<int> kcount0;
70  std::vector<int> kcount1;
71  std::vector<int> kcount2;
72  kcount0.resize(2 * kgrid + 1, 0);
73  kcount1.resize(2 * kgrid + 1, 0);
74  kcount2.resize(2 * kgrid + 1, 0);
75  for (int i = -kgrid; i < (kgrid + 1); i++)
76  {
77  for (int j = -kgrid; j < (kgrid + 1); j++)
78  {
79  for (int k = -kgrid; k < (kgrid + 1); k++)
80  {
81  PosType ikpt, kpt;
82  ikpt[0] = i + twist[0];
83  ikpt[1] = j + twist[1];
84  ikpt[2] = k + twist[2];
85  //convert to Cartesian: note that 2Pi is multiplied
86  kpt = Lattice.k_cart(ikpt);
87  bool not_recorded = true;
88  // This collects the k-points within the parallelepiped (if enabled)
89  if (directional && ikpt[0] * ikpt[0] <= kgrid_squared[0] && ikpt[1] * ikpt[1] <= kgrid_squared[1] &&
90  ikpt[2] * ikpt[2] <= kgrid_squared[2])
91  {
92  kPoints.push_back(kpt);
93  kcount0[kgrid + i] = 1;
94  kcount1[kgrid + j] = 1;
95  kcount2[kgrid + k] = 1;
96  not_recorded = false;
97  }
98  // This collects the k-points within a sphere (if enabled and the k-point has not been recorded yet)
99  if (sphere && not_recorded &&
100  kpt[0] * kpt[0] + kpt[1] * kpt[1] + kpt[2] * kpt[2] <=
101  kmax_squared) //if (std::sqrt(kx*kx+ky*ky+kz*kz)<=sphere_kmax)
102  {
103  kPoints.push_back(kpt);
104  }
105  }
106  }
107  }
108  app_log() << "\n MomentumDistribution named " << my_name_ << "\n";
109  if (sphere && !directional)
110  {
111  app_log() << " Using all k-space points with (kx^2+ky^2+kz^2)^0.5 < " << sphere_kmax
112  << " for Momentum Distribution." << std::endl;
113  app_log() << " Total number of k-points for Momentum Distribution is " << kPoints.size() << std::endl;
114  }
115  else if (directional && !sphere)
116  {
117  int sums[3];
118  sums[0] = 0;
119  sums[1] = 0;
120  sums[2] = 0;
121  for (int i = 0; i < 2 * kgrid + 1; i++)
122  {
123  sums[0] += kcount0[i];
124  sums[1] += kcount1[i];
125  sums[2] += kcount2[i];
126  }
127  app_log() << " Using all k-space points within cut-offs " << input_.get_kmax0() << ", " << input_.get_kmax1()
128  << ", " << input_.get_kmax2() << " for Momentum Distribution." << std::endl;
129  app_log() << " Total number of k-points for Momentum Distribution: " << kPoints.size() << std::endl;
130  app_log() << " Number of grid points in kmax0 direction: " << sums[0] << std::endl;
131  app_log() << " Number of grid points in kmax1 direction: " << sums[1] << std::endl;
132  app_log() << " Number of grid points in kmax2 direction: " << sums[2] << std::endl;
133  }
134  else
135  {
136  int sums[3];
137  sums[0] = 0;
138  sums[1] = 0;
139  sums[2] = 0;
140  for (int i = 0; i < 2 * kgrid + 1; i++)
141  {
142  sums[0] += kcount0[i];
143  sums[1] += kcount1[i];
144  sums[2] += kcount2[i];
145  }
146  app_log() << " Using all k-space points with (kx^2+ky^2+kz^2)^0.5 < " << sphere_kmax << ", and" << std::endl;
147  app_log() << " within the cut-offs " << input_.get_kmax0() << ", " << input_.get_kmax1() << ", "
148  << input_.get_kmax2() << " for Momentum Distribution." << std::endl;
149  app_log() << " Total number of k-points for Momentum Distribution is " << kPoints.size() << std::endl;
150  app_log() << " The number of k-points within the cut-off region: " << sums[0] * sums[1] * sums[2] << std::endl;
151  app_log() << " Number of grid points in kmax0 direction: " << sums[0] << std::endl;
152  app_log() << " Number of grid points in kmax1 direction: " << sums[1] << std::endl;
153  app_log() << " Number of grid points in kmax2 direction: " << sums[2] << std::endl;
154  }
155  app_log() << " Number of samples: " << input_.get_samples() << std::endl;
156  app_log() << " My twist is: " << twist[0] << " " << twist[1] << " " << twist[2] << "\n\n";
157 
158  // resize arrays
159  nofK.resize(kPoints.size());
160  kdotp.resize(kPoints.size());
161  auto samples = input_.get_samples();
162  vPos.resize(samples);
163  phases.resize(kPoints.size());
164  phases_vPos.resize(samples);
165  for (int im = 0; im < samples; im++)
166  phases_vPos[im].resize(kPoints.size());
167  psi_ratios_all.resize(samples, psi_ratios.size());
168 
169  // allocate data storage
170  size_t data_size = nofK.size();
171  data_.resize(data_size, 0.0);
172 }
173 
175 {
176  data_locality_ = dl;
177 }
178 
179 std::unique_ptr<OperatorEstBase> MomentumDistribution::spawnCrowdClone() const
180 {
181  std::size_t data_size = data_.size();
182  auto spawn_data_locality = data_locality_;
183 
185  {
186  // This is just a stub until a memory saving optimization is deemed necessary
187  spawn_data_locality = DataLocality::queue;
188  data_size = 0;
189  throw std::runtime_error("There is no memory savings implementation for MomentumDistribution");
190  }
191 
192  auto spawn = std::make_unique<MomentumDistribution>(*this, spawn_data_locality);
193  spawn->get_data().resize(data_size);
194  return spawn;
195 }
196 
197 //MomentumDistribution::MomentumDistribution(const MomentumDistribution& md)
198 // : OperatorEstBase(md),
199 // input_(std::move(md.input_))
200 //{
201 // if (data_locality_ == DataLocality::crowd)
202 // {
203 // app_log()<<"MD::cons dl crowd\n";
204 // size_t data_size = md.data_->size();
205 // data_ = createLocalData(data_size, data_locality_);
206 // }
207 // else if (data_locality_ == DataLocality::rank)
208 // {
209 // app_log()<<"MD::cons dl rank\n";
210 // assert(md.data_locality_ == DataLocality::rank);
211 // size_t data_size = 10; // jtk fix
212 // data_locality_ = DataLocality::queue;
213 // data_ = createLocalData(data_size, data_locality_);
214 // }
215 // else
216 // app_log()<<"MD::cons dl other\n";
217 //}
218 
220 {
221  //if (data_locality_ == DataLocality::rank)
222  //{
223  // app_log()<<"MD::startBlock dl rank\n";
224  // size_t data_size = 10; // jtk fix
225  // data_->reserve(data_size);
226  // data_->resize(0);
227  //}
228  //else
229  // app_log()<<"MD::startBlock dl other\n";
230 }
231 
232 /** Gets called every step and writes to thread local data.
233  *
234  */
236  const RefVector<ParticleSet>& psets,
237  const RefVector<TrialWaveFunction>& wfns,
238  const RefVector<QMCHamiltonian>& hams,
240 {
241  for (int iw = 0; iw < walkers.size(); ++iw)
242  {
243  MCPWalker& walker = walkers[iw];
244  ParticleSet& pset = psets[iw];
245  TrialWaveFunction& psi = wfns[iw];
246  RealType weight = walker.Weight;
247 
248  const int np = pset.getTotalNum();
249  const int nk = kPoints.size();
250 
251  // accumulate weight
252  // (required by all estimators, otherwise inf results)
253  walkers_weight_ += weight;
254 
255  auto samples = input_.get_samples();
256  // compute phase factors
257  for (int s = 0; s < samples; ++s)
258  {
259  PosType newpos;
260  for (int i = 0; i < OHMMS_DIM; ++i)
261  newpos[i] = rng();
262  //make it cartesian
263  vPos[s] = Lattice.toCart(newpos);
264  pset.makeVirtualMoves(vPos[s]);
266  for (int i = 0; i < np; ++i)
267  psi_ratios_all[s][i] = psi_ratios[i];
268 
269  for (int ik = 0; ik < nk; ++ik)
270  kdotp[ik] = -dot(kPoints[ik], vPos[s]);
271  eval_e2iphi(nk, kdotp.data(), phases_vPos[s].data(0), phases_vPos[s].data(1));
272  }
273 
274  // update n(k)
275  std::fill_n(nofK.begin(), nk, RealType(0));
276  for (int i = 0; i < np; ++i)
277  {
278  for (int ik = 0; ik < nk; ++ik)
279  kdotp[ik] = dot(kPoints[ik], pset.R[i]);
280  eval_e2iphi(nk, kdotp.data(), phases.data(0), phases.data(1));
281  for (int s = 0; s < samples; ++s)
282  {
283  const ComplexType one_ratio(psi_ratios_all[s][i]);
284  const RealType ratio_c = one_ratio.real();
285  const RealType ratio_s = one_ratio.imag();
286  const RealType* restrict phases_c = phases.data(0);
287  const RealType* restrict phases_s = phases.data(1);
288  const RealType* restrict phases_vPos_c = phases_vPos[s].data(0);
289  const RealType* restrict phases_vPos_s = phases_vPos[s].data(1);
290  RealType* restrict nofK_here = nofK.data();
291 #pragma omp simd aligned(nofK_here, phases_c, phases_s, phases_vPos_c, phases_vPos_s : QMC_SIMD_ALIGNMENT)
292  for (int ik = 0; ik < nk; ++ik)
293  nofK_here[ik] += (phases_c[ik] * phases_vPos_c[ik] - phases_s[ik] * phases_vPos_s[ik]) * ratio_c -
294  (phases_s[ik] * phases_vPos_c[ik] + phases_c[ik] * phases_vPos_s[ik]) * ratio_s;
295  }
296  }
297 
298  // accumulate data
299  for (int ik = 0; ik < nofK.size(); ++ik)
300  data_[ik] += weight * nofK[ik] * norm_nofK;
301  }
302 }
303 
304 
305 void MomentumDistribution::collect(const RefVector<OperatorEstBase>& type_erased_operator_estimators)
306 {
308  {
309  OperatorEstBase::collect(type_erased_operator_estimators);
310  }
311  else
312  {
313  throw std::runtime_error("You cannot call collect on a MomentumDistribution with this DataLocality");
314  }
315 }
316 
317 
319 {
320  using namespace std::string_literals;
321  //descriptor for the data, 1-D data
322  std::vector<int> ng(1);
323  //add nofk
324  ng[0] = nofK.size();
325  h5desc_.push_back({{"nofk"s}});
326  auto& h5o = h5desc_.back();
327  //h5o.set_dimensions(ng, my_index_);
328  h5o.set_dimensions(ng, 0); // JTK: doesn't seem right
329  h5o.addProperty(const_cast<std::vector<PosType>&>(kPoints), "kpoints", file);
330  h5o.addProperty(const_cast<std::vector<int>&>(kWeights), "kweights", file);
331 }
332 
333 
334 } // namespace qmcplusplus
void resize(size_type n, Type_t val=Type_t())
Resize the container.
Definition: OhmmsVector.h:166
a class that defines a supercell in D-dimensional Euclean space.
void evaluateRatiosAlltoOne(ParticleSet &P, std::vector< ValueType > &ratios)
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
Scalar_t WignerSeitzRadius_G
Wigner-Seitz cell radius in reciprocal space.
std::vector< ObservableHelper > h5desc_
void fill_n(T *x, size_t count, const T &value)
Definition: OMPstd.hpp:21
std::ostream & app_log()
Definition: OutputManager.h:65
std::unique_ptr< OperatorEstBase > spawnCrowdClone() const override
standard interface
std::vector< ValueType > psi_ratios
wavefunction ratios
Vector< RealType > kdotp
nofK internal
Class that collects momentum distribution of electrons.
void collect(const RefVector< OperatorEstBase > &operator_estimators) override
this allows the EstimatorManagerNew to reduce without needing to know the details of MomentumDistribu...
float real(const float &c)
real part of a scalar. Cannot be replaced by std::real due to AFQMC specific needs.
class to handle hdf file
Definition: hdf_archive.h:51
const char walkers[]
Definition: HDFVersion.h:36
void resize(size_type n, size_type m)
Resize the container.
Definition: OhmmsMatrix.h:99
DataLocality data_locality_
locality for accumulation of estimator data.
#define OHMMS_DIM
Definition: config.h:64
Matrix< ValueType > psi_ratios_all
wavefunction ratios all samples
MakeReturn< BinaryNode< FnPow, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t, typename CreateLeaf< Vector< T2, C2 > >::Leaf_t > >::Expression_t pow(const Vector< T1, C1 > &l, const Vector< T2, C2 > &r)
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > lattice
SingleParticlePos k_cart(const SingleParticlePos &kin) const
conversion of a reciprocal-vector
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
QMCT::FullPrecRealType walkers_weight_
void registerOperatorEstimator(hdf_archive &file) override
this allows the EstimatorManagerNew to reduce without needing to know the details of MomentumDistribu...
const RealType norm_nofK
normalization factor for n(k)
aligned_vector< RealType > nofK
nofK
Scalar_t Volume
Physical properties of a supercell.
std::vector< int > kWeights
weight of k-points (make use of symmetry)
An abstract class for gridded estimators.
std::vector< VectorSoaContainer< RealType, 2 > > phases_vPos
phases of vPos
Declaration of a TrialWaveFunction.
std::vector< std::reference_wrapper< T > > RefVector
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
std::vector< PosType > kPoints
list of k-points in Cartesian Coordinates
Class to represent a many-body trial wave function.
TinyVector< SingleParticlePos, D > Gv
Reciprocal unit vectors.
const MomentumDistributionInput input_
input values
VectorSoaContainer< RealType, 2 > phases
phases
DataLocality
data locality with respect to walker buffer
Definition: DataLocality.h:19
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
MomentumDistribution(MomentumDistributionInput &&mdi, size_t np, const PosType &twist, const LatticeType &lattice, DataLocality dl=DataLocality::crowd)
Constructor for MomentumDistributionInput.
SingleParticlePos toCart(const TinyVector< T1, D > &c) const
Convert a unit vector to a cartesian vector.
void startBlock(int steps) override
This allows us to allocate the necessary data for the DataLocality::queue.
void resize(size_type n)
resize myData
A container class to represent a walker.
Definition: Walker.h:49
Native representation for Momentum Distribution Estimators inputs.
void eval_e2iphi(int n, const T *restrict phi, T *restrict phase_r, T *restrict phase_i)
Definition: e2iphi.h:61
void accumulate(const RefVector< MCPWalker > &walkers, const RefVector< ParticleSet > &psets, const RefVector< TrialWaveFunction > &wfns, const RefVector< QMCHamiltonian > &hams, RandomBase< FullPrecRealType > &rng) override
accumulate 1 or more walkers of MomentumDistribution samples
virtual void collect(const RefVector< OperatorEstBase > &oebs)
Reduce estimator result data from crowds to rank.
std::string my_name_
name of this object – only used for debugging and h5 output