QMCPACK
EinsplineSetBuilderESHDF.fft.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) 2019 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 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
10 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
11 //
12 // File created by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
13 //////////////////////////////////////////////////////////////////////////////////////
14 
15 
16 #include "EinsplineSetBuilder.h"
17 #include "DistanceTable.h"
18 #include "OhmmsData/AttributeSet.h"
19 #include "Utilities/Timer.h"
20 #include "Message/Communicate.h"
21 #include "Message/CommOperators.h"
23 #include "Utilities/qmc_common.h"
24 
25 #include <array>
26 #include <string_view>
27 
28 namespace qmcplusplus
29 {
30 bool sortByIndex(BandInfo leftB, BandInfo rightB)
31 {
32  if (leftB.BandIndex == rightB.BandIndex)
33  {
34  if ((leftB.Energy < rightB.Energy + 1e-6) && (leftB.Energy > rightB.Energy - 1e-6))
35  return leftB.TwistIndex < rightB.TwistIndex;
36  else
37  return leftB.Energy < rightB.Energy;
38  }
39  else
40  return (leftB.BandIndex < rightB.BandIndex);
41 };
42 
44 {
45  if (!H5File.open(H5FileName, H5F_ACC_RDONLY))
46  {
47  app_error() << "Could not open HDF5 file \"" << H5FileName << "\" in EinsplineSetBuilder::ReadOrbitalInfo.\n";
48  return false;
49  }
50 
51  try
52  {
53  // Read format
54  std::string format;
55  H5File.read(format, "/format");
56  if (format.find("ES") == std::string::npos)
57  throw std::runtime_error("Format string input \"" + format + "\" doesn't contain \"ES\" keyword.");
58  Format = ESHDF;
59  H5File.read(Version, "/version");
60  app_log() << " HDF5 orbital file version " << Version[0] << "." << Version[1] << "." << Version[2] << std::endl;
61  }
62  catch (const std::exception& e)
63  {
64  app_error() << e.what() << std::endl
65  << "EinsplineSetBuilder::ReadOrbitalInfo h5 file format is too old or it is not a bspline orbital file!"
66  << std::endl;
67  return false;
68  }
69 
70  return ReadOrbitalInfo_ESHDF(skipChecks);
71 }
72 
74 {
75  app_log() << " Reading orbital file in ESHDF format.\n";
76  H5File.read(Version, "/version");
77  app_log() << " ESHDF orbital file version " << Version[0] << "." << Version[1] << "." << Version[2] << std::endl;
78  H5File.read(Lattice, "/supercell/primitive_vectors");
79  RecipLattice = 2.0 * M_PI * inverse(Lattice);
81  std::array<char, 1000> buff;
82  int length = std::snprintf(buff.data(), buff.size(),
83  " Lattice = \n [ %9.6f %9.6f %9.6f\n"
84  " %9.6f %9.6f %9.6f\n"
85  " %9.6f %9.6f %9.6f ]\n",
86  Lattice(0, 0), Lattice(0, 1), Lattice(0, 2), Lattice(1, 0), Lattice(1, 1), Lattice(1, 2),
87  Lattice(2, 0), Lattice(2, 1), Lattice(2, 2));
88  if (length < 0)
89  throw std::runtime_error("Error converting lattice to a string");
90  app_log() << std::string_view(buff.data(), length);
91  length =
92  std::snprintf(buff.data(), buff.size(),
93  " SuperLattice = \n [ %9.6f %9.6f %9.6f\n"
94  " %9.6f %9.6f %9.6f\n"
95  " %9.6f %9.6f %9.6f ]\n",
96  SuperLattice(0, 0), SuperLattice(0, 1), SuperLattice(0, 2), SuperLattice(1, 0), SuperLattice(1, 1),
97  SuperLattice(1, 2), SuperLattice(2, 0), SuperLattice(2, 1), SuperLattice(2, 2));
98  if (length < 0)
99  throw std::runtime_error("Error converting SuperLattice to a string");
100  app_log() << std::string_view(buff.data(), length) << std::endl;
101  if (!CheckLattice())
102  throw std::runtime_error("CheckLattice failed");
104  for (int i = 0; i < 3; i++)
105  for (int j = 0; j < 3; j++)
106  LatticeInv(i, j) = RecipLattice(i, j) / (2.0 * M_PI);
107  int have_dpsi = false;
108  NumTwists = NumSpins = NumBands = 0;
110  H5File.read(NumBands, "/electrons/kpoint_0/spin_0/number_of_states");
111  H5File.readEntry(NumSpins, "/electrons/number_of_spins");
112  H5File.read(NumTwists, "/electrons/number_of_kpoints");
113  H5File.readEntry(have_dpsi, "/electrons/have_dpsi");
114  HaveOrbDerivs = have_dpsi;
115  app_log() << "bands=" << NumBands << ", elecs=" << NumElectrons << ", spins=" << NumSpins << ", twists=" << NumTwists
116  << std::endl;
117  //////////////////////////////////
118  // Read ion types and locations //
119  //////////////////////////////////
120  Vector<int> species_ids;
121  H5File.read(species_ids, "/atoms/species_ids");
122  int num_species;
123  H5File.read(num_species, "/atoms/number_of_species");
124  std::vector<int> atomic_numbers(num_species);
125  for (int isp = 0; isp < num_species; isp++)
126  {
127  std::ostringstream name;
128  name << "/atoms/species_" << isp << "/atomic_number";
129  H5File.readEntry(atomic_numbers[isp], name.str());
130  }
131  IonTypes.resize(species_ids.size());
132  for (int i = 0; i < species_ids.size(); i++)
133  IonTypes[i] = atomic_numbers[species_ids[i]];
134  H5File.read(IonPos, "/atoms/positions");
135  for (int i = 0; i < IonTypes.size(); i++)
136  app_log() << "Atom type(" << i << ") = " << IonTypes[i] << std::endl;
137  /////////////////////////////////////
138  // Read atom orbital info from xml //
139  /////////////////////////////////////
140  // construct Super2Prim mapping.
141  if (Super2Prim.size() == 0)
142  {
143  //SourcePtcl->convert2Cart(SourcePtcl->R);
144  Super2Prim.resize(SourcePtcl->R.size(), -1);
145  std::vector<int> prim_atom_counts;
146  prim_atom_counts.resize(IonPos.size(), 0);
147  for (int i = 0; i < SourcePtcl->R.size(); i++)
148  {
150  for (int j = 0; j < IonPos.size(); j++)
151  {
152  PosType dr = PrimCell.toUnit_floor(IonPos[j]) - ref;
153  for (int k = 0; k < OHMMS_DIM; k++)
154  dr[k] -= round(dr[k]);
155  if (dot(dr, dr) < MatchingTol)
156  {
157  if (Super2Prim[i] < 0)
158  {
159  Super2Prim[i] = j;
160  prim_atom_counts[j]++;
161  }
162  else
163  {
164  app_error() << "Supercell ion " << i << " at " << SourcePtcl->R[j]
165  << " was found twice in the primitive cell as ion " << Super2Prim[i] << " and " << j
166  << std::endl;
167  if (!skipChecks)
168  abort();
169  }
170  }
171  }
172  if (Super2Prim[i] < 0)
173  {
174  app_error() << "Supercell ion " << i << " not found in the primitive cell" << std::endl;
175  if (!skipChecks)
176  abort();
177  }
178  else
179  {
180  //app_log() << "Supercell ion " << i << " mapped to primitive cell ion " << Super2Prim[i] << std::endl;
181  }
182  }
183  const int tiling_size = std::abs(det(TileMatrix));
184  for (int i = 0; i < IonPos.size(); i++)
185  if (prim_atom_counts[i] != tiling_size)
186  {
187  app_error() << "Primitive cell ion " << i << " was found only " << prim_atom_counts[i]
188  << " times in the supercell rather than " << tiling_size << std::endl;
189  if (!skipChecks)
190  abort();
191  }
192  // construct AtomicCentersInfo
194  for (int i = 0; i < IonPos.size(); i++)
196  const auto& source_species = SourcePtcl->getSpeciesSet();
197  int Zind = source_species.findAttribute("atomicnumber");
198  const int table_id = SourcePtcl->addTable(*SourcePtcl);
199  const auto& ii_table = SourcePtcl->getDistTable(table_id);
200  SourcePtcl->update(true);
201  for (int i = 0; i < IonPos.size(); i++)
202  {
203  AtomicCentersInfo.non_overlapping_radius[i] = std::numeric_limits<RealType>::max();
204  //should only call get_first_neighbor to set non_overlapping_radius if there are more than one atom in the cell
205  if (Super2Prim.size() == 1)
206  continue;
207  for (int j = 0; j < Super2Prim.size(); j++)
208  if (Super2Prim[j] == i)
209  {
210  // set GroupID for each ion in primitive cell
211  if ((Zind < 0) || (source_species(Zind, SourcePtcl->GroupID[j]) == IonTypes[i]))
213  else
214  {
215  app_error() << "Primitive cell ion " << i << " vs supercell ion " << j
216  << " atomic number not matching: " << IonTypes[i] << " vs "
217  << source_species(Zind, SourcePtcl->GroupID[j]) << std::endl;
218  if (!skipChecks)
219  abort();
220  }
221  // set non_overlapping_radius for each ion in primitive cell
222  RealType r(0);
223  PosType dr;
224  ii_table.get_first_neighbor(j, r, dr, false);
225  if (r < 1e-3)
226  APP_ABORT("EinsplineSetBuilder::ReadOrbitalInfo_ESHDF too close ions <1e-3 bohr!");
228  break;
229  }
230  }
231 
232  // load cutoff_radius, spline_radius, spline_npoints, lmax if exists.
233  const int inner_cutoff_ind = source_species.findAttribute("inner_cutoff");
234  const int cutoff_radius_ind = source_species.findAttribute("cutoff_radius");
235  const int spline_radius_ind = source_species.findAttribute("spline_radius");
236  const int spline_npoints_ind = source_species.findAttribute("spline_npoints");
237  const int lmax_ind = source_species.findAttribute("lmax");
238 
239  for (int center_idx = 0; center_idx < AtomicCentersInfo.Ncenters; center_idx++)
240  {
241  const int my_GroupID = AtomicCentersInfo.GroupID[center_idx];
242  if (inner_cutoff_ind >= 0)
243  AtomicCentersInfo.inner_cutoff[center_idx] = source_species(inner_cutoff_ind, my_GroupID);
244  if (cutoff_radius_ind >= 0)
245  AtomicCentersInfo.cutoff[center_idx] = source_species(cutoff_radius_ind, my_GroupID);
246  if (spline_radius_ind >= 0)
247  AtomicCentersInfo.spline_radius[center_idx] = source_species(spline_radius_ind, my_GroupID);
248  if (spline_npoints_ind >= 0)
249  AtomicCentersInfo.spline_npoints[center_idx] = source_species(spline_npoints_ind, my_GroupID);
250  if (lmax_ind >= 0)
251  AtomicCentersInfo.lmax[center_idx] = source_species(lmax_ind, my_GroupID);
252  }
253  }
254  ///////////////////////////
255  // Read the twist angles //
256  ///////////////////////////
257  primcell_kpoints.resize(NumTwists);
258  for (int ti = 0; ti < NumTwists; ti++)
259  {
260  std::ostringstream path;
261  path << "/electrons/kpoint_" << ti << "/reduced_k";
262  TinyVector<double, OHMMS_DIM> primcell_kpoints_DP;
263  H5File.read(primcell_kpoints_DP, path.str());
264  primcell_kpoints[ti] = primcell_kpoints_DP;
265  }
267  {
268  //////////////////////////////////////////////////////////
269  // Only if it is bulk: If the density has not been set in TargetPtcl, and //
270  // the density is available, read it in and save it //
271  // in TargetPtcl. //
272  //////////////////////////////////////////////////////////
273  if (TargetPtcl.getLattice().SuperCellEnum == SUPERCELL_BULK)
274  {
275  // FIXME: add support for more than one spin density
276  if (TargetPtcl.Density_G.empty())
277  {
278  Array<double, OHMMS_DIM> Density_r_DP;
279  TinyVector<int, 3> mesh;
280  H5File.read(TargetPtcl.DensityReducedGvecs, "/electrons/density/gvectors");
281  int numG = TargetPtcl.DensityReducedGvecs.size();
282 // Convert primitive G-vectors to supercell G-vectors
283 // Also, flip sign since ESHDF format uses opposite sign convention
284 #pragma omp parallel for
285  for (int iG = 0; iG < numG; iG++)
287  app_log() << " Read " << numG << " density G-vectors.\n";
288  for (int ispin = 0; ispin < NumSpins; ispin++)
289  {
290  std::ostringstream density_r_path, density_g_path;
291  density_r_path << "/electrons/density/spin_" << ispin << "/density_r";
292  density_g_path << "/electrons/density/spin_" << ispin << "/density_g";
293  H5File.readEntry(Density_r_DP, density_r_path.str());
294  TargetPtcl.Density_r = Density_r_DP;
295  if (TargetPtcl.DensityReducedGvecs.size())
296  {
297  app_log() << " EinsplineSetBuilder found density in the HDF5 file.\n";
298  std::vector<ComplexType> density_G;
299  std::vector<std::complex<double>> Density_G_DP;
300  H5File.read(Density_G_DP, density_g_path.str());
301  density_G.assign(Density_G_DP.begin(), Density_G_DP.end());
302  if (!density_G.size())
303  {
304  app_error() << " Density reduced G-vectors defined, but not the" << " density.\n";
305  abort();
306  }
307  else
308  {
309  if (ispin == 0)
310  TargetPtcl.Density_G = density_G;
311  else
312  for (int iG = 0; iG < density_G.size(); iG++)
313  TargetPtcl.Density_G[iG] += density_G[iG];
314  }
315  }
316  }
317  }
318  //////////////////////////////////////////////////////////
319  // If the density has not been set in TargetPtcl, and //
320  // the density is available, read it in and save it //
321  // in TargetPtcl. //
322  //////////////////////////////////////////////////////////
323  // FIXME: add support for more than one spin potential
324  if (!TargetPtcl.VHXC_r[0].size())
325  {
326  TinyVector<int, 3> mesh;
327  H5File.readEntry(TargetPtcl.VHXCReducedGvecs, "/electrons/VHXC/gvectors");
328  int numG = TargetPtcl.VHXCReducedGvecs.size();
329 // Convert primitive G-vectors to supercell G-vectors
330 // Also, flip sign since ESHDF format uses opposite sign convention
331 #pragma omp parallel for
332  for (int iG = 0; iG < numG; iG++)
334  app_log() << " Read " << numG << " VHXC G-vectors.\n";
335  for (int ispin = 0; ispin < NumSpins; ispin++)
336  {
337  Array<double, OHMMS_DIM> VHXC_r_DP;
338  std::ostringstream VHXC_r_path, VHXC_g_path;
339  VHXC_r_path << "/electrons/VHXC/spin_" << ispin << "/VHXC_r";
340  VHXC_g_path << "/electrons/VHXC/spin_" << ispin << "/VHXC_g";
341  H5File.readEntry(VHXC_r_DP, VHXC_r_path.str());
342  TargetPtcl.VHXC_r[ispin] = VHXC_r_DP;
343  if (TargetPtcl.VHXCReducedGvecs.size())
344  {
345  app_log() << " EinsplineSetBuilder found VHXC in the HDF5 file.\n";
346  std::vector<std::complex<double>> VHXC_G_DP;
347  std::vector<ComplexType> VHXC_G;
348  H5File.read(VHXC_G_DP, VHXC_g_path.str());
349  VHXC_G.assign(VHXC_G_DP.begin(), VHXC_G_DP.end());
350  if (!VHXC_G.size())
351  {
352  app_error() << " VHXC reduced G-vectors defined, but not the" << " VHXC.\n";
353  abort();
354  }
355  else
356  TargetPtcl.VHXC_G[ispin] = VHXC_G;
357  }
358  }
359  }
360  }
361  }
362  else
363  {
364  app_log() << " Skip initialization of the density" << std::endl;
365  }
366  return true;
367 }
368 
370 {
371  bool root = myComm->rank() == 0;
372  //this is always ugly
373  MeshSize = 0;
374  int hasPsig = 1;
375  if (root)
376  {
377  H5File.readEntry(MeshSize, "/electrons/psi_r_mesh");
378  H5File.readEntry(MeshSize, "/electrons/mesh");
379  }
381  hasPsig = (MeshSize[0] == 0);
382  if (hasPsig)
383  {
384  int nallowed = 257;
385  int allowed[] = {72, 75, 80, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150,
386  160, 162, 180, 192, 200, 216, 225, 240, 243, 250, 256, 270, 288, 300,
387  320, 324, 360, 375, 384, 400, 405, 432, 450, 480, 486, 500, 512, 540,
388  576, 600, 625, 640, 648, 675, 720, 729, 750, 768, 800, 810, 864, 900,
389  960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 1215, 1250, 1280, 1296, 1350, 1440,
390  1458, 1500, 1536, 1600, 1620, 1728, 1800, 1875, 1920, 1944, 2000, 2025, 2048, 2160,
391  2187, 2250, 2304, 2400, 2430, 2500, 2560, 2592, 2700, 2880, 2916, 3000, 3072, 3125,
392  3200, 3240, 3375, 3456, 3600, 3645, 3750, 3840, 3888, 4000, 4050, 4096, 4320, 4374,
393  4500, 4608, 4800, 4860, 5000, 5120, 5184, 5400, 5625, 5760, 5832, 6000, 6075, 6144,
394  6250, 6400, 6480, 6561, 6750, 6912, 7200, 7290, 7500, 7680, 7776, 8000, 8100, 8192,
395  8640, 8748, 9000, 9216, 9375, 9600, 9720, 10000, 10125, 10240, 10368, 10800, 10935, 11250,
396  11520, 11664, 12000, 12150, 12288, 12500, 12800, 12960, 13122, 13500, 13824, 14400, 14580, 15000,
397  15360, 15552, 15625, 16000, 16200, 16384, 16875, 17280, 17496, 18000, 18225, 18432, 18750, 19200,
398  19440, 19683, 20000, 20250, 20480, 20736, 21600, 21870, 22500, 23040, 23328, 24000, 24300, 24576,
399  25000, 25600, 25920, 26244, 27000, 27648, 28125, 28800, 29160, 30000, 30375, 30720, 31104, 31250,
400  32000, 32400, 32768, 32805, 33750, 34560, 34992, 36000, 36450, 36864, 37500, 38400, 38880, 39366,
401  40000, 40500, 40960, 41472, 43200, 43740, 45000, 46080, 46656, 46875, 48000, 48600, 49152, 50000,
402  50625, 51200, 51840, 52488, 54000, 54675, 55296, 56250, 57600, 58320, 59049, 60000, 60750, 61440,
403  62208, 62500, 64000, 64800, 65536};
404  MaxNumGvecs = 0;
405  // std::set<TinyVector<int,3> > Gset;
406  // Read k-points for all G-vectors and take the union
407  TinyVector<int, 3> maxIndex(0, 0, 0);
408  Gvecs.resize(NumTwists);
409  {
410  int numg = 0;
411  if (root)
412  {
413  std::ostringstream Gpath;
414  Gpath << "/electrons/kpoint_0/gvectors";
415  H5File.read(Gvecs[0], Gpath.str());
416  numg = Gvecs[0].size();
417  }
418  myComm->bcast(numg);
419  if (!root)
420  Gvecs[0].resize(numg);
421  myComm->bcast(Gvecs[0]);
422  MaxNumGvecs = Gvecs[0].size();
423  for (int ig = 0; ig < Gvecs[0].size(); ig++)
424  {
425  maxIndex[0] = std::max(maxIndex[0], std::abs(Gvecs[0][ig][0]));
426  maxIndex[1] = std::max(maxIndex[1], std::abs(Gvecs[0][ig][1]));
427  maxIndex[2] = std::max(maxIndex[2], std::abs(Gvecs[0][ig][2]));
428  }
429  // for (int ig=0; ig<Gvecs.size(); ig++)
430  // if (Gset.find(Gvecs[ig]) == Gset.end())
431  // Gset.insert(Gvecs[ig]);
432  } //done with kpoint_0
433  MeshSize[0] = (int)std::ceil(4.0 * MeshFactor * maxIndex[0]);
434  MeshSize[1] = (int)std::ceil(4.0 * MeshFactor * maxIndex[1]);
435  MeshSize[2] = (int)std::ceil(4.0 * MeshFactor * maxIndex[2]);
436  //only use 2^a 3^b 5^c where a>=2 up to 65536
437  int* ix = std::lower_bound(allowed, allowed + nallowed, MeshSize[0]);
438  int* iy = std::lower_bound(allowed, allowed + nallowed, MeshSize[1]);
439  int* iz = std::lower_bound(allowed, allowed + nallowed, MeshSize[2]);
440  MeshSize[0] = (MeshSize[0] > 128) ? *ix : (MeshSize[0] + MeshSize[0] % 2);
441  MeshSize[1] = (MeshSize[1] > 128) ? *iy : (MeshSize[1] + MeshSize[1] % 2);
442  MeshSize[2] = (MeshSize[2] > 128) ? *iz : (MeshSize[2] + MeshSize[2] % 2);
443  if (Version[0] < 2)
444  {
445  //get the map for each twist, but use the MeshSize from kpoint_0
446  app_log() << " ESHDF::Version " << Version << std::endl;
447  app_log() << " Assumes distinct Gvecs set for different twists. Regenerate orbital files using updated QE."
448  << std::endl;
449  for (int k = 0; k < DistinctTwists.size(); ++k)
450  {
451  int ik = DistinctTwists[k];
452  if (ik == 0)
453  continue; //already done
454  int numg = 0;
455  if (root)
456  {
457  std::ostringstream Gpath;
458  Gpath << "/electrons/kpoint_" << ik << "/gvectors";
459  H5File.read(Gvecs[ik], Gpath.str());
460  numg = Gvecs[ik].size();
461  }
462  myComm->bcast(numg);
463  if (numg == 0)
464  {
465  //copy kpoint_0, default
466  Gvecs[ik] = Gvecs[0];
467  }
468  else
469  {
470  if (numg != MaxNumGvecs)
471  {
472  std::ostringstream o;
473  o << "Twist " << ik << ": The number of Gvecs is different from kpoint_0."
474  << " This is not supported anymore. Rerun pw2qmcpack.x or equivalent";
475  APP_ABORT(o.str());
476  }
477  if (!root)
478  Gvecs[ik].resize(numg);
479  myComm->bcast(Gvecs[ik]);
480  }
481  }
482  }
483  }
484  app_log() << "B-spline mesh factor is " << MeshFactor << std::endl;
485  app_log() << "B-spline mesh size is (" << MeshSize[0] << ", " << MeshSize[1] << ", " << MeshSize[2] << ")\n";
486  app_log() << "Maxmimum number of Gvecs " << MaxNumGvecs << std::endl;
487  app_log().flush();
488  return hasPsig;
489 }
490 
491 void EinsplineSetBuilder::OccupyBands_ESHDF(int spin, int sortBands, int numOrbs)
492 {
493  if (myComm->rank() != 0)
494  return;
495 
496  std::vector<BandInfo>& SortBands(*FullBands[spin]);
497  SortBands.clear(); //??? can exit if SortBands is already made?
498  int maxOrbs(0);
499  for (int ti = 0; ti < DistinctTwists.size(); ti++)
500  {
501  int tindex = DistinctTwists[ti];
502  // First, read valence states
503  std::ostringstream ePath;
504  ePath << "/electrons/kpoint_" << tindex << "/spin_" << spin << "/eigenvalues";
505  std::vector<double> eigvals;
506  H5File.read(eigvals, ePath.str());
507  for (int bi = 0; bi < NumBands; bi++)
508  {
509  BandInfo band;
510  band.TwistIndex = tindex;
511  band.BandIndex = bi;
512  band.MakeTwoCopies = MakeTwoCopies[ti];
513  band.Energy = eigvals[bi];
514  if (band.Energy > -1.0e100)
515  SortBands.push_back(band);
516  if (MakeTwoCopies[ti])
517  maxOrbs += 2;
518  else
519  maxOrbs++;
520  }
521  }
522 
523  app_log() << SortBands.size() << " complex-valued orbitals supplied by h5 can be expanded up to " << maxOrbs
524  << " SPOs." << std::endl;
525  if (maxOrbs < numOrbs)
526  myComm->barrier_and_abort("EinsplineSetBuilder::OccupyBands_ESHDF user input requests "
527  "more orbitals than what the h5 file supplies.");
528 
529  // Now sort the bands by energy
530  if (sortBands == 2)
531  {
532  app_log() << "Sorting the bands by index now:\n";
533  sort(SortBands.begin(), SortBands.end(), sortByIndex);
534  }
535  else if (sortBands == 1)
536  {
537  app_log() << "Sorting the bands now:\n";
538  sort(SortBands.begin(), SortBands.end());
539  }
540 
541  std::vector<int> gsOcc(maxOrbs);
542  int N_gs_orbs = numOrbs;
543  int nocced(0);
544  for (int ti = 0; ti < SortBands.size(); ti++)
545  {
546  if (nocced < N_gs_orbs)
547  {
548  if (SortBands[ti].MakeTwoCopies && (N_gs_orbs - nocced > 1))
549  {
550  nocced += 2;
551  gsOcc[ti] = 2;
552  }
553  else if ((SortBands[ti].MakeTwoCopies && (N_gs_orbs - nocced == 1)) || !SortBands[ti].MakeTwoCopies)
554  {
555  nocced += 1;
556  gsOcc[ti] = 1;
557  }
558  }
559  }
560  if (occ_format == "energy")
561  {
562  app_log() << " Occupying bands based on energy in mode " << (Occ.size() > 0 ? "\"excited\"" : "\"ground\"")
563  << std::endl;
564  // To get the occupations right.
565  std::vector<int> Removed(0, 0);
566  std::vector<int> Added(0, 0);
567  for (int ien = 0; ien < Occ.size(); ien++)
568  {
569  if (Occ[ien] < 0)
570  Removed.push_back(-Occ[ien]);
571  else if (Occ[ien] > 0)
572  Added.push_back(Occ[ien]);
573  }
574  if (Added.size() - Removed.size() != 0)
575  {
576  app_log() << "need to add and remove same number of orbitals. " << Added.size() << " " << Removed.size()
577  << std::endl;
578  APP_ABORT("ChangedOccupations");
579  }
580  std::vector<int> DiffOcc(maxOrbs, 0);
581  //Probably a cleaner way to do this.
582  for (int i = 0; i < Removed.size(); i++)
583  DiffOcc[Removed[i] - 1] -= 1;
584  for (int i = 0; i < Added.size(); i++)
585  DiffOcc[Added[i] - 1] += 1;
586  std::vector<int> SumOrb(SortBands.size(), 0);
587  int doi(0);
588  for (int i = 0; i < SumOrb.size(); i++)
589  {
590  if (SortBands[i].MakeTwoCopies)
591  {
592  SumOrb[i] = gsOcc[i] + DiffOcc[doi++];
593  SumOrb[i] += DiffOcc[doi++];
594  }
595  else
596  SumOrb[i] = gsOcc[i] + DiffOcc[doi++];
597  }
598  std::vector<BandInfo> ReOrderedBands;
599  std::vector<BandInfo> RejectedBands;
600  for (int i = 0; i < SumOrb.size(); i++)
601  {
602  if (SumOrb[i] == 2)
603  {
604  SortBands[i].MakeTwoCopies = true;
605  ReOrderedBands.push_back(SortBands[i]);
606  }
607  else if (SumOrb[i] == 1)
608  {
609  SortBands[i].MakeTwoCopies = false;
610  ReOrderedBands.push_back(SortBands[i]);
611  }
612  else if (SumOrb[i] == 0)
613  {
614  SortBands[i].MakeTwoCopies = false;
615  RejectedBands.push_back(SortBands[i]);
616  }
617  else
618  {
619  app_log() << " Trying to add the same orbital (" << i << ") less than zero or more than 2 times." << std::endl;
620  APP_ABORT("Sorting Excitation");
621  }
622  }
623  ReOrderedBands.insert(ReOrderedBands.end(), RejectedBands.begin(), RejectedBands.end());
624  SortBands = ReOrderedBands;
625  }
626  else if (occ_format == "band")
627  {
628  app_log() << " Occupying bands based on (ti,bi) data." << std::endl;
629  if (Occ.size() != particle_hole_pairs * 4)
630  {
631  app_log() << " Need Occ = pairs*4. Occ is (ti,bi) of removed, then added." << std::endl;
632  app_log() << Occ.size() << " " << particle_hole_pairs << std::endl;
633  APP_ABORT("ChangedOccupations");
634  }
635  int cnt(0);
636  for (int ien = 0; ien < SortBands.size(); ien++)
637  {
638  if ((Occ[cnt] == SortBands[ien].TwistIndex) && (Occ[cnt + 1] == SortBands[ien].BandIndex))
639  {
640  if (cnt < particle_hole_pairs * 2)
641  {
642  gsOcc[ien] -= 1;
643  cnt += 2;
644  app_log() << "removing orbital " << ien << std::endl;
645  }
646  else
647  {
648  gsOcc[ien] += 1;
649  app_log() << "adding orbital " << ien << std::endl;
650  cnt += 2;
651  }
652  }
653  }
654  std::vector<BandInfo> ReOrderedBands;
655  std::vector<BandInfo> RejectedBands;
656  for (int i = 0; i < SortBands.size(); i++)
657  {
658  if (gsOcc[i] == 2)
659  {
660  SortBands[i].MakeTwoCopies = true;
661  ReOrderedBands.push_back(SortBands[i]);
662  }
663  else if (gsOcc[i] == 1)
664  {
665  SortBands[i].MakeTwoCopies = false;
666  ReOrderedBands.push_back(SortBands[i]);
667  }
668  else if (gsOcc[i] == 0)
669  {
670  SortBands[i].MakeTwoCopies = false;
671  RejectedBands.push_back(SortBands[i]);
672  }
673  else
674  {
675  app_log() << " Trying to add the same orbital (" << i << ") less than zero or more than 2 times." << std::endl;
676  APP_ABORT("Sorting Excitation");
677  }
678  }
679  ReOrderedBands.insert(ReOrderedBands.end(), RejectedBands.begin(), RejectedBands.end());
680  SortBands = ReOrderedBands;
681  }
682  //for(int sw=0;sw<Removed.size();sw++){
683  // app_log()<<" Swapping two orbitals "<<Removed[sw]<<" and "<<Added[sw]<< std::endl;
684  // BandInfo tempband(SortBands[Removed[sw]-1]);
685  // SortBands[Removed[sw]-1] = SortBands[Added[sw]-1];
686  // SortBands[Added[sw]-1] = tempband;
687  //}
688  int orbIndex = 0;
689  int numOrbs_counter = 0;
690  while (numOrbs_counter < numOrbs)
691  {
692  if (SortBands[orbIndex].MakeTwoCopies)
693  numOrbs_counter += 2;
694  else
695  numOrbs_counter++;
696  orbIndex++;
697  }
698  NumDistinctOrbitals = orbIndex;
699  app_log() << "We will read " << NumDistinctOrbitals << " distinct complex-valued orbitals from h5.\n";
700 }
701 
702 } // namespace qmcplusplus
void set(const Tensor< TT, D > &lat)
set the lattice vector from the command-line options
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.
double Energy
energy associated with this band
Definition: BandInfo.h:37
Tensor< int, OHMMS_DIM > TileMatrix
bool open(const std::filesystem::path &fname, unsigned flags=H5F_ACC_RDWR)
open a file
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
int rank() const
return the rank
Definition: Communicate.h:116
Tensor< T, D >::Type_t det(const Tensor< T, D > &a)
Definition: TensorOps.h:838
Array< RealType, OHMMS_DIM > Density_r
Definition: ParticleSet.h:99
QTBase::RealType RealType
Definition: Configuration.h:58
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
size_t getTotalNum() const
Definition: ParticleSet.h:493
std::ostream & app_log()
Definition: OutputManager.h:65
ParticleSet & TargetPtcl
quantum particle set
std::vector< TinyVector< double, OHMMS_DIM > > ion_pos
int BandIndex
band index
Definition: BandInfo.h:31
std::ostream & app_error()
Definition: OutputManager.h:67
Builder class for einspline-based SPOSet objects.
void OccupyBands_ESHDF(int spin, int sortBands, int numOrbs)
struct qmcplusplus::EinsplineSetBuilder::CenterInfo AtomicCentersInfo
ParticleSet * SourcePtcl
ionic system
Timer class.
void update(bool skipSK=false)
update the internal data
#define OHMMS_DIM
Definition: config.h:64
std::vector< std::unique_ptr< std::vector< BandInfo > > > FullBands
Helper vector for sorting bands.
TinyVector< T, 3 > lower_bound(const TinyVector< T, 3 > &a, const TinyVector< T, 3 > &b)
helper function to determine the lower bound of a domain (need to move up)
ParticleIndex GroupID
Species ID.
Definition: ParticleSet.h:77
bool HaveOrbDerivs
This is true if we have the orbital derivatives w.r.t. the ion positions.
Vector< TinyVector< double, OHMMS_DIM > > IonPos
int addTable(const ParticleSet &psrc, DTModes modes=DTModes::ALL_OFF)
add a distance table
std::vector< ComplexType > VHXC_G[2]
Definition: ParticleSet.h:103
size_type size() const
return the current size
Definition: OhmmsVector.h:162
MakeReturn< UnaryNode< FnCeil, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t ceil(const Vector< T1, C1 > &l)
SingleParticlePos toUnit_floor(const TinyVector< T1, D > &r) const
Communicate * myComm
pointer to Communicate
Definition: MPIObjectBase.h:62
std::vector< ComplexType > Density_G
Definition: ParticleSet.h:98
size_t size() const
Definition: OhmmsArray.h:57
ParticlePos R
Position.
Definition: ParticleSet.h:79
#define APP_ABORT(msg)
Widely used but deprecated fatal error macros from legacy code.
Definition: AppAbort.h:27
bool MakeTwoCopies
This is true if we should make distinct copies represeninting a +k, -k pair.
Definition: BandInfo.h:39
auto & getDistTable(int table_ID) const
get a distance table by table_ID
Definition: ParticleSet.h:190
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
bool sortByIndex(BandInfo leftB, BandInfo rightB)
int TwistIndex
twist index
Definition: BandInfo.h:29
bool ReadGvectors_ESHDF()
read gvectors for each twist
Tensor< T, D > inverse(const Tensor< T, D > &a)
Definition: TensorOps.h:879
Tensor< double, OHMMS_DIM > LatticeInv
Array< RealType, OHMMS_DIM > VHXC_r[2]
Definition: ParticleSet.h:104
Tensor< double, OHMMS_DIM > SuperLattice
const auto & getLattice() const
Definition: ParticleSet.h:251
std::vector< std::vector< TinyVector< int, 3 > > > Gvecs
std::vector< TinyVector< double, OHMMS_DIM > > primcell_kpoints
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
void read(T &data, const std::string &aname)
read the data from the group aname and check status runtime error is issued on I/O error ...
Definition: hdf_archive.h:306
void bcast(T &)
bool ReadOrbitalInfo_ESHDF(bool skipChecks=false)
QMCState qmc_common
a unique QMCState during a run
Definition: qmc_common.cpp:111
void barrier_and_abort(const std::string &msg) const
bool readEntry(T &data, const std::string &aname)
read the data from the group aname and return status use read() for inbuilt error checking ...
Definition: hdf_archive.h:293
A D-dimensional Array class based on PETE.
Definition: OhmmsArray.h:25
int findAttribute(const std::string &name) const
almost all code ignores this and just uses addAttribute for the same purpose.
Definition: SpeciesSet.h:128
Tensor< double, OHMMS_DIM > RecipLattice
std::vector< TinyVector< int, OHMMS_DIM > > DensityReducedGvecs
Particle density in G-space for MPC interaction.
Definition: ParticleSet.h:97
std::vector< TinyVector< int, OHMMS_DIM > > VHXCReducedGvecs
DFT potential.
Definition: ParticleSet.h:102
Tensor< double, OHMMS_DIM > Lattice
bool use_density
true, if density is used, e.g. MPC
Definition: qmc_common.h:35