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: Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 // Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
10 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
11 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
12 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
13 //
14 // File created by: Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
15 //////////////////////////////////////////////////////////////////////////////////////
16
17
18 #include "LCAOrbitalBuilder.h"
19 #include "OhmmsData/AttributeSet.h"
20 #include "QMCWaveFunctions/SPOSet.h"
21 #include "QMCWaveFunctions/LCAO/NGFunctor.h"
22 #include "QMCWaveFunctions/LCAO/MultiQuinticSpline1D.h"
23 #include "QMCWaveFunctions/LCAO/SoaCartesianTensor.h"
24 #include "QMCWaveFunctions/LCAO/SoaSphericalTensor.h"
25 #include "QMCWaveFunctions/LCAO/SoaAtomicBasisSet.h"
26 #include "QMCWaveFunctions/LCAO/SoaLocalizedBasisSet.h"
27 #include "QMCWaveFunctions/LCAO/LCAOrbitalSet.h"
28 //#include "QMCWaveFunctions/LCAO/RadialOrbitalSetBuilder.h"
29 #include "QMCWaveFunctions/LCAO/AOBasisBuilder.h"
30 #include "QMCWaveFunctions/LCAO/MultiFunctorAdapter.h"
31 #if !defined(QMC_COMPLEX)
32 #include "QMCWaveFunctions/LCAO/LCAOrbitalSetWithCorrection.h"
33 #include "QMCWaveFunctions/LCAO/CuspCorrectionConstruction.h"
34 #endif
35 #include "hdf/hdf_archive.h"
36 #include "Message/CommOperators.h"
37 #include "Utilities/ProgressReportEngine.h"
38 #include "config/stdlib/math.hpp"
39
40 namespace qmcplusplus
41 {
42 /** traits for a localized basis set; used by createBasisSet
43 *
44 * T radial function value type
45 * ORBT orbital value type, can be complex
46 * ROT {0=numuerica;, 1=gto; 2=sto}
47 * SH {0=cartesian, 1=spherical}
48 * If too confusing, inroduce enumeration.
49 */
50 template<typename T, typename ORBT, int ROT, int SH>
51 struct ao_traits
52 {};
53
54 /** specialization for numerical-cartesian AO */
55 template<typename T, typename ORBT>
56 struct ao_traits<T, ORBT, 0, 0>
57 {
58 using radial_type = MultiQuinticSpline1D<T>;
59 using angular_type = SoaCartesianTensor<T>;
60 using ao_type = SoaAtomicBasisSet<radial_type, angular_type>;
61 using basis_type = SoaLocalizedBasisSet<ao_type, ORBT>;
62 };
63
64 /** specialization for numerical-spherical AO */
65 template<typename T, typename ORBT>
66 struct ao_traits<T, ORBT, 0, 1>
67 {
68 using radial_type = MultiQuinticSpline1D<T>;
69 using angular_type = SoaSphericalTensor<T>;
70 using ao_type = SoaAtomicBasisSet<radial_type, angular_type>;
71 using basis_type = SoaLocalizedBasisSet<ao_type, ORBT>;
72 };
73
74 /** specialization for GTO-cartesian AO */
75 template<typename T, typename ORBT>
76 struct ao_traits<T, ORBT, 1, 0>
77 {
78 using radial_type = MultiFunctorAdapter<GaussianCombo<T>>;
79 using angular_type = SoaCartesianTensor<T>;
80 using ao_type = SoaAtomicBasisSet<radial_type, angular_type>;
81 using basis_type = SoaLocalizedBasisSet<ao_type, ORBT>;
82 };
83
84 /** specialization for GTO-cartesian AO */
85 template<typename T, typename ORBT>
86 struct ao_traits<T, ORBT, 1, 1>
87 {
88 using radial_type = MultiFunctorAdapter<GaussianCombo<T>>;
89 using angular_type = SoaSphericalTensor<T>;
90 using ao_type = SoaAtomicBasisSet<radial_type, angular_type>;
91 using basis_type = SoaLocalizedBasisSet<ao_type, ORBT>;
92 };
93
94 /** specialization for STO-spherical AO */
95 template<typename T, typename ORBT>
96 struct ao_traits<T, ORBT, 2, 1>
97 {
98 using radial_type = MultiFunctorAdapter<SlaterCombo<T>>;
99 using angular_type = SoaSphericalTensor<T>;
100 using ao_type = SoaAtomicBasisSet<radial_type, angular_type>;
101 using basis_type = SoaLocalizedBasisSet<ao_type, ORBT>;
102 };
103
104
is_same(const xmlChar * a,const char * b)105 inline bool is_same(const xmlChar* a, const char* b) { return !strcmp((const char*)a, b); }
106
107 using BasisSet_t = LCAOrbitalSet::basis_type;
108
LCAOrbitalBuilder(ParticleSet & els,ParticleSet & ions,Communicate * comm,xmlNodePtr cur)109 LCAOrbitalBuilder::LCAOrbitalBuilder(ParticleSet& els, ParticleSet& ions, Communicate* comm, xmlNodePtr cur)
110 : SPOSetBuilder("LCAO", comm),
111 targetPtcl(els),
112 sourcePtcl(ions),
113 h5_path(""),
114 SuperTwist(0.0),
115 doCuspCorrection(false)
116 {
117 ClassName = "LCAOrbitalBuilder";
118 ReportEngine PRE(ClassName, "createBasisSet");
119
120 std::string cuspC("no"); // cusp correction
121 OhmmsAttributeSet aAttrib;
122 aAttrib.add(cuspC, "cuspCorrection");
123 aAttrib.add(h5_path, "href");
124 aAttrib.add(PBCImages, "PBCimages");
125 aAttrib.add(SuperTwist, "twist");
126 aAttrib.put(cur);
127
128 if (cuspC == "yes")
129 doCuspCorrection = true;
130 //Evaluate the Phase factor. Equals 1 for OBC.
131 EvalPeriodicImagePhaseFactors(SuperTwist, PeriodicImagePhaseFactors);
132
133 // no need to wait but load the basis set
134 processChildren(cur, [&](const std::string& cname, const xmlNodePtr element) {
135 if (cname == "basisset")
136 {
137 XMLAttrString basisset_name_input(element, "name");
138 std::string basisset_name(basisset_name_input.empty() ? "LCAOBSet" : basisset_name_input.c_str());
139 if (basisset_map_.find(basisset_name) != basisset_map_.end())
140 {
141 std::ostringstream err_msg;
142 err_msg << "Cannot create basisset " << basisset_name << " which already exists." << std::endl;
143 throw std::runtime_error(err_msg.str());
144 }
145 if (h5_path != "")
146 basisset_map_[basisset_name] = loadBasisSetFromH5(element);
147 else
148 basisset_map_[basisset_name] = loadBasisSetFromXML(element, cur);
149 }
150 });
151
152 // deprecated h5 basis set handling when basisset element is missing
153 if (basisset_map_.size() == 0 && h5_path != "")
154 {
155 app_warning() << "!!!!!!! Deprecated input style: missing basisset element. "
156 << "LCAO needs an explicit basisset XML element. "
157 << "Fallback on loading an implicit one." << std::endl;
158 basisset_map_["LCAOBSet"] = loadBasisSetFromH5(cur);
159 }
160
161 if (basisset_map_.size() == 0)
162 throw std::runtime_error("No basisset found in the XML input!");
163 }
164
~LCAOrbitalBuilder()165 LCAOrbitalBuilder::~LCAOrbitalBuilder()
166 {
167 //properly cleanup
168 }
169
determineRadialOrbType(xmlNodePtr cur) const170 int LCAOrbitalBuilder::determineRadialOrbType(xmlNodePtr cur) const
171 {
172 std::string keyOpt;
173 std::string transformOpt;
174 OhmmsAttributeSet aAttrib;
175 aAttrib.add(keyOpt, "keyword");
176 aAttrib.add(keyOpt, "key");
177 aAttrib.add(transformOpt, "transform");
178 aAttrib.put(cur);
179
180 int radialOrbType = -1;
181 if (transformOpt == "yes" || keyOpt == "NMO")
182 radialOrbType = 0;
183 else
184 {
185 if (keyOpt == "GTO")
186 radialOrbType = 1;
187 if (keyOpt == "STO")
188 radialOrbType = 2;
189 }
190 return radialOrbType;
191 }
192
loadBasisSetFromXML(xmlNodePtr cur,xmlNodePtr parent)193 std::unique_ptr<BasisSet_t> LCAOrbitalBuilder::loadBasisSetFromXML(xmlNodePtr cur, xmlNodePtr parent)
194 {
195 ReportEngine PRE(ClassName, "loadBasisSetFromXML(xmlNodePtr)");
196 int ylm = -1;
197 {
198 xmlNodePtr cur1 = cur->xmlChildrenNode;
199 while (cur1 != NULL && ylm < 0)
200 {
201 if (is_same(cur1->name, "atomicBasisSet"))
202 {
203 std::string sph;
204 OhmmsAttributeSet att;
205 att.add(sph, "angular");
206 att.put(cur1);
207 ylm = (sph == "cartesian") ? 0 : 1;
208 }
209 cur1 = cur1->next;
210 }
211 }
212
213 if (ylm < 0)
214 PRE.error("Missing angular attribute of atomicBasisSet.", true);
215
216 int radialOrbType = determineRadialOrbType(cur);
217 if (radialOrbType < 0)
218 {
219 app_warning() << "Radial orbital type cannot be determined based on the attributes of basisset line. "
220 << "Trying the parent element." << std::endl;
221 radialOrbType = determineRadialOrbType(parent);
222 }
223
224 if (radialOrbType < 0)
225 PRE.error("Unknown radial function for LCAO orbitals. Specify keyword=\"NMO/GTO/STO\" .", true);
226
227 BasisSet_t* myBasisSet = nullptr;
228 /** process atomicBasisSet per ion species */
229 switch (radialOrbType)
230 {
231 case (0): //numerical
232 app_log() << " LCAO: SoaAtomicBasisSet<MultiQuintic," << ylm << ">" << std::endl;
233 if (ylm)
234 myBasisSet = createBasisSet<0, 1>(cur);
235 else
236 myBasisSet = createBasisSet<0, 0>(cur);
237 break;
238 case (1): //gto
239 app_log() << " LCAO: SoaAtomicBasisSet<MultiGTO," << ylm << ">" << std::endl;
240 if (ylm)
241 myBasisSet = createBasisSet<1, 1>(cur);
242 else
243 myBasisSet = createBasisSet<1, 0>(cur);
244 break;
245 case (2): //sto
246 app_log() << " LCAO: SoaAtomicBasisSet<MultiSTO," << ylm << ">" << std::endl;
247 myBasisSet = createBasisSet<2, 1>(cur);
248 break;
249 default:
250 PRE.error("Cannot construct SoaAtomicBasisSet<ROT,YLM>.", true);
251 break;
252 }
253
254 return std::unique_ptr<BasisSet_t>(myBasisSet);
255 }
256
loadBasisSetFromH5(xmlNodePtr parent)257 std::unique_ptr<BasisSet_t> LCAOrbitalBuilder::loadBasisSetFromH5(xmlNodePtr parent)
258 {
259 ReportEngine PRE(ClassName, "loadBasisSetFromH5()");
260
261 hdf_archive hin(myComm);
262 int ylm = -1;
263 if (myComm->rank() == 0)
264 {
265 if (!hin.open(h5_path, H5F_ACC_RDONLY))
266 PRE.error("Could not open H5 file", true);
267 if (!hin.push("basisset"))
268 PRE.error("Could not open basisset group in H5; Probably Corrupt H5 file", true);
269
270 std::string sph;
271 std::string ElemID0 = "atomicBasisSet0";
272 if (!hin.push(ElemID0.c_str()))
273 PRE.error("Could not open group Containing atomic Basis set in H5; Probably Corrupt H5 file", true);
274 if (!hin.readEntry(sph, "angular"))
275 PRE.error("Could not find name of basisset group in H5; Probably Corrupt H5 file", true);
276 ylm = (sph == "cartesian") ? 0 : 1;
277 hin.close();
278 }
279
280 myComm->bcast(ylm);
281 if (ylm < 0)
282 PRE.error("Missing angular attribute of atomicBasisSet.", true);
283
284 int radialOrbType = determineRadialOrbType(parent);
285 if (radialOrbType < 0)
286 PRE.error("Unknown radial function for LCAO orbitals. Specify keyword=\"NMO/GTO/STO\" .", true);
287
288 BasisSet_t* myBasisSet = nullptr;
289 /** process atomicBasisSet per ion species */
290 switch (radialOrbType)
291 {
292 case (0): //numerical
293 app_log() << " LCAO: SoaAtomicBasisSet<MultiQuintic," << ylm << ">" << std::endl;
294 if (ylm)
295 myBasisSet = createBasisSetH5<0, 1>();
296 else
297 myBasisSet = createBasisSetH5<0, 0>();
298 break;
299 case (1): //gto
300 app_log() << " LCAO: SoaAtomicBasisSet<MultiGTO," << ylm << ">" << std::endl;
301 if (ylm)
302 myBasisSet = createBasisSetH5<1, 1>();
303 else
304 myBasisSet = createBasisSetH5<1, 0>();
305 break;
306 case (2): //sto
307 app_log() << " LCAO: SoaAtomicBasisSet<MultiSTO," << ylm << ">" << std::endl;
308 myBasisSet = createBasisSetH5<2, 1>();
309 break;
310 default:
311 PRE.error("Cannot construct SoaAtomicBasisSet<ROT,YLM>.", true);
312 break;
313 }
314 return std::unique_ptr<BasisSet_t>(myBasisSet);
315 }
316
317
318 template<int I, int J>
createBasisSet(xmlNodePtr cur)319 LCAOrbitalBuilder::BasisSet_t* LCAOrbitalBuilder::createBasisSet(xmlNodePtr cur)
320 {
321 ReportEngine PRE(ClassName, "createBasisSet(xmlNodePtr)");
322
323 using ao_type = typename ao_traits<RealType, ValueType, I, J>::ao_type;
324 using basis_type = typename ao_traits<RealType, ValueType, I, J>::basis_type;
325
326 basis_type* mBasisSet = new basis_type(sourcePtcl, targetPtcl);
327
328 //list of built centers
329 std::vector<std::string> ao_built_centers;
330
331 /** process atomicBasisSet per ion species */
332 cur = cur->xmlChildrenNode;
333 while (cur != NULL) //loop over unique ioons
334 {
335 std::string cname((const char*)(cur->name));
336
337 if (cname == "atomicBasisSet")
338 {
339 std::string elementType;
340 std::string sph;
341 OhmmsAttributeSet att;
342 att.add(elementType, "elementType");
343 att.put(cur);
344
345 if (elementType.empty())
346 PRE.error("Missing elementType attribute of atomicBasisSet.", true);
347
348 auto it = std::find(ao_built_centers.begin(), ao_built_centers.end(), elementType);
349 if (it == ao_built_centers.end())
350 {
351 AOBasisBuilder<ao_type> any(elementType, myComm);
352 any.put(cur);
353 ao_type* aoBasis = any.createAOSet(cur);
354 if (aoBasis)
355 {
356 //add the new atomic basis to the basis set
357 int activeCenter = sourcePtcl.getSpeciesSet().findSpecies(elementType);
358 mBasisSet->add(activeCenter, aoBasis);
359 }
360 ao_built_centers.push_back(elementType);
361 }
362 }
363 cur = cur->next;
364 } // done with basis set
365 mBasisSet->setBasisSetSize(-1);
366 mBasisSet->setPBCParams(PBCImages, SuperTwist, PeriodicImagePhaseFactors);
367 return mBasisSet;
368 }
369
370
371 template<int I, int J>
createBasisSetH5()372 LCAOrbitalBuilder::BasisSet_t* LCAOrbitalBuilder::createBasisSetH5()
373 {
374 ReportEngine PRE(ClassName, "createBasisSetH5(xmlNodePtr)");
375
376 using ao_type = typename ao_traits<RealType, ValueType, I, J>::ao_type;
377 using basis_type = typename ao_traits<RealType, ValueType, I, J>::basis_type;
378
379 basis_type* mBasisSet = new basis_type(sourcePtcl, targetPtcl);
380
381 //list of built centers
382 std::vector<std::string> ao_built_centers;
383
384 int Nb_Elements(0);
385 std::string basiset_name;
386
387 /** process atomicBasisSet per ion species */
388 app_log() << "Reading BasisSet from HDF5 file:" << h5_path << std::endl;
389
390 hdf_archive hin(myComm);
391 if (myComm->rank() == 0)
392 {
393 if (!hin.open(h5_path, H5F_ACC_RDONLY))
394 PRE.error("Could not open H5 file", true);
395 if (!hin.push("basisset"))
396 PRE.error("Could not open basisset group in H5; Probably Corrupt H5 file", true);
397 hin.read(Nb_Elements, "NbElements");
398 }
399
400 myComm->bcast(Nb_Elements);
401 if (Nb_Elements < 1)
402 PRE.error("Missing elementType attribute of atomicBasisSet.", true);
403
404 for (int i = 0; i < Nb_Elements; i++)
405 {
406 std::string elementType, dataset;
407 std::stringstream tempElem;
408 std::string ElemID0 = "atomicBasisSet", ElemType;
409 tempElem << ElemID0 << i;
410 ElemType = tempElem.str();
411
412 if (myComm->rank() == 0)
413 {
414 if (!hin.push(ElemType.c_str()))
415 PRE.error("Could not open group Containing atomic Basis set in H5; Probably Corrupt H5 file", true);
416 if (!hin.readEntry(basiset_name, "name"))
417 PRE.error("Could not find name of basisset group in H5; Probably Corrupt H5 file", true);
418 if (!hin.readEntry(elementType, "elementType"))
419 PRE.error("Could not read elementType in H5; Probably Corrupt H5 file", true);
420 }
421 myComm->bcast(basiset_name);
422 myComm->bcast(elementType);
423
424 auto it = std::find(ao_built_centers.begin(), ao_built_centers.end(), elementType);
425 if (it == ao_built_centers.end())
426 {
427 AOBasisBuilder<ao_type> any(elementType, myComm);
428 any.putH5(hin);
429 ao_type* aoBasis = any.createAOSetH5(hin);
430 if (aoBasis)
431 {
432 //add the new atomic basis to the basis set
433 int activeCenter = sourcePtcl.getSpeciesSet().findSpecies(elementType);
434 mBasisSet->add(activeCenter, aoBasis);
435 }
436 ao_built_centers.push_back(elementType);
437 }
438
439 if (myComm->rank() == 0)
440 hin.pop();
441 }
442
443 if (myComm->rank() == 0)
444 {
445 hin.pop();
446 hin.close();
447 }
448 mBasisSet->setBasisSetSize(-1);
449 mBasisSet->setPBCParams(PBCImages, SuperTwist, PeriodicImagePhaseFactors);
450 return mBasisSet;
451 }
452
453
createSPOSetFromXML(xmlNodePtr cur)454 SPOSet* LCAOrbitalBuilder::createSPOSetFromXML(xmlNodePtr cur)
455 {
456 ReportEngine PRE(ClassName, "createSPO(xmlNodePtr)");
457 std::string spo_name(""), id, cusp_file(""), optimize("no");
458 std::string basisset_name("LCAOBSet");
459 OhmmsAttributeSet spoAttrib;
460 spoAttrib.add(spo_name, "name");
461 spoAttrib.add(id, "id");
462 spoAttrib.add(cusp_file, "cuspInfo");
463 spoAttrib.add(optimize, "optimize");
464 spoAttrib.add(basisset_name, "basisset");
465 spoAttrib.put(cur);
466
467 BasisSet_t* myBasisSet = nullptr;
468 if (basisset_map_.find(basisset_name) == basisset_map_.end())
469 myComm->barrier_and_abort("basisset \"" + basisset_name + "\" cannot be found\n");
470 else
471 myBasisSet = basisset_map_[basisset_name]->makeClone();
472
473 if (optimize == "yes")
474 app_log() << " SPOSet " << spo_name << " is optimizable\n";
475
476 LCAOrbitalSet* lcos = nullptr;
477 #if !defined(QMC_COMPLEX)
478 LCAOrbitalSetWithCorrection* lcwc = nullptr;
479 if (doCuspCorrection)
480 {
481 app_summary() << " Using cusp correction." << std::endl;
482 lcos = lcwc = new LCAOrbitalSetWithCorrection(sourcePtcl, targetPtcl, std::unique_ptr<BasisSet_t>(myBasisSet),
483 optimize == "yes");
484 }
485 else
486 lcos = new LCAOrbitalSet(std::unique_ptr<BasisSet_t>(myBasisSet), optimize == "yes");
487 #else
488 lcos = new LCAOrbitalSet(std::unique_ptr<BasisSet_t>(myBasisSet), optimize == "yes");
489 #endif
490 loadMO(*lcos, cur);
491
492 #if !defined(QMC_COMPLEX)
493 if (doCuspCorrection)
494 {
495 int num_centers = sourcePtcl.getTotalNum();
496
497 // Sometimes sposet attribute is 'name' and sometimes it is 'id'
498 if (id == "")
499 id = spo_name;
500
501 int orbital_set_size = lcos->getOrbitalSetSize();
502 Matrix<CuspCorrectionParameters> info(num_centers, orbital_set_size);
503
504 bool valid = false;
505 if (myComm->rank() == 0)
506 {
507 valid = readCuspInfo(cusp_file, id, orbital_set_size, info);
508 }
509 #ifdef HAVE_MPI
510 myComm->comm.broadcast_value(valid);
511 if (valid)
512 {
513 for (int orb_idx = 0; orb_idx < orbital_set_size; orb_idx++)
514 {
515 for (int center_idx = 0; center_idx < num_centers; center_idx++)
516 {
517 broadcastCuspInfo(info(center_idx, orb_idx), *myComm, 0);
518 }
519 }
520 }
521 #endif
522 if (!valid)
523 {
524 generateCuspInfo(orbital_set_size, num_centers, info, targetPtcl, sourcePtcl, *lcwc, id, *myComm);
525 }
526
527 applyCuspCorrection(info, num_centers, orbital_set_size, targetPtcl, sourcePtcl, *lcwc, id);
528 }
529 #endif
530
531 return lcos;
532 }
533
534
535 /** Parse the xml file for information on the Dirac determinants.
536 *@param cur the current xmlNode
537 */
loadMO(LCAOrbitalSet & spo,xmlNodePtr cur)538 bool LCAOrbitalBuilder::loadMO(LCAOrbitalSet& spo, xmlNodePtr cur)
539 {
540 #undef FunctionName
541 #define FunctionName \
542 printf("Calling FunctionName from %s\n", __FUNCTION__); \
543 FunctionNameReal
544 //Check if HDF5 present
545 ReportEngine PRE("LCAOrbitalBuilder", "put(xmlNodePtr)");
546
547 //initialize the number of orbital by the basis set size
548 int norb = spo.getBasisSetSize();
549 std::string debugc("no");
550 double orbital_mix_magnitude = 0.0;
551 bool PBC = false;
552 OhmmsAttributeSet aAttrib;
553 aAttrib.add(norb, "orbitals");
554 aAttrib.add(norb, "size");
555 aAttrib.add(debugc, "debug");
556 aAttrib.add(orbital_mix_magnitude, "orbital_mix_magnitude");
557 aAttrib.put(cur);
558 xmlNodePtr occ_ptr = NULL;
559 xmlNodePtr coeff_ptr = NULL;
560 cur = cur->xmlChildrenNode;
561 while (cur != NULL)
562 {
563 std::string cname((const char*)(cur->name));
564 if (cname == "occupation")
565 {
566 occ_ptr = cur;
567 }
568 else if (cname.find("coeff") < cname.size() || cname == "parameter" || cname == "Var")
569 {
570 coeff_ptr = cur;
571 }
572 cur = cur->next;
573 }
574 if (coeff_ptr == NULL)
575 {
576 app_log() << " Using Identity for the LCOrbitalSet " << std::endl;
577 return true;
578 }
579 spo.setOrbitalSetSize(norb);
580 bool success = putOccupation(spo, occ_ptr);
581 if (h5_path == "")
582 success = putFromXML(spo, coeff_ptr);
583 else
584 {
585 hdf_archive hin(myComm);
586
587 if (myComm->rank() == 0)
588 {
589 if (!hin.open(h5_path, H5F_ACC_RDONLY))
590 APP_ABORT("LCAOrbitalBuilder::putFromH5 missing or incorrect path to H5 file.");
591 //TO REVIEWERS:: IDEAL BEHAVIOUR SHOULD BE:
592 /*
593 if(!hin.push("PBC")
594 PBC=false;
595 else
596 if (!hin.readEntry(PBC,"PBC"))
597 APP_ABORT("Could not read PBC dataset in H5 file. Probably corrupt file!!!.");
598 // However, it always succeeds to enter the if condition even if the group does not exists...
599 */
600 hin.push("PBC");
601 PBC = false;
602 hin.read(PBC, "PBC");
603 hin.close();
604 }
605 myComm->bcast(PBC);
606 if (PBC)
607 success = putPBCFromH5(spo, coeff_ptr);
608 else
609 success = putFromH5(spo, coeff_ptr);
610 }
611
612 // Ye: used to construct cusp correction
613 //bool success2 = transformSPOSet();
614 if (debugc == "yes")
615 {
616 app_log() << " Single-particle orbital coefficients dims=" << spo.C->rows() << " x " << spo.C->cols()
617 << std::endl;
618 app_log() << *spo.C << std::endl;
619 }
620
621 return success;
622 }
623
putFromXML(LCAOrbitalSet & spo,xmlNodePtr coeff_ptr)624 bool LCAOrbitalBuilder::putFromXML(LCAOrbitalSet& spo, xmlNodePtr coeff_ptr)
625 {
626 int norbs = 0;
627 OhmmsAttributeSet aAttrib;
628 aAttrib.add(norbs, "size");
629 aAttrib.add(norbs, "orbitals");
630 aAttrib.put(coeff_ptr);
631 if (norbs < spo.getOrbitalSetSize())
632 {
633 return false;
634 APP_ABORT("LCAOrbitalBuilder::putFromXML missing or incorrect size");
635 }
636 if (norbs)
637 {
638 std::vector<ValueType> Ctemp;
639 int BasisSetSize = spo.getBasisSetSize();
640 Ctemp.resize(norbs * BasisSetSize);
641 putContent(Ctemp, coeff_ptr);
642 int n = 0, i = 0;
643 std::vector<ValueType>::iterator cit(Ctemp.begin());
644 while (i < spo.getOrbitalSetSize())
645 {
646 if (Occ[n] > std::numeric_limits<RealType>::epsilon())
647 {
648 std::copy(cit, cit + BasisSetSize, (*spo.C)[i]);
649 i++;
650 }
651 n++;
652 cit += BasisSetSize;
653 }
654 }
655 return true;
656 }
657
658 /** read data from a hdf5 file
659 * @param norb number of orbitals to be initialized
660 * @param coeff_ptr xmlnode for coefficients
661 */
putFromH5(LCAOrbitalSet & spo,xmlNodePtr coeff_ptr)662 bool LCAOrbitalBuilder::putFromH5(LCAOrbitalSet& spo, xmlNodePtr coeff_ptr)
663 {
664 #if defined(HAVE_LIBHDF5)
665 int neigs = spo.getBasisSetSize();
666 int setVal = -1;
667 std::string setname;
668 OhmmsAttributeSet aAttrib;
669 aAttrib.add(setVal, "spindataset");
670 aAttrib.add(neigs, "size");
671 aAttrib.add(neigs, "orbitals");
672 aAttrib.put(coeff_ptr);
673 hdf_archive hin(myComm);
674 if (myComm->rank() == 0)
675 {
676 if (!hin.open(h5_path, H5F_ACC_RDONLY))
677 APP_ABORT("LCAOrbitalBuilder::putFromH5 missing or incorrect path to H5 file.");
678
679 Matrix<RealType> Ctemp;
680 char name[72];
681
682 //This is to make sure of Backward compatibility with previous tags.
683 sprintf(name, "%s%d", "/Super_Twist/eigenset_", setVal);
684 setname = name;
685 if (!hin.readEntry(Ctemp, setname))
686 {
687 sprintf(name, "%s%d", "/KPTS_0/eigenset_", setVal);
688 setname = name;
689 if (!hin.readEntry(Ctemp, setname))
690 {
691 setname = "LCAOrbitalBuilder::putFromH5 Missing " + setname + " from HDF5 File.";
692 APP_ABORT(setname.c_str());
693 }
694 }
695 hin.close();
696
697 if (Ctemp.cols() != spo.getBasisSetSize())
698 {
699 std::ostringstream err_msg;
700 err_msg << "Basis set size " << spo.getBasisSetSize() << " mismatched the number of MO coefficients columns "
701 << Ctemp.cols() << " from h5." << std::endl;
702 myComm->barrier_and_abort(err_msg.str());
703 }
704
705 int norbs = spo.getOrbitalSetSize();
706 if (Ctemp.rows() < norbs)
707 {
708 std::ostringstream err_msg;
709 err_msg << "Need " << norbs << " orbitals. Insufficient rows of MO coefficients " << Ctemp.rows() << " from h5."
710 << std::endl;
711 myComm->barrier_and_abort(err_msg.str());
712 }
713
714 int n = 0, i = 0;
715 while (i < norbs)
716 {
717 if (Occ[n] > 0.0)
718 {
719 std::copy(Ctemp[n], Ctemp[n + 1], (*spo.C)[i]);
720 i++;
721 }
722 n++;
723 }
724 }
725 myComm->bcast(spo.C->data(), spo.C->size());
726 #else
727 APP_ABORT("LCAOrbitalBuilder::putFromH5 HDF5 is disabled.")
728 #endif
729 return true;
730 }
731
732
733 /** read data from a hdf5 file
734 * @param norb number of orbitals to be initialized
735 * @param coeff_ptr xmlnode for coefficients
736 */
putPBCFromH5(LCAOrbitalSet & spo,xmlNodePtr coeff_ptr)737 bool LCAOrbitalBuilder::putPBCFromH5(LCAOrbitalSet& spo, xmlNodePtr coeff_ptr)
738 {
739 #if defined(HAVE_LIBHDF5)
740 ReportEngine PRE("LCAOrbitalBuilder", "LCAOrbitalBuilder::putPBCFromH5");
741 int norbs = spo.getOrbitalSetSize();
742 int neigs = spo.getBasisSetSize();
743 int setVal = -1;
744 bool IsComplex = false;
745 bool MultiDet = false;
746 PosType SuperTwist(0.0);
747 PosType SuperTwistH5(0.0);
748 OhmmsAttributeSet aAttrib;
749 aAttrib.add(setVal, "spindataset");
750 aAttrib.add(neigs, "size");
751 aAttrib.add(neigs, "orbitals");
752 aAttrib.put(coeff_ptr);
753 hdf_archive hin(myComm);
754
755 xmlNodePtr curtemp = coeff_ptr;
756
757 std::string xmlTag("determinantset");
758 std::string MSDTag("sposet");
759 std::string SDTag("determinant");
760 std::string EndTag("qmcsystem");
761 std::string curname;
762
763 do
764 {
765 std::stringstream ss;
766 curtemp = curtemp->parent;
767 ss << curtemp->name;
768 ss >> curname;
769 if (curname == MSDTag)
770 MultiDet = true; ///Used to know if running an MSD calculation - needed for order of Orbitals.
771 if (curname == SDTag)
772 MultiDet = false;
773
774 } while ((xmlTag != curname) && (curname != EndTag));
775 if (curname == EndTag)
776 {
777 APP_ABORT(
778 "Could not find in wf file the \"sposet\" or \"determinant\" tags. Please verify input or contact developers");
779 }
780
781 aAttrib.add(SuperTwist, "twist");
782 aAttrib.put(curtemp);
783
784 if (myComm->rank() == 0)
785 {
786 if (!hin.open(h5_path, H5F_ACC_RDONLY))
787 APP_ABORT("LCAOrbitalBuilder::putFromH5 missing or incorrect path to H5 file.");
788 hin.push("parameters");
789 hin.read(IsComplex, "IsComplex");
790 hin.pop();
791
792 std::string setname("/Super_Twist/Coord");
793 hin.read(SuperTwistH5, setname);
794 if (std::abs(SuperTwistH5[0] - SuperTwist[0]) >= 1e-6 || std::abs(SuperTwistH5[1] - SuperTwist[1]) >= 1e-6 ||
795 std::abs(SuperTwistH5[2] - SuperTwist[2]) >= 1e-6)
796 {
797 app_log() << "Super Twist in XML : " << SuperTwist[0] << " In H5:" << SuperTwistH5[0] << std::endl;
798 app_log() << " " << SuperTwist[1] << " " << SuperTwistH5[1] << std::endl;
799 app_log() << " " << SuperTwist[2] << " " << SuperTwistH5[2] << std::endl;
800 app_log() << "Diff in Coord x :" << std::abs(SuperTwistH5[0] - SuperTwist[0]) << std::endl;
801 app_log() << " y :" << std::abs(SuperTwistH5[1] - SuperTwist[1]) << std::endl;
802 app_log() << " z :" << std::abs(SuperTwistH5[2] - SuperTwist[2]) << std::endl;
803 APP_ABORT("Requested Super Twist in XML and Super Twist in HDF5 do not Match!!! Aborting.");
804 }
805 //SuperTwist=SuperTwistH5;
806 Matrix<ValueType> Ctemp;
807 LoadFullCoefsFromH5(hin, setVal, SuperTwist, Ctemp, MultiDet);
808
809 int n = 0, i = 0;
810 while (i < norbs)
811 {
812 if (Occ[n] > 0.0)
813 {
814 std::copy(Ctemp[n], Ctemp[n + 1], (*spo.C)[i]);
815 i++;
816 }
817 n++;
818 }
819
820 hin.close();
821 }
822 #ifdef HAVE_MPI
823 myComm->comm.broadcast_n(spo.C->data(), spo.C->size());
824 #endif
825
826 #else
827 APP_ABORT("LCAOrbitalBuilder::putFromH5 HDF5 is disabled.")
828 #endif
829 return true;
830 }
831
832
putOccupation(LCAOrbitalSet & spo,xmlNodePtr occ_ptr)833 bool LCAOrbitalBuilder::putOccupation(LCAOrbitalSet& spo, xmlNodePtr occ_ptr)
834 {
835 //die??
836 if (spo.getBasisSetSize() == 0)
837 {
838 APP_ABORT("LCAOrbitalBuilder::putOccupation detected ZERO BasisSetSize");
839 return false;
840 }
841 Occ.resize(std::max(spo.getBasisSetSize(), spo.getOrbitalSetSize()));
842 Occ = 0.0;
843 for (int i = 0; i < spo.getOrbitalSetSize(); i++)
844 Occ[i] = 1.0;
845 std::vector<int> occ_in;
846 std::string occ_mode("table");
847 if (occ_ptr == NULL)
848 {
849 occ_mode = "ground";
850 }
851 else
852 {
853 const XMLAttrString o(occ_ptr, "mode");
854 if (!o.empty())
855 occ_mode = o;
856 }
857 //Do nothing if mode == ground
858 if (occ_mode == "excited")
859 {
860 putContent(occ_in, occ_ptr);
861 for (int k = 0; k < occ_in.size(); k++)
862 {
863 if (occ_in[k] < 0) //remove this, -1 is to adjust the base
864 Occ[-occ_in[k] - 1] = 0.0;
865 else
866 Occ[occ_in[k] - 1] = 1.0;
867 }
868 }
869 else if (occ_mode == "table")
870 {
871 putContent(Occ, occ_ptr);
872 }
873 return true;
874 }
875
readRealMatrixFromH5(hdf_archive & hin,const std::string & setname,Matrix<LCAOrbitalBuilder::RealType> & Creal) const876 void LCAOrbitalBuilder::readRealMatrixFromH5(hdf_archive& hin,
877 const std::string& setname,
878 Matrix<LCAOrbitalBuilder::RealType>& Creal) const
879 {
880 if (!hin.readEntry(Creal, setname))
881 {
882 std::string error_msg = "LCAOrbitalBuilder::readRealMatrixFromH5 Missing " + setname + " from HDF5 File.";
883 APP_ABORT(error_msg.c_str());
884 }
885 }
886
LoadFullCoefsFromH5(hdf_archive & hin,int setVal,PosType & SuperTwist,Matrix<std::complex<RealType>> & Ctemp,bool MultiDet)887 void LCAOrbitalBuilder::LoadFullCoefsFromH5(hdf_archive& hin,
888 int setVal,
889 PosType& SuperTwist,
890 Matrix<std::complex<RealType>>& Ctemp,
891 bool MultiDet)
892 {
893 Matrix<RealType> Creal;
894 Matrix<RealType> Ccmplx;
895
896 char name[72];
897 std::string setname;
898 ///When running Single Determinant calculations, MO coeff loaded based on occupation and lowest eingenvalue.
899 ///However, for solids with multideterminants, orbitals are order by kpoints; first all MOs for kpoint 1, then 2 etc
900 /// The multideterminants occupation is specified in the input/HDF5 and theefore as long as there is consistency between
901 /// the order in which we read the orbitals and the occupation, we are safe. In the case of Multideterminants generated
902 /// by pyscf and Quantum Package, They are stored in the same order as generated for quantum package and one should use
903 /// the orbitals labelled eigenset_unsorted.
904
905 if (MultiDet == false)
906 sprintf(name, "%s%d", "/Super_Twist/eigenset_", setVal);
907 else
908 sprintf(name, "%s%d", "/Super_Twist/eigenset_unsorted_", setVal);
909
910 setname = name;
911 readRealMatrixFromH5(hin, setname, Creal);
912
913 bool IsComplex = true;
914 hin.read(IsComplex, "/parameters/IsComplex");
915 if (IsComplex == false)
916 {
917 Ccmplx.resize(Creal.rows(), Creal.cols());
918 Ccmplx = 0.0;
919 }
920 else
921 {
922 setname = std::string(name) + "_imag";
923 readRealMatrixFromH5(hin, setname, Ccmplx);
924 }
925
926 Ctemp.resize(Creal.rows(), Creal.cols());
927 for (int i = 0; i < Ctemp.rows(); i++)
928 for (int j = 0; j < Ctemp.cols(); j++)
929 Ctemp[i][j] = std::complex<RealType>(Creal[i][j], Ccmplx[i][j]);
930 }
931
LoadFullCoefsFromH5(hdf_archive & hin,int setVal,PosType & SuperTwist,Matrix<RealType> & Creal,bool MultiDet)932 void LCAOrbitalBuilder::LoadFullCoefsFromH5(hdf_archive& hin,
933 int setVal,
934 PosType& SuperTwist,
935 Matrix<RealType>& Creal,
936 bool MultiDet)
937 {
938 bool IsComplex = false;
939 hin.read(IsComplex, "/parameters/IsComplex");
940 if (IsComplex &&
941 (std::abs(SuperTwist[0]) >= 1e-6 || std::abs(SuperTwist[1]) >= 1e-6 || std::abs(SuperTwist[2]) >= 1e-6))
942 {
943 std::string setname("This Wavefunction is Complex and you are using the real version of QMCPACK. "
944 "Please re-run this job with the Complex build of QMCPACK.");
945 APP_ABORT(setname.c_str());
946 }
947
948 char name[72];
949 bool PBC = false;
950 hin.read(PBC, "/PBC/PBC");
951 if (MultiDet && PBC)
952 sprintf(name, "%s%d", "/Super_Twist/eigenset_unsorted_", setVal);
953 else
954 sprintf(name, "%s%d", "/Super_Twist/eigenset_", setVal);
955 readRealMatrixFromH5(hin, name, Creal);
956 }
957
958 /// Periodic Image Phase Factors computation to be determined
EvalPeriodicImagePhaseFactors(PosType SuperTwist,std::vector<RealType> & LocPeriodicImagePhaseFactors)959 void LCAOrbitalBuilder::EvalPeriodicImagePhaseFactors(PosType SuperTwist,
960 std::vector<RealType>& LocPeriodicImagePhaseFactors)
961 {
962 const int NbImages = (PBCImages[0] + 1) * (PBCImages[1] + 1) * (PBCImages[2] + 1);
963 LocPeriodicImagePhaseFactors.resize(NbImages);
964 for (size_t i = 0; i < NbImages; i++)
965 LocPeriodicImagePhaseFactors[i] = 1.0;
966 }
967
EvalPeriodicImagePhaseFactors(PosType SuperTwist,std::vector<std::complex<RealType>> & LocPeriodicImagePhaseFactors)968 void LCAOrbitalBuilder::EvalPeriodicImagePhaseFactors(PosType SuperTwist,
969 std::vector<std::complex<RealType>>& LocPeriodicImagePhaseFactors)
970 {
971 // Allow computation to continue with no HDF file if the system has open boundary conditions.
972 // The complex build is usually only used with open BC for testing.
973 bool usesOpenBC = PBCImages[0] == 0 && PBCImages[1] == 0 && PBCImages[2] == 0;
974
975 ///Exp(ik.g) where i is imaginary, k is the supertwist and g is the translation vector PBCImage.
976 if (h5_path != "" && !usesOpenBC)
977 {
978 hdf_archive hin(myComm);
979 if (myComm->rank() == 0)
980 {
981 if (!hin.open(h5_path, H5F_ACC_RDONLY))
982 APP_ABORT("Could not open H5 file");
983 if (!hin.push("Cell"))
984 APP_ABORT("Could not open Cell group in H5; Probably Corrupt H5 file; accessed from LCAOrbitalBuilder");
985 if (!hin.readEntry(Lattice, "LatticeVectors"))
986 APP_ABORT("Could not open Lattice vectors in H5; Probably Corrupt H5 file; accessed from LCAOrbitalBuilder");
987 hin.close();
988 }
989 for (int i = 0; i < 3; i++)
990 for (int j = 0; j < 3; j++)
991 myComm->bcast(Lattice(i, j));
992 }
993 else if (!usesOpenBC)
994 {
995 APP_ABORT("Attempting to run PBC LCAO with no HDF5 support. Behaviour is unknown. Safer to exit");
996 }
997
998 int phase_idx = 0;
999 int TransX, TransY, TransZ;
1000 RealType phase;
1001
1002 for (int i = 0; i <= PBCImages[0]; i++) //loop Translation over X
1003 {
1004 TransX = ((i % 2) * 2 - 1) * ((i + 1) / 2);
1005 for (int j = 0; j <= PBCImages[1]; j++) //loop Translation over Y
1006 {
1007 TransY = ((j % 2) * 2 - 1) * ((j + 1) / 2);
1008 for (int k = 0; k <= PBCImages[2]; k++) //loop Translation over Z
1009 {
1010 TransZ = ((k % 2) * 2 - 1) * ((k + 1) / 2);
1011 RealType s, c;
1012 PosType Val;
1013 Val[0] = TransX * Lattice(0, 0) + TransY * Lattice(1, 0) + TransZ * Lattice(2, 0);
1014 Val[1] = TransX * Lattice(0, 1) + TransY * Lattice(1, 1) + TransZ * Lattice(2, 1);
1015 Val[2] = TransX * Lattice(0, 2) + TransY * Lattice(1, 2) + TransZ * Lattice(2, 2);
1016
1017 phase = dot(SuperTwist, Val);
1018 qmcplusplus::sincos(phase, &s, &c);
1019
1020 LocPeriodicImagePhaseFactors.emplace_back(c, s);
1021 }
1022 }
1023 }
1024 }
1025 } // namespace qmcplusplus
1026