QMCPACK
EinsplineSetBuilder_createSPOs.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 // Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
9 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 // Paul R. C. Kent, kentpr@ornl.gov, Oak Ridge National Laboratory
11 // Raymond Clay III, j.k.rofling@gmail.com, Lawrence Livermore National Laboratory
12 // Ying Wai Li, yingwaili@ornl.gov, Oak Ridge National Laboratory
13 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
14 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
15 //
16 // File created by: Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
17 //////////////////////////////////////////////////////////////////////////////////////
18 
19 
20 #include "EinsplineSetBuilder.h"
21 #include <PlatformSelector.hpp>
22 #include "CPU/e2iphi.h"
23 #include "CPU/SIMD/vmath.hpp"
24 #include "OhmmsData/AttributeSet.h"
25 #include "Message/CommOperators.h"
26 #include "Utilities/Timer.h"
28 #include "Particle/DistanceTable.h"
29 #include "einspline_helper.hpp"
30 #include "BsplineReader.h"
31 #include "BsplineSet.h"
32 #include "createBsplineReader.h"
33 
34 #include <array>
35 #include <string_view>
36 
37 namespace qmcplusplus
38 {
40  int twist_num_inp,
41  const TinyVector<double, OHMMS_DIM>& twist_inp,
42  bool skipChecks)
43 {
44  // 1. set a lot of internal parameters in the EinsplineSetBuilder class
45  // e.g. TileMatrix, use_real_splines_, DistinctTwists, MakeTwoCopies.
46  // 2. this is also where metadata for the orbitals are read from the wavefunction hdf5 file
47  // and broadcast to MPI groups. Variables broadcasted are listed in
48  // EinsplineSetBuilderCommon.cpp EinsplineSetBuilder::BroadcastOrbitalInfo()
49  //
50 
51  Timer orb_info_timer;
52  // The tiling can be set by a simple vector, (e.g. 2x2x2), or by a
53  // full 3x3 matrix of integers. If the tilematrix was not set in
54  // the input file...
55  bool matrixNotSet = true;
56  for (int i = 0; i < 3; i++)
57  for (int j = 0; j < 3; j++)
58  matrixNotSet = matrixNotSet && (TileMatrix(i, j) == 0);
59  // then set the matrix to identity.
60  if (matrixNotSet)
61  for (int i = 0; i < 3; i++)
62  for (int j = 0; j < 3; j++)
63  TileMatrix(i, j) = (i == j) ? 1 : 0;
64  if (myComm->rank() == 0)
65  {
66  std::array<char, 1000> buff;
67  int length =
68  std::snprintf(buff.data(), buff.size(), " TileMatrix = \n [ %2d %2d %2d\n %2d %2d %2d\n %2d %2d %2d ]\n",
69  TileMatrix(0, 0), TileMatrix(0, 1), TileMatrix(0, 2), TileMatrix(1, 0), TileMatrix(1, 1),
70  TileMatrix(1, 2), TileMatrix(2, 0), TileMatrix(2, 1), TileMatrix(2, 2));
71  if (length < 0)
72  throw std::runtime_error("Error converting TileMatrix to a string");
73  app_log() << std::string_view(buff.data(), length);
74  }
75  if (numOrbs == 0)
77  "EinsplineSetBuilder::createSPOSet You must specify the number of orbitals in the input file.");
78  else
79  app_log() << " Reading " << numOrbs << " orbitals from HDF5 file.\n";
80 
81  /////////////////////////////////////////////////////////////////
82  // Read the basic orbital information, without reading all the //
83  // orbitals themselves. //
84  /////////////////////////////////////////////////////////////////
85  orb_info_timer.restart();
86  if (myComm->rank() == 0)
87  if (!ReadOrbitalInfo(skipChecks))
88  throw std::runtime_error("EinsplineSetBuilder::set_metadata Error reading orbital info from HDF5 file.");
89  app_log() << "TIMER EinsplineSetBuilder::ReadOrbitalInfo " << orb_info_timer.elapsed() << std::endl;
90  myComm->barrier();
91 
92  orb_info_timer.restart();
94  app_log() << "TIMER EinsplineSetBuilder::BroadcastOrbitalInfo " << orb_info_timer.elapsed() << std::endl;
95  app_log().flush();
96 
97  // setup primitive cell and supercell
101 
102  // Now, analyze the k-point mesh to figure out the what k-points are needed
103  AnalyzeTwists2(twist_num_inp, twist_inp);
104 }
105 
106 std::unique_ptr<SPOSet> EinsplineSetBuilder::createSPOSetFromXML(xmlNodePtr cur)
107 {
108  //use 2 bohr as the default when truncated orbitals are used based on the extend of the ions
109  int numOrbs = 0;
110  int sortBands(1);
111  int spinSet = 0;
112  bool skipChecks = false;
113  int twist_num_inp = TWISTNUM_NO_INPUT;
115 
116  std::string sourceName;
117  std::string spo_prec("double");
118  std::string truncate("no");
119  std::string hybrid_rep("no");
120  std::string skip_checks("no");
121  std::string use_einspline_set_extended(
122  "no"); // use old spline library for high-order derivatives, e.g. needed for backflow optimization
123  std::string useGPU;
124  std::string GPUsharing = "no";
125 
126  ScopedTimer spo_timer_scope(createGlobalTimer("einspline::CreateSPOSetFromXML", timer_level_medium));
127 
128  {
129  TinyVector<int, OHMMS_DIM> TileFactor_do_not_use;
131  a.add(H5FileName, "href");
132  a.add(TileFactor_do_not_use, "tile", {}, TagStatus::DELETED);
133  a.add(sortBands, "sort");
134  a.add(TileMatrix, "tilematrix");
135  a.add(twist_num_inp, "twistnum");
136  a.add(twist_inp, "twist");
137  a.add(sourceName, "source");
138  a.add(MeshFactor, "meshfactor");
139  a.add(hybrid_rep, "hybridrep");
141  a.add(GPUsharing, "gpusharing"); // split spline across GPUs visible per rank
142  a.add(spo_prec, "precision");
143  a.add(truncate, "truncate");
144  a.add(myName, "tag");
145  a.add(skip_checks, "skip_checks");
146 
147  a.put(XMLRoot);
148  a.add(numOrbs, "size");
149  a.add(numOrbs, "norbs");
150  a.add(spinSet, "spindataset");
151  a.add(spinSet, "group");
152  a.put(cur);
153 
154  if (myName.empty())
155  myName = "einspline";
156  }
157 
158  if (skip_checks == "yes")
159  skipChecks = true;
160 
161  auto pit(ParticleSets.find(sourceName));
162  if (pit == ParticleSets.end())
163  myComm->barrier_and_abort("Einspline needs the source particleset");
164  else
165  SourcePtcl = pit->second.get();
166 
167  ///////////////////////////////////////////////
168  // Read occupation information from XML file //
169  ///////////////////////////////////////////////
170  const std::vector<int> last_occ(Occ);
171  Occ.resize(0, 0); // correspond to ground
172  bool NewOcc(false);
173 
174  {
175  OhmmsAttributeSet oAttrib;
176  oAttrib.add(spinSet, "spindataset");
177  oAttrib.put(cur);
178  }
179 
180  xmlNodePtr spo_cur = cur;
181  cur = cur->children;
182  while (cur != NULL)
183  {
184  std::string cname((const char*)(cur->name));
185  if (cname == "occupation")
186  {
187  std::string occ_mode("ground");
188  occ_format = "energy";
190  OhmmsAttributeSet oAttrib;
191  oAttrib.add(occ_mode, "mode");
192  oAttrib.add(spinSet, "spindataset");
193  oAttrib.add(occ_format, "format");
194  oAttrib.add(particle_hole_pairs, "pairs");
195  oAttrib.put(cur);
196  if (occ_mode == "excited")
197  putContent(Occ, cur);
198  else if (occ_mode != "ground")
199  myComm->barrier_and_abort("EinsplineSetBuilder::createSPOSet Only ground state occupation "
200  "currently supported in EinsplineSetBuilder.");
201  }
202  cur = cur->next;
203  }
204  if (Occ != last_occ)
205  {
206  NewOcc = true;
207  }
208  else
209  NewOcc = false;
210 #if defined(MIXED_PRECISION)
211  app_log() << "\t MIXED_PRECISION=1 Overwriting the einspline storage to single precision.\n";
212  spo_prec = "single"; //overwrite
213 #endif
214  H5OrbSet aset(H5FileName, spinSet, numOrbs);
215  const auto iter = SPOSetMap.find(aset);
216  if ((iter != SPOSetMap.end()) && (!NewOcc))
217  app_warning() << "!!!!!!! Identical SPOSets are detected by EinsplineSetBuilder! "
218  "Implicit sharing one SPOSet for spin-up and spin-down electrons has been removed. "
219  "Each determinant creates its own SPOSet with dedicated memory for spline coefficients. "
220  "To avoid increasing the memory footprint of spline coefficients, "
221  "create a single SPOset outside the determinantset using 'sposet_collection' "
222  "and reference it by name on the determinant line."
223  << std::endl;
224 
225  if (FullBands[spinSet] == 0)
226  FullBands[spinSet] = std::make_unique<std::vector<BandInfo>>();
227 
228  // Ensure the first SPO set must be spinSet==0
229  // to correctly initialize key data of EinsplineSetBuilder
230  if (SPOSetMap.size() == 0 && spinSet != 0)
231  myComm->barrier_and_abort("The first SPO set must have spindataset=\"0\"");
232 
233  // set the internal parameters
234  if (spinSet == 0)
235  set_metadata(numOrbs, twist_num_inp, twist_inp, skipChecks);
236 
237  //////////////////////////////////
238  // Create the OrbitalSet object
239  //////////////////////////////////
240  Timer mytimer;
241  mytimer.restart();
242  OccupyBands(spinSet, sortBands, numOrbs, skipChecks);
243  if (spinSet == 0)
244  TileIons();
245 
246  bool use_single = (spo_prec == "single" || spo_prec == "float");
247 
248  // safeguard for a removed feature
249  if (truncate == "yes")
251  "The 'truncate' feature of spline SPO has been removed. Please use hybrid orbital representation.");
252 
253 #if !defined(QMC_COMPLEX)
254  if (use_real_splines_)
255  {
256  //if(TargetPtcl.Lattice.SuperCellEnum != SUPERCELL_BULK && truncate=="yes")
257  if (MixedSplineReader == 0)
258  MixedSplineReader = createBsplineReal(this, use_single, hybrid_rep == "yes", useGPU);
259  }
260  else
261 #endif
262  {
263  if (MixedSplineReader == 0)
264  MixedSplineReader = createBsplineComplex(this, use_single, hybrid_rep == "yes", useGPU);
265  }
266 
267  MixedSplineReader->setCommon(XMLRoot);
268  // temporary disable the following function call, Ye Luo
269  // RotateBands_ESHDF(spinSet, dynamic_cast<EinsplineSetExtended<std::complex<double> >*>(OrbitalSet));
270  bcastSortBands(spinSet, NumDistinctOrbitals, myComm->rank() == 0);
271  auto OrbitalSet = MixedSplineReader->create_spline_set(spinSet, spo_cur);
272  if (!OrbitalSet)
273  myComm->barrier_and_abort("Failed to create SPOSet*");
274  app_log() << "Time spent in creating B-spline SPOs " << mytimer.elapsed() << " sec" << std::endl;
275  OrbitalSet->finalizeConstruction();
276  SPOSetMap[aset] = OrbitalSet.get();
277  return OrbitalSet;
278 }
279 
280 std::unique_ptr<SPOSet> EinsplineSetBuilder::createSPOSet(xmlNodePtr cur, SPOSetInputInfo& input_info)
281 {
282  if (MixedSplineReader == 0)
283  myComm->barrier_and_abort("EinsplineSetExtended<T> cannot create a SPOSet");
284 
285  std::string aname;
286  int spinSet(0);
288  a.add(spinSet, "spindataset");
289  a.add(spinSet, "group");
290  a.put(cur);
291 
292  //allow only non-overlapping index sets and use the max index as the identifier
293  int norb = input_info.max_index();
294  H5OrbSet aset(H5FileName, spinSet, norb);
295 
296  auto bspline_zd = MixedSplineReader->create_spline_set(spinSet, cur, input_info);
297  if (bspline_zd)
298  SPOSetMap[aset] = bspline_zd.get();
299  return bspline_zd;
300 }
301 
302 } // namespace qmcplusplus
void set(const Tensor< TT, D > &lat)
set the lattice vector from the command-line options
a class that defines a supercell in D-dimensional Euclean space.
std::unique_ptr< SPOSet > createSPOSet(xmlNodePtr cur, SPOSetInputInfo &input_info) override
initialize with the existing SPOSet
const PSetMap & ParticleSets
reference to the particleset pool
double elapsed() const
Definition: Timer.h:30
Tensor< double, OHMMS_DIM > GGt
Tensor< int, OHMMS_DIM > TileMatrix
void restart()
Definition: Timer.h:29
void barrier() const
std::ostream & app_warning()
Definition: OutputManager.h:69
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
class to read state range information from sposet input
int rank() const
return the rank
Definition: Communicate.h:116
std::map< H5OrbSet, SPOSet *, H5OrbSet > SPOSetMap
std::ostream & app_log()
Definition: OutputManager.h:65
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
std::string myName
name of the object
Definition: MPIObjectBase.h:67
Builder class for einspline-based SPOSet objects.
ParticleSet * SourcePtcl
ionic system
Timer class.
Tensor_t G
Reciprocal unit vectors. G(j,i) i=vector and j=x,y,z.
void AnalyzeTwists2(const int twist_num_inp, const TinyVector< double, OHMMS_DIM > &twist_inp)
analyze twists of orbitals in h5 and determinine twist_num_
std::vector< std::unique_ptr< std::vector< BandInfo > > > FullBands
Helper vector for sorting bands.
static constexpr double TWIST_NO_INPUT
twist_inp[i] <= -9999 to indicate no given input after parsing XML
void bcastSortBands(int splin, int N, bool root)
broadcast SortBands
base class to read data and manage spline tables
Communicate * myComm
pointer to Communicate
Definition: MPIObjectBase.h:62
std::unique_ptr< BsplineReader > createBsplineReal(EinsplineSetBuilder *e, bool use_single, bool hybrid_rep, const std::string &useGPU)
create a reader which handles real splines, R2R case spline storage and computation precision is doub...
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
NewTimer & createGlobalTimer(const std::string &myname, timer_levels mylevel)
std::unique_ptr< BsplineReader > createBsplineComplex(EinsplineSetBuilder *e, bool hybrid_rep, const std::string &useGPU)
create a reader which handles complex (double size real) splines, C2R or C2C case spline storage and ...
BsplineSet is a SPOSet derived class and serves as a base class for B-spline SPO C2C/C2R/R2R implemen...
AntiSymTensor< T, D > transpose(const AntiSymTensor< T, D > &rhs)
void OccupyBands(int spin, int sortBands, int numOrbs, bool skipChecks=false)
std::unique_ptr< BsplineReader > MixedSplineReader
reader to use BsplineReader
construct a name for spline SPO set
static constexpr int TWISTNUM_NO_INPUT
twistnum_inp == -9999 to indicate no given input after parsing XML
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 set_metadata(int numOrbs, int twist_num_inp, const TinyVector< double, OHMMS_DIM > &twist_inp, bool skipChecks=false)
a specific but clean code path in createSPOSetFromXML, for PBC, double, ESHDF
xmlNodePtr XMLRoot
root XML node with href, sort, tilematrix, twistnum, source, precision,truncate,version ...
Tensor< double, OHMMS_DIM > SuperLattice
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
void barrier_and_abort(const std::string &msg) const
std::unique_ptr< SPOSet > createSPOSetFromXML(xmlNodePtr cur) override
initialize the Antisymmetric wave function for electrons
bool get(std::ostream &os) const override
dummy. For satisfying OhmmsElementBase.
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 use_real_splines_
if false, splines are conceptually complex valued
const std::vector< std::string > candidate_values