QMCPACK
PWOrbitalSetBuilder.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) 2023 QMCPACK developers.
6 //
7 // File developed by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
10 // Mark Dewing, markdewing@gmail.com, University of Illinois at Urbana-Champaign
11 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
12 //
13 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
14 //////////////////////////////////////////////////////////////////////////////////////
15 
16 
17 /** @file
18  * @brief Definition of a builder class for PWOrbitalSet
19  */
20 #include "PWOrbitalSetBuilder.h"
22 #include "OhmmsData/ParameterSet.h"
23 #include "OhmmsData/AttributeSet.h"
24 #include "Message/Communicate.h"
25 
26 namespace qmcplusplus
27 {
29  : SPOSetBuilder("Planewave", comm),
30  targetPtcl(p),
31  rootNode(cur),
32  myParam{std::make_unique<PWParameterSet>(comm)},
33  hfile{comm}
34 {
35  //
36  //Get wavefunction data and parameters from XML and HDF5
37  //
38  //catch parameters
39  myParam->put(cur);
40  //check the current href
41  bool success = getH5(cur, "href");
42  //Move through the XML tree and read basis information
43  processChildren(cur, [&](const std::string& cname, const xmlNodePtr element) {
44  if (cname == "basisset")
45  {
46  const std::string a(getXMLAttributeValue(element, "ecut"));
47  if (!a.empty())
48  myParam->Ecut = std::stod(a);
49  }
50  else if (cname == "coefficients")
51  {
52  //close
53  if (success)
54  hfile.close();
55  success = getH5(element, "hdata");
56  }
57  });
58 
59  if (!success)
60  throw std::runtime_error("h5 cannot be open for creating PW basis!");
61  //create PW Basis
62  createPWBasis();
63 }
64 
66 
67 std::unique_ptr<SPOSet> PWOrbitalSetBuilder::createSPOSetFromXML(xmlNodePtr cur)
68 {
69  int spin_group = 0;
70  std::string spo_object_name;
71  OhmmsAttributeSet aAttrib;
72  aAttrib.add(spin_group, "spindataset");
73  aAttrib.add(spo_object_name, "name");
74  aAttrib.add(spo_object_name, "id");
75  aAttrib.put(cur);
76  return createPW(cur, spo_object_name, spin_group);
77 }
78 
79 /** The read routine - get data from XML and H5. Process it and build orbitals.
80  *
81  * - parameters
82  * -- num_tiwsts
83  * -- num_bands
84  * -- complex_coefficients
85  * -- maximum_ecut
86  * - basis
87  */
89 {
90  //recycle int and double reader
91  int idata = 0;
92  //start of parameters
93  hfile.read(idata, "electrons/number_of_kpoints");
94  int nkpts = idata;
95  hfile.read(idata, "electrons/number_of_spins");
96  hfile.read(idata, "electrons/kpoint_0/spin_0/number_of_states");
97  int nbands = idata;
98  myParam->numBands = nbands;
99  app_log() << "Number of bands = " << nbands << std::endl;
100  // Cutoff no longer present in the HDF file
101  RealType ecut = 0.0;
102  //end of parameters
103  //check if input parameters are valid
104  int nup = targetPtcl.last(0);
105  int ndown = targetPtcl.getTotalNum() - nup;
106  if (nbands < nup || nbands < ndown)
107  {
108  app_error() << "Not enough bands in h5 file" << std::endl;
110  }
111  std::string tname = myParam->getTwistAngleName();
112  TinyVector<double, OHMMS_DIM> TwistAngle_DP;
113  hfile.read(TwistAngle_DP, "/electrons/kpoint_0/reduced_k");
114  TwistAngle = TwistAngle_DP;
115  if (!myBasisSet)
116  myBasisSet = std::make_unique<PWBasis>(TwistAngle);
117 
118  //Read the planewave basisset.
119  //Note that the same data is opened here for each twist angle-avoids duplication in the
120  //h5 file (which may become very large).
121  //return the ecut to be used by the basis set
122  RealType real_ecut = myParam->getEcut(ecut);
123  //create at least one basis set but do resize the containers
124  int nh5gvecs = myBasisSet->readbasis(hfile, real_ecut, targetPtcl.getLattice(), myParam->pwTag, myParam->pwMultTag);
125  app_log() << " num_twist = " << nkpts << std::endl;
126  app_log() << " twist angle = " << TwistAngle << std::endl;
127  app_log() << " num_bands = " << nbands << std::endl;
128  app_log() << " input maximum_ecut = " << ecut << std::endl;
129  app_log() << " current maximum_ecut = " << real_ecut << std::endl;
130  app_log() << " num_planewaves = " << nh5gvecs << std::endl;
131  return true;
132 }
133 
134 std::unique_ptr<SPOSet> PWOrbitalSetBuilder::createPW(xmlNodePtr cur, const std::string& objname, int spinIndex)
135 {
136  int nb = targetPtcl.last(spinIndex) - targetPtcl.first(spinIndex);
137  std::vector<int> occBand(nb);
138  for (int i = 0; i < nb; i++)
139  occBand[i] = i;
140  using GIndex_t = PWBasis::GIndex_t;
141  GIndex_t nG(1);
142  bool transform2grid = false;
143  cur = cur->children;
144  while (cur != NULL)
145  {
146  std::string cname((const char*)(cur->name));
147  if (cname == "transform")
148  {
149  putContent(nG, cur);
150  transform2grid = true;
151  }
152  else if (cname == "occupation")
153  {
154  std::string occMode("ground");
155  int bandoffset(1);
156  OhmmsAttributeSet aAttrib;
157  aAttrib.add(occMode, "mode");
158  aAttrib.add(bandoffset, "offset"); /* reserved for index offset */
159  aAttrib.put(cur);
160  if (occMode == "excited")
161  {
162  std::vector<int> occ;
163  std::vector<int> deleted, added;
164  putContent(occ, cur);
165  for (int i = 0; i < occ.size(); i++)
166  {
167  if (occ[i] < 0)
168  deleted.push_back(-occ[i]);
169  else
170  added.push_back(occ[i]);
171  }
172  if (deleted.size() != added.size())
173  {
174  app_error() << " Numbers of deleted and added bands are not identical." << std::endl;
176  }
177  for (int i = 0; i < deleted.size(); i++)
178  {
179  occBand[deleted[i] - bandoffset] = added[i] - bandoffset;
180  }
181  app_log() << " mode=\"excited\" Occupied states: " << std::endl;
182  copy(occBand.begin(), occBand.end(), std::ostream_iterator<int>(app_log(), " "));
183  app_log() << std::endl;
184  }
185  }
186  cur = cur->next;
187  }
188  std::string tname = "kpoint_0";
189  hfile.push("electrons", false);
190  hfile.push("kpoint_0", false);
191  //create a single-particle orbital set
192  auto psi = std::make_unique<SPOSetType>(objname);
193  if (transform2grid)
194  {
195  nb = myParam->numBands;
196  occBand.resize(nb);
197  for (int i = 0; i < nb; i++)
198  occBand[i] = i;
199  }
200  //going to take care of occ
201  psi->resize(new PWBasis(*myBasisSet), nb, true);
202  if (myParam->hasComplexData(hfile)) //input is complex
203  {
204  //app_log() << " PW coefficients are complex." << std::endl;
205  using TempVecType = std::vector<std::complex<RealType>>;
206  using TempVecType_DP = std::vector<std::complex<double>>;
207  TempVecType_DP coefs_DP(myBasisSet->inputmap.size());
208  int ib = 0;
209  while (ib < nb)
210  {
211  std::string bname(myParam->getBandName(occBand[ib], spinIndex));
212  app_log() << " Reading " << tname << "/" << bname << std::endl;
213  hfile.push(bname, false);
214  hfile.read(coefs_DP, "psi_g");
215  TempVecType coefs(coefs_DP.begin(), coefs_DP.end());
216  psi->addVector(coefs, ib);
217  hfile.pop();
218  ++ib;
219  }
220  }
221  else
222  {
223  // It appears the coefficients are always stored as complex in the HDF file?
224  //app_log() << " PW coefficients are real." << std::endl;
225  using ComplexTempVecType = std::vector<std::complex<RealType>>;
226  using ComplexTempVecType_DP = std::vector<std::complex<double>>;
227  ComplexTempVecType_DP complex_coefs_DP(myBasisSet->inputmap.size());
228  int ib = 0;
229  while (ib < nb)
230  {
231  std::string bname(myParam->getBandName(occBand[ib], spinIndex));
232  app_log() << " Reading " << tname << "/" << bname << std::endl;
233  hfile.push(bname, false);
234  hfile.read(complex_coefs_DP, "psi_g");
235  ComplexTempVecType complex_coefs(complex_coefs_DP.begin(), complex_coefs_DP.end());
236  psi->addVector(complex_coefs, ib);
237  hfile.pop();
238  ++ib;
239  }
240  }
241  hfile.pop();
242  hfile.pop();
243 #if defined(QMC_COMPLEX)
244  if (transform2grid)
245  {
246  app_warning() << " Going to transform on grid " << std::endl;
247  transform2GridData(nG, spinIndex, *psi);
248  }
249 #endif
250  return psi;
251 }
252 
253 #if defined(QMC_COMPLEX)
254 void PWOrbitalSetBuilder::transform2GridData(PWBasis::GIndex_t& nG, int spinIndex, PWOrbitalSet& pwFunc)
255 {
256  std::ostringstream splineTag;
257  splineTag << "eigenstates_" << nG[0] << "_" << nG[1] << "_" << nG[2];
258  herr_t status = H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
259  std::string splineTagStr = splineTag.str();
260  app_log() << " splineTag " << splineTagStr << std::endl;
261  if (!hfile.is_group(splineTagStr))
262  {
263  hfile.push(splineTagStr, true);
264  hfile.write(nG, "grid");
265  }
266  else
267  {
268  hfile.push(splineTagStr, false);
269  }
270  std::string tname = myParam->getTwistName();
271  hfile.push(tname, true);
272 
273  TinyVector<double, OHMMS_DIM> TwistAngle_DP;
274  TwistAngle_DP = TwistAngle;
275  hfile.write(TwistAngle_DP, "twist_angle");
277  RealType dx = 1.0 / static_cast<RealType>(nG[0] - 1);
278  RealType dy = 1.0 / static_cast<RealType>(nG[1] - 1);
279  RealType dz = 1.0 / static_cast<RealType>(nG[2] - 1);
280 #if defined(VERYTINYMEMORY)
281  using StorageType = Array<ParticleSet::SingleParticleValue, 3>;
282  StorageType inData(nG[0], nG[1], nG[2]);
283  int ib = 0;
284  while (ib < myParam->numBands)
285  {
286  std::string bname(myParam->getBandName(ib));
287  hfile.push(bname, true);
288  if (myParam->hasSpin)
289  {
290  bname = myParam->getSpinName(spinIndex);
291  hfile.push(bname, true);
292  }
293  for (int ig = 0; ig < nG[0]; ig++)
294  {
295  RealType x = ig * dx;
296  for (int jg = 0; jg < nG[1]; jg++)
297  {
298  RealType y = jg * dy;
299  for (int kg = 0; kg < nG[2]; kg++)
300  {
301  inData(ig, jg, kg) = pwFunc.evaluate(ib, lattice.toCart(PosType(x, y, kg * dz)));
302  }
303  }
304  }
305  app_log() << " Add spline data " << ib << " h5path=" << tname << "/eigvector" << std::endl;
306  hfile.write(inData, myParam->eigvecTag);
307  if (myParam->hasSpin)
308  mfile.pop();
309  mfile.pop();
310  ++ib;
311  }
312 #else
313  using StorageType = Array<ParticleSet::SingleParticleValue, 3>;
314  UPtrVector<StorageType> inData;
315  int nb = myParam->numBands;
316  for (int ib = 0; ib < nb; ib++)
317  inData.push_back(std::make_unique<StorageType>(nG[0], nG[1], nG[2]));
318  PosType tAngle = targetPtcl.getLattice().k_cart(TwistAngle);
319  ParticleSet ptemp(targetPtcl.getSimulationCell());
320  ptemp.create({1});
322  for (int ig = 0; ig < nG[0]; ig++)
323  {
324  RealType x = ig * dx;
325  for (int jg = 0; jg < nG[1]; jg++)
326  {
327  RealType y = jg * dy;
328  for (int kg = 0; kg < nG[2]; kg++)
329  {
330  ptemp.R[0] = lattice.toCart(PosType(x, y, kg * dz));
331  pwFunc.evaluateValue(ptemp, 0, phi);
332  RealType x(dot(ptemp.R[0], tAngle));
333  ValueType phase(std::cos(x), -std::sin(x));
334  for (int ib = 0; ib < nb; ib++)
335  (*inData[ib])(ig, jg, kg) = phase * phi[ib];
336  }
337  }
338  }
339  for (int ib = 0; ib < nb; ib++)
340  {
341  std::string bname(myParam->getBandName(ib));
342  hfile.push(bname, true);
343  if (myParam->hasSpin)
344  {
345  bname = myParam->getSpinName(spinIndex);
346  hfile.push(bname, true);
347  }
348  app_log() << " Add spline data " << ib << " h5path=" << tname << "/eigvector" << std::endl;
349  hfile.write(*inData[ib], myParam->eigvecTag);
350  if (myParam->hasSpin)
351  hfile.pop();
352  hfile.pop();
353  }
354 #endif
355  hfile.pop();
356  hfile.pop();
357 }
358 #endif
359 
360 bool PWOrbitalSetBuilder::getH5(xmlNodePtr cur, const char* aname)
361 {
362  const std::string a(getXMLAttributeValue(cur, aname));
363  if (a.empty())
364  return false;
365 
366  bool success = hfile.open(a, H5F_ACC_RDONLY | H5P_DEFAULT);
367  if (!success)
368  {
369  app_error() << " Cannot open " << a << " file." << std::endl;
371  }
372  myParam->checkVersion(hfile);
373  //overwrite the parameters
374  myParam->put(rootNode);
375  return success;
376 }
377 
378 } // namespace qmcplusplus
std::ostream & app_warning()
Definition: OutputManager.h:69
void write(T &data, const std::string &aname)
write the data to the group aname and check status runtime error is issued on I/O error ...
Definition: hdf_archive.h:259
bool open(const std::filesystem::path &fname, unsigned flags=H5F_ACC_RDWR)
open a file
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
QTBase::RealType RealType
Definition: Configuration.h:58
ValueType evaluate(int ib, const PosType &pos)
Definition: PWOrbitalSet.h:74
size_t getTotalNum() const
Definition: ParticleSet.h:493
std::ostream & app_log()
Definition: OutputManager.h:65
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > ParticleLayout
Definition: Configuration.h:79
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
MakeReturn< UnaryNode< FnSin, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sin(const Vector< T1, C1 > &l)
std::ostream & app_error()
Definition: OutputManager.h:67
int first(int igroup) const
return the first index of a group i
Definition: ParticleSet.h:514
bool getH5(xmlNodePtr cur, const char *aname)
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
void copy(const Array< T1, 3 > &src, Array< T2, 3 > &dest)
Definition: Blitz.h:639
hdf_archive hfile
hdf5 handler to clean up
QMCTraits::PosType PosType
Wrapping information on parallelism.
Definition: Communicate.h:68
const auto & getSimulationCell() const
Definition: ParticleSet.h:250
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > lattice
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
base class for the real SPOSet builder
Definition: SPOSetBuilder.h:47
MakeReturn< UnaryNode< FnCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t cos(const Vector< T1, C1 > &l)
PWOrbitalSetBuilder(const ParticleSet &p, Communicate *comm, xmlNodePtr cur)
constructor
QTBase::ValueType ValueType
Definition: Configuration.h:60
std::unique_ptr< SPOSet > createSPOSetFromXML(xmlNodePtr cur) override
create an sposet from xml and save the resulting SPOSet
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
OrbitalSetTraits< ValueType >::ValueVector ValueVector
Definition: SPOSet.h:49
std::unique_ptr< PWParameterSet > myParam
parameter set
QTBase::PosType PosType
Definition: Configuration.h:61
int last(int igroup) const
return the last index of a group i
Definition: ParticleSet.h:517
xmlNodePtr rootNode
xml node for determinantset
std::string getXMLAttributeValue(const xmlNodePtr cur, const std::string_view name)
get the value string for attribute name if name is unfound in cur you get an empty string back this i...
void push(const std::string &gname, bool createit=true)
push a group to the group stack
void evaluateValue(const ParticleSet &P, int iat, ValueVector &psi) override
evaluate the values of this single-particle orbital set
bool putContent(T &a, xmlNodePtr cur)
replaces a&#39;s value with the first "element" in the "string" returned by XMLNodeString{cur}.
Definition: libxmldefs.h:88
void abort() const
QMCTraits::RealType RealType
std::unique_ptr< SPOSet > createPW(xmlNodePtr cur, const std::string &objname, int spinIndex)
void processChildren(const xmlNodePtr cur, const F &functor)
process through all the children of an XML element F is a lambda or functor void F/[](const std::stri...
Definition: libxmldefs.h:175
bool is_group(const std::string &aname)
check if aname is a group
const auto & getLattice() const
Definition: ParticleSet.h:251
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
Declaration of a builder class for PWOrbitalSet.
Plane-wave basis set.
Definition: PWBasis.h:40
A D-dimensional Array class based on PETE.
Definition: OhmmsArray.h:25
const ParticleSet & targetPtcl
target particle set
void add(PDT &aparam, const std::string &aname, std::vector< PDT > candidate_values={}, TagStatus status=TagStatus::OPTIONAL)
add a new attribute
Definition: AttributeSet.h:42
bool createPWBasis()
The read routine - get data from XML and H5.
TinyVector< IndexType, 3 > GIndex_t
Definition: PWBasis.h:44
std::unique_ptr< PWBasis > myBasisSet
PosType TwistAngle
input twist angle