QMCPACK
ECPotentialBuilder.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) 2020 QMCPACK developers.
6 //
7 // File developed by: Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
11 // Cody A. Melton, cmelton@sandia.gov, Sandia National Laboratories
12 //
13 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
14 //////////////////////////////////////////////////////////////////////////////////////
15 
16 
17 #include "ECPotentialBuilder.h"
23 #include "OhmmsData/AttributeSet.h"
25 
26 namespace qmcplusplus
27 {
28 /** constructor
29  *\param ions the positions of the ions
30  *\param els the positions of the electrons
31  *\param psi trial wavefunction
32  */
34  ParticleSet& ions,
35  ParticleSet& els,
36  TrialWaveFunction& psi,
37  Communicate* c)
38  : MPIObjectBase(c),
39  hasLocalPot(false),
40  hasNonLocalPot(false),
41  hasSOPot(false),
42  hasL2Pot(false),
43  targetH(h),
44  IonConfig(ions),
45  targetPtcl(els),
46  targetPsi(psi)
47 {}
48 
50 
51 bool ECPotentialBuilder::put(xmlNodePtr cur)
52 {
53  if (localPot.empty())
54  {
55  int ng = IonConfig.getSpeciesSet().getTotalNum();
56  localZeff.resize(ng, 1);
57  localPot.resize(ng);
58  nonLocalPot.resize(ng);
59  soPot.resize(ng);
60  L2Pot.resize(ng);
61  }
62  std::string ecpFormat;
63  std::string NLPP_algo;
64  std::string use_DLA;
65  std::string pbc;
66  std::string forces;
67  std::string physicalSO;
68  std::string spin_integrator;
69 
70  OhmmsAttributeSet pAttrib;
71  pAttrib.add(ecpFormat, "format", {"table", "xml"});
72  pAttrib.add(NLPP_algo, "algorithm", {"batched", "non-batched"});
73  pAttrib.add(use_DLA, "DLA", {"no", "yes"});
74  pAttrib.add(pbc, "pbc", {"yes", "no"});
75  pAttrib.add(forces, "forces", {"no", "yes"});
76  pAttrib.add(physicalSO, "physicalSO", {"yes", "no"});
77  pAttrib.add(spin_integrator, "spin_integrator", {"exact", "simpson"});
78  pAttrib.put(cur);
79 
80  bool doForces = (forces == "yes") || (forces == "true");
81  if (use_DLA == "yes")
82  app_log() << " Using determinant localization approximation (DLA)" << std::endl;
83 
84  use_exact_spin = (spin_integrator == "exact") ? true : false;
85  if (ecpFormat == "xml")
86  {
87  useXmlFormat(cur);
88  }
89  else
90  {
92  }
93 
94  ///create LocalECPotential
95  bool usePBC = !(IonConfig.getLattice().SuperCellEnum == SUPERCELL_OPEN || pbc == "no");
96 
97 
98  if (hasLocalPot)
99  {
100  if (IonConfig.getLattice().SuperCellEnum == SUPERCELL_OPEN || pbc == "no")
101  {
102  std::unique_ptr<LocalECPotential> apot = std::make_unique<LocalECPotential>(IonConfig, targetPtcl);
103  for (int i = 0; i < localPot.size(); i++)
104  if (localPot[i])
105  apot->add(i, std::move(localPot[i]), localZeff[i]);
106  targetH.addOperator(std::move(apot), "LocalECP");
107  }
108  else
109  {
110  if (doForces)
111  app_log() << " Will compute forces in CoulombPBCAB.\n" << std::endl;
112  std::unique_ptr<CoulombPBCAB> apot = std::make_unique<CoulombPBCAB>(IonConfig, targetPtcl, doForces);
113  for (int i = 0; i < localPot.size(); i++)
114  {
115  if (localPot[i])
116  apot->add(i, std::move(localPot[i]));
117  }
118  targetH.addOperator(std::move(apot), "LocalECP");
119  }
120  }
121  if (hasNonLocalPot)
122  {
123  std::unique_ptr<NonLocalECPotential> apot =
124  std::make_unique<NonLocalECPotential>(IonConfig, targetPtcl, targetPsi, doForces, use_DLA == "yes");
125 
126  int nknot_max = 0;
127  // These are actually NonLocalECPComponents
128  for (int i = 0; i < nonLocalPot.size(); i++)
129  {
130  if (nonLocalPot[i])
131  {
132  nknot_max = std::max(nknot_max, nonLocalPot[i]->getNknot());
133  if (NLPP_algo == "batched")
134  nonLocalPot[i]->initVirtualParticle(targetPtcl);
135  apot->addComponent(i, std::move(nonLocalPot[i]));
136  }
137  }
138  app_log() << "\n Using NonLocalECP potential \n"
139  << " Maximum grid on a sphere for NonLocalECPotential: " << nknot_max << std::endl;
140  if (NLPP_algo == "batched")
141  app_log() << " Using batched ratio computing in NonLocalECP" << std::endl;
142 
143  targetH.addOperator(std::move(apot), "NonLocalECP");
144  }
145  if (hasSOPot)
146  {
147 #ifndef QMC_COMPLEX
148  APP_ABORT("SOECPotential evaluations require complex build. Rebuild with -D QMC_COMPLEX=1\n");
149 #endif
150  if (physicalSO == "yes")
151  app_log() << " Spin-Orbit potential included in local energy" << std::endl;
152  else if (physicalSO == "no")
153  app_log() << " Spin-Orbit potential is not included in local energy" << std::endl;
154  else
155  APP_ABORT("physicalSO must be set to yes/no. Unknown option given\n");
156 
157  std::unique_ptr<SOECPotential> apot = std::make_unique<SOECPotential>(IonConfig, targetPtcl, targetPsi, use_exact_spin);
158  int nknot_max = 0;
159  int sknot_max = 0;
160  for (int i = 0; i < soPot.size(); i++)
161  {
162  if (soPot[i])
163  {
164  nknot_max = std::max(nknot_max, soPot[i]->getNknot());
165  sknot_max = std::max(sknot_max, soPot[i]->getSknot());
166  if (NLPP_algo == "batched")
167  soPot[i]->initVirtualParticle(targetPtcl);
168  apot->addComponent(i, std::move(soPot[i]));
169  }
170  }
171  app_log() << "\n Using SOECP potential \n"
172  << " Maximum grid on a sphere for SOECPotential: " << nknot_max << std::endl;
173  if (use_exact_spin)
174  app_log() << " Using fast SOECP evaluation. Spin integration is exact" << std::endl;
175  else
176  app_log() << " Maximum grid for Simpson's rule for spin integral: " << sknot_max << std::endl;
177  if (NLPP_algo == "batched")
178  app_log() << " Using batched ratio computing in SOECP potential" << std::endl;
179  if (physicalSO == "yes")
180  targetH.addOperator(std::move(apot), "SOECP"); //default is physical operator
181  else
182  targetH.addOperator(std::move(apot), "SOECP", false);
183  }
184  if (hasL2Pot)
185  {
186  std::unique_ptr<L2Potential> apot = std::make_unique<L2Potential>(IonConfig, targetPtcl, targetPsi);
187  for (int i = 0; i < L2Pot.size(); i++)
188  if (L2Pot[i])
189  apot->add(i, std::move(L2Pot[i]));
190  app_log() << "\n Using L2 potential" << std::endl;
191  targetH.addOperator(std::move(apot), "L2");
192  }
193 
194  app_log().flush();
195  return true;
196 }
197 
199 {
200  cur = cur->children;
201  while (cur != NULL)
202  {
203  std::string cname((const char*)cur->name);
204  if (cname == "pseudo")
205  {
206  std::string href("none");
207  std::string ionName("none");
208  std::string format("xml");
209  int nrule = -1;
210  int llocal = -1;
211  bool disable_randomize_grid;
212  //RealType rc(2.0);//use 2 Bohr
213  OhmmsAttributeSet hAttrib;
214  hAttrib.add(href, "href");
215  hAttrib.add(ionName, "elementType");
216  hAttrib.add(ionName, "symbol");
217  hAttrib.add(format, "format");
218  hAttrib.add(nrule, "nrule");
219  hAttrib.add(llocal, "l-local");
220  hAttrib.add(disable_randomize_grid, "disable_randomize_grid", {false, true});
221  //hAttrib.add(rc,"cutoff");
222  hAttrib.put(cur);
223  SpeciesSet& ion_species(IonConfig.getSpeciesSet());
224  int speciesIndex = ion_species.findSpecies(ionName);
225  int chargeIndex = ion_species.findAttribute("charge");
226  int AtomicNumberIndex = ion_species.findAttribute("atomicnumber");
227  if (AtomicNumberIndex == -1)
228  AtomicNumberIndex = ion_species.findAttribute("atomic_number");
229  bool success = false;
230  if (speciesIndex < ion_species.getTotalNum())
231  {
232  app_log() << std::endl << " Adding pseudopotential for " << ionName << std::endl;
233 
234  //Use simpsons rule for spin integral if not using exact spin integration
235  int srule = use_exact_spin ? 0 : 8;
236  ECPComponentBuilder ecp(ionName, myComm, nrule, llocal, srule);
237  if (format == "xml")
238  {
239  if (href == "none")
240  {
241  success = ecp.put(cur);
242  }
243  else
244  {
245  success = ecp.parse(href, cur);
246  }
247  }
248  else if (format == "casino")
249  {
250  //success=ecp.parseCasino(href,rc);
251  success = ecp.parseCasino(href, cur);
252  }
253  if (success)
254  {
255  if (OHMMS::Controller->rank() == 0)
256  ecp.printECPTable();
257  if (ecp.pp_loc)
258  {
259  localPot[speciesIndex] = std::move(ecp.pp_loc);
260  localZeff[speciesIndex] = ecp.Zeff;
261  hasLocalPot = true;
262  }
263  if (ecp.pp_nonloc)
264  {
265  if (disable_randomize_grid)
266  app_warning() << "NLPP grid randomization is turned off. This setting should only be used for testing."
267  << std::endl;
268  ecp.pp_nonloc->set_randomize_grid(!disable_randomize_grid);
269  hasNonLocalPot = true;
270  nonLocalPot[speciesIndex] = std::move(ecp.pp_nonloc);
271  }
272  if (ecp.pp_so)
273  {
274  hasSOPot = true;
275  soPot[speciesIndex] = std::move(ecp.pp_so);
276  }
277  if (ecp.pp_L2)
278  {
279  hasL2Pot = true;
280  L2Pot[speciesIndex] = std::move(ecp.pp_L2);
281  }
282  if (chargeIndex == -1)
283  {
284  app_error() << " Ion species " << ionName << " needs parameter \'charge\'" << std::endl;
285  success = false;
286  }
287  else
288  {
289  RealType ion_charge = ion_species(chargeIndex, speciesIndex);
290  if (std::fabs(ion_charge - ecp.Zeff) > 1e-4)
291  {
292  app_error() << " Ion species " << ionName << " charge " << ion_charge << " pseudopotential charge "
293  << ecp.Zeff << " mismatch!" << std::endl;
294  success = false;
295  }
296  }
297  if (AtomicNumberIndex == -1)
298  {
299  app_error() << " Ion species " << ionName << " needs parameter \'atomicnumber\'" << std::endl;
300  success = false;
301  }
302  else
303  {
304  int atomic_number = ion_species(AtomicNumberIndex, speciesIndex);
305  if (atomic_number != ecp.AtomicNumber)
306  {
307  app_error() << " Ion species " << ionName << " atomicnumber " << atomic_number
308  << " pseudopotential atomic-number " << ecp.AtomicNumber << " mismatch!" << std::endl;
309  success = false;
310  }
311  }
312  }
313  }
314  else
315  {
316  app_error() << " Ion species " << ionName << " is not found." << std::endl;
317  }
318  if (!success)
319  {
320  app_error() << " Failed to add pseudopotential for element " << ionName << std::endl;
321  myComm->barrier_and_abort("ECPotentialBuilder::useXmlFormat failed!");
322  }
323  }
324  cur = cur->next;
325  }
326 }
327 
328 /** reimplement simple table format used by NonLocalPPotential
329  */
331 {
332  SpeciesSet& Species(IonConfig.getSpeciesSet());
333  int ng(Species.getTotalNum());
334  int icharge(Species.addAttribute("charge"));
335  for (int ig = 0; ig < ng; ig++)
336  {
337  std::vector<RealType> grid_temp, pp_temp;
338  std::string species(Species.speciesName[ig]);
339  std::string fname = species + ".psf";
340  std::ifstream fin(fname.c_str(), std::ios_base::in);
341  if (!fin)
342  {
343  ERRORMSG("Could not open file " << fname)
344  exit(-1);
345  }
346  // Read Number of potentials (local and non) for this atom
347  int npotentials;
348  fin >> npotentials;
349  int lmax = -1;
350  int numnonloc = 0;
351  RealType rmax(0.0);
352  app_log() << " ECPotential for " << species << std::endl;
353  std::unique_ptr<NonLocalECPComponent> mynnloc;
354  using CubicSplineFuncType = OneDimCubicSpline<RealType>;
355  for (int ij = 0; ij < npotentials; ij++)
356  {
357  int angmom, npoints;
358  fin >> angmom >> npoints;
360  inFunc.put(npoints, fin);
361  if (angmom < 0)
362  //local potential, input is rescale by -r/z
363  {
364  RealType zinv = -1.0 / Species(icharge, ig);
365  int ng = npoints - 1;
366  RealType rf = 5.0;
367  ng = static_cast<int>(rf * 100) + 1; //use 1e-2 resolution
368  auto agrid = std::make_unique<LinearGrid<RealType>>();
369  agrid->set(0, rf, ng);
370  std::vector<RealType> pp_temp(ng);
371  pp_temp[0] = 0.0;
372  for (int j = 1; j < ng; j++)
373  {
374  RealType r((*agrid)[j]);
375  pp_temp[j] = r * zinv * inFunc.splint(r);
376  }
377  pp_temp[ng - 1] = 1.0;
378  auto app = std::make_unique<RadialPotentialType>(std::move(agrid), pp_temp);
379  app->spline();
380  localPot[ig] = std::move(app);
381  app_log() << " LocalECP l=" << angmom << std::endl;
382  app_log() << " Linear grid=[0," << rf << "] npts=" << ng << std::endl;
383  hasLocalPot = true; //will create LocalECPotential
384  }
385  else
386  {
387  hasNonLocalPot = true; //will create NonLocalECPotential
388  if (!mynnloc)
389  mynnloc = std::make_unique<NonLocalECPComponent>();
390  RealType rf = inFunc.rmax();
391  auto agrid = std::make_unique<LinearGrid<RealType>>();
392  int ng = static_cast<int>(rf * 100) + 1;
393  agrid->set(0.0, rf, ng);
394  app_log() << " NonLocalECP l=" << angmom << " rmax = " << rf << std::endl;
395  app_log() << " Linear grid=[0," << rf << "] npts=" << ng << std::endl;
396  std::vector<RealType> pp_temp(ng);
397  //get the value
398  pp_temp[0] = inFunc(0);
399  for (int j = 1; j < ng; j++)
400  {
401  pp_temp[j] = inFunc.splint((*agrid)[j]);
402  }
403  auto app = new RadialPotentialType(std::move(agrid), pp_temp);
404  app->spline();
405  mynnloc->add(angmom, app);
406  lmax = std::max(lmax, angmom);
407  rmax = std::max(rmax, rf);
408  numnonloc++;
409  }
410  if (mynnloc)
411  {
412  mynnloc->setLmax(lmax);
413  mynnloc->setRmax(rmax);
414  app_log() << " Maximum cutoff of NonLocalECP " << rmax << std::endl;
415  }
416  }
417  fin.close();
418  if (mynnloc)
419  {
420  int numsgridpts = 0;
421  std::string fname = species + ".sgr";
422  std::ifstream fin(fname.c_str(), std::ios_base::in);
423  if (!fin)
424  {
425  app_error() << "Could not open file " << fname << std::endl;
426  exit(-1);
427  }
428  PosType xyz;
429  RealType weight;
430  while (fin >> xyz >> weight)
431  {
432  mynnloc->addknot(xyz, weight);
433  numsgridpts++;
434  }
435  //cout << "Spherical grid : " << numsgridpts << " points" << std::endl;
436  mynnloc->resize_warrays(numsgridpts, numnonloc, lmax);
437  nonLocalPot[ig] = std::move(mynnloc);
438  }
439  } //species
440 }
441 } // namespace qmcplusplus
#define ERRORMSG(msg)
Definition: OutputManager.h:86
std::ostream & app_warning()
Definition: OutputManager.h:69
Base class for any object which needs to know about a MPI communicator.
Definition: MPIObjectBase.h:26
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
void addOperator(std::unique_ptr< OperatorBase > &&h, const std::string &aname, bool physical=true)
add an operator
std::ostream & app_log()
Definition: OutputManager.h:65
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
std::ostream & app_error()
Definition: OutputManager.h:67
Collection of Local Energy Operators.
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
std::vector< std::unique_ptr< SOECPComponent > > soPot
std::unique_ptr< NonLocalECPComponent > pp_nonloc
int getTotalNum() const
return the number of species
Definition: SpeciesSet.h:55
Wrapping information on parallelism.
Definition: Communicate.h:68
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
LocalECPotential::RadialPotentialType RadialPotentialType
std::unique_ptr< SOECPComponent > pp_so
Communicate * myComm
pointer to Communicate
Definition: MPIObjectBase.h:62
Declaration of a builder class for an ECP component for an ionic type.
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
bool parseCasino(const std::string &fname, xmlNodePtr cur)
#define APP_ABORT(msg)
Widely used but deprecated fatal error macros from legacy code.
Definition: AppAbort.h:27
ECPotentialBuilder(QMCHamiltonian &h, ParticleSet &ions, ParticleSet &els, TrialWaveFunction &psi, Communicate *c)
constructor
std::unique_ptr< RadialPotentialType > pp_loc
std::vector< std::unique_ptr< RadialPotentialType > > localPot
void put(int npoints, std::istream &fin)
bool parse(const std::string &fname, xmlNodePtr cur)
std::vector< RealType > localZeff
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
void useSimpleTableFormat()
reimplement simple table format used by NonLocalPPotential
adaptor class to handle a temporary OneDimCubicSpline on a numerical grid.
std::vector< std::unique_ptr< NonLocalECPComponent > > nonLocalPot
std::unique_ptr< L2RadialPotential > pp_L2
Class to represent a many-body trial wave function.
const auto & getLattice() const
Definition: ParticleSet.h:251
std::vector< std::unique_ptr< L2RadialPotential > > L2Pot
Custom container for set of attributes for a set of species.
Definition: SpeciesSet.h:33
int findSpecies(const std::string &name) const
if the input species is not found, add a new species
Definition: SpeciesSet.h:114
void barrier_and_abort(const std::string &msg) const
int rank() const
return the rank of the communicator
Definition: MPIObjectBase.h:35
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
Definition of OneDimNumGridFunctor.
Declaration of QMCHamiltonian.