QMCPACK
RadialOrbitalSetBuilder.h
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: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
8 // Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
9 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
10 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
11 //
12 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
13 //////////////////////////////////////////////////////////////////////////////////////
14 
15 
16 #ifndef QMCPLUSPLUS_RADIAL_NUMERICALGRIDORBITALBUILDER_H
17 #define QMCPLUSPLUS_RADIAL_NUMERICALGRIDORBITALBUILDER_H
18 
19 #include "Configuration.h"
20 #include "hdf/HDFVersion.h"
24 #include "Numerics/Transform2GridFunctor.h"
26 #include "OptimizableFunctorBase.h"
28 #include "Message/MPIObjectBase.h"
29 #include "MultiQuinticSpline1D.h"
30 
31 
32 namespace qmcplusplus
33 {
34 /** abstract class to defer generation of spline functors
35  * @tparam T precision of the final result
36  */
37 template<typename T>
39 {
40  ///temporary grid in double precision
42  ///the multiple set
44  /** convert input 1D functor to the multi set
45  * @param agrid original grid
46  * @param multiset the object that should be populated
47  * @param ispline index of the this analytic function
48  * @param int order quintic (or cubic) only quintic is used
49  */
50  virtual void convert(grid_type& agrid, FnOut& multiset, int ispline, int order) = 0;
51  virtual ~TransformerBase() {}
52 };
53 
54 template<typename T, typename FnIn>
56 {
58  using FnOut = typename TransformerBase<T>::FnOut;
59 
60  std::unique_ptr<FnIn> m_ref; //candidate for unique_ptr
61  A2NTransformer(std::unique_ptr<FnIn> in) : m_ref(std::move(in)) {}
62 
63  void convert(grid_type& agrid, FnOut& multiset, int ispline, int order) override
64  {
66  spline_type radorb(agrid.makeClone());
67  Transform2GridFunctor<FnIn, spline_type> transform(*m_ref, radorb);
68  transform.generate(agrid.rmin(), agrid.rmax(), agrid.size());
69  multiset.add_spline(ispline, radorb);
70  }
71 };
72 
73 
74 /** Build a set of radial orbitals at the origin
75  *
76  * For a center,
77  * - only one grid is used
78  * - any number of radial orbitals
79  * - using MultiQuinticSpline1D
80  * - Gaussian and Slater mixing allowed
81  * - Slater's are assumed to fit in a 100 rmax grid
82  */
83 template<typename COT>
84 class RadialOrbitalSetBuilder : public MPIObjectBase
85 {
86 public:
87  //Now we count on COT::ValueType being real
88  //since COT::ValueType == ROT::ValueType && ROT==MultiQuiniticSpline1D
89  //And MultiQuiniticSpline1D does not distringuish between real_type of r
90  //And the value_type of 'Psi(r)' this is safe for now
91  //I think COT::gridtype needs to go to a template<typename RT, typename VT>
92  //For this all to become 'correct'.
93  using RealType = typename COT::RealType;
94  using RadialOrbitalType = typename COT::RadialOrbital_t;
95  using GridType = typename COT::GridType;
96 
97 
98  ///true, if the RadialOrbitalType is normalized
99  bool Normalized;
100  ///the atomic orbitals
102  ///input grid in case transform is needed
103  std::unique_ptr<GridType> input_grid;
104  ///the quantum number of this node
106 
107  ///constructor
109  COT& aos,
110  int radial_grid_size = 1001); //radial_grid_size is 1001 just magic?
111 
112  ///add a grid
113  bool addGrid(xmlNodePtr cur, const std::string& rad_type);
114  bool addGridH5(hdf_archive& hin);
115 
116  /** add a radial functor
117  * @param cur xml element
118  * @param nlms quantum number
119  */
120  bool addRadialOrbital(xmlNodePtr cur, const std::string& m_infunctype, const QuantumNumberType& nlms);
121  bool addRadialOrbitalH5(hdf_archive& hin, const std::string& radtype, const QuantumNumberType& nlms);
122 
123  /** This is when the radial orbitals are actually created */
124  void finalize();
125 
126 private:
127  //only check the cutoff
128  void addGaussian(xmlNodePtr cur);
130  void addSlater(xmlNodePtr cur);
131 
132  template<typename Fin, typename T>
133  T find_cutoff(Fin& in, T rmax);
134 
135  /// hdf file only for numerical basis h5 file generated by SQD
137 
138  /// Number of grid points
140 
141  ///maximum cutoff for an orbital, could come from XML always set to -1 by constructor
143 
144  ///safe common cutoff radius
146 
147  /** radial functors to be finalized
148  */
149  std::vector<std::unique_ptr<TransformerBase<RealType>>> radTemp;
150 
151  std::tuple<int, double, double> grid_param_in;
152 };
153 
154 template<typename COT>
156  : MPIObjectBase(comm), Normalized(true), m_orbitals(aos), radial_grid_size_(radial_grid_size), m_rcut(-1.0)
157 {}
158 
159 template<typename COT>
160 bool RadialOrbitalSetBuilder<COT>::addGrid(xmlNodePtr cur, const std::string& rad_type)
161 {
162  if (rad_type == "Numerical")
163  {
164  hin.push("grid");
165  addGridH5(hin);
166  hin.pop();
167  }
168  else
169  input_grid = OneDimGridFactory::createGrid(cur);
170 
171  //set zero to use std::max
172  m_rcut_safe = 0;
173 
174  return true;
175 }
176 
177 template<typename COT>
179 {
180  app_log() << " Grid is created by the input parameters in h5" << std::endl;
181 
182  std::string gridtype;
183  if (myComm->rank() == 0)
184  {
185  hin.read(gridtype, "grid_type");
186  }
187  myComm->bcast(gridtype);
188 
189  int npts = 0;
190  RealType ri = 0.0, rf = 10.0, rmax_safe = 10;
191  if (myComm->rank() == 0)
192  {
193  double tt = 0;
194  hin.read(tt, "grid_ri");
195  ri = tt;
196  hin.read(tt, "grid_rf");
197  rf = tt;
198  // Ye TODO: grid handling will all moved to XML.
199  //hin.read(tt, "rmax_safe");
200  //rmax_safe = tt;
201  hin.read(npts, "grid_npts");
202  }
203  myComm->bcast(ri);
204  myComm->bcast(rf);
205  myComm->bcast(rmax_safe);
206  myComm->bcast(npts);
207 
208  if (gridtype.empty())
209  myComm->barrier_and_abort("Grid type is not specified.");
210 
211  if (gridtype == "log")
212  {
213  app_log() << " Using log grid ri = " << ri << " rf = " << rf << " npts = " << npts << std::endl;
214  input_grid = std::make_unique<LogGrid<RealType>>();
215  }
216  else if (gridtype == "linear")
217  {
218  app_log() << " Using linear grid ri = " << ri << " rf = " << rf << " npts = " << npts << std::endl;
219  input_grid = std::make_unique<LinearGrid<RealType>>();
220  }
221 
222  input_grid->set(ri, rf, npts);
223 
224  //set zero to use std::max
225  m_rcut_safe = 0;
226 
227  return true;
228 }
229 
230 /** Add a new Slater Type Orbital with quantum numbers \f$(n,l,m,s)\f$
231  * \param cur the current xmlNode to be processed
232  * \param nlms a vector containing the quantum numbers \f$(n,l,m,s)\f$
233  * \return true is succeeds
234  *
235  */
236 template<typename COT>
238  const std::string& m_infunctype,
239  const QuantumNumberType& nlms)
240 {
241  std::string radtype(m_infunctype);
242  std::string dsname("0");
243  OhmmsAttributeSet aAttrib;
244  aAttrib.add(radtype, "type");
245  aAttrib.add(m_rcut, "rmax");
246  aAttrib.add(dsname, "ds");
247  aAttrib.put(cur);
248  m_nlms = nlms;
249  if (radtype == "Gaussian" || radtype == "GTO")
250  addGaussian(cur);
251  else if (radtype == "Slater" || radtype == "STO")
252  addSlater(cur);
253  else
254  myComm->barrier_and_abort("Purely numerical atomic orbitals are not supported any longer.");
255  return true;
256 }
257 
258 template<typename COT>
260  const std::string& radtype_atomicBasisSet,
261  const QuantumNumberType& nlms)
262 {
263  std::string dsname("0");
264  std::string radtype(radtype_atomicBasisSet);
265  if (myComm->rank() == 0)
266  hin.read(radtype, "type");
267  myComm->bcast(radtype);
268 
269  m_nlms = nlms;
270  if (radtype == "Gaussian" || radtype == "GTO")
271  addGaussianH5(hin);
272  else if (radtype == "Slater" || radtype == "STO")
273  // addSlaterH5(hin);
274  myComm->barrier_and_abort(
275  " RadType: Slater. Any type other than Gaussian not implemented in H5 format. Please contact developers.");
276  else
277  myComm->barrier_and_abort(
278  " RadType: Numerical. Any type other than Gaussian not implemented in H5 format. Please contact developers.");
279  return true;
280 }
281 
282 
283 template<typename COT>
285 {
286  int L = m_nlms[1];
287  using gto_type = GaussianCombo<OHMMS_PRECISION_FULL>;
288  auto gset = std::make_unique<gto_type>(L, Normalized);
289  gset->putBasisGroup(cur);
290  //Warning::Magic Number for max rmax of gaussians
291  RealType r0 = find_cutoff(*gset, 100.);
292  m_rcut_safe = std::max(m_rcut_safe, r0);
293  radTemp.push_back(std::make_unique<A2NTransformer<RealType, gto_type>>(std::move(gset)));
294  m_orbitals.RnlID.push_back(m_nlms);
295 }
296 
297 
298 template<typename COT>
300 {
301  int L = m_nlms[1];
302  using gto_type = GaussianCombo<OHMMS_PRECISION_FULL>;
303  auto gset = std::make_unique<gto_type>(L, Normalized);
304  gset->putBasisGroupH5(hin, *myComm);
305  //at least gamess derived xml seems to provide the max its grid goes to
306  //So in priniciple this 100 should be coming in from input
307  //m_rcut seems like it once served this purpose but is somehow
308  //a class global variable even though it should apply here and
309  //similar locations on a function by function basis.
310  RealType r0 = find_cutoff(*gset, 100.);
311  m_rcut_safe = 6 * std::max(m_rcut_safe, r0);
312  radTemp.push_back(std::make_unique<A2NTransformer<RealType, gto_type>>(std::move(gset)));
313  m_orbitals.RnlID.push_back(m_nlms);
314 }
315 
316 
317 /* Finalize this set using the common grid
318  *
319  * This function puts the All RadialOrbitals
320  * on a logarithmic grid with r_max of matching the largest r_max found
321  * filling radTemp. The derivatives at the endpoint
322  * are assumed to be all zero. Note: for the radial orbital we use
323  * \f[ f(r) = \frac{R(r)}{r^l}, \f] where \f$ R(r) \f$ is the usual
324  * radial orbital and \f$ l \f$ is the angular momentum.
325  *
326  */
327 template<typename COT>
329 {
330  // This is a temporary grid used in conversion, at the full precision of the calculation
331  // to reduce error. It doesn't need to be on the heap but this is the result of a
332  // series of design decisions requiring a base class pointer here.
333  std::unique_ptr<OneDimGridBase<OHMMS_PRECISION_FULL>> grid_prec;
334  grid_prec = std::make_unique<LogGrid<OHMMS_PRECISION_FULL>>();
335  // FIXME: should not hard-coded, probably should be input grid
336  grid_prec->set(1.e-6, m_rcut_safe, 1001);
337 
338  auto& multiset = m_orbitals.MultiRnl;
339  const int norbs = radTemp.size();
340  multiset.initialize(*grid_prec, norbs);
341 
342  for (int ib = 0; ib < norbs; ++ib)
343  radTemp[ib]->convert(*grid_prec, multiset, ib, 5);
344 
345  multiset.finalize();
346 
347  app_log() << " Setting cutoff radius " << m_rcut_safe << std::endl << std::endl;
348  m_orbitals.setRmax(static_cast<RealType>(m_rcut_safe));
349 }
350 
351 template<typename COT>
353 {
354  using sto_type = SlaterCombo<OHMMS_PRECISION_FULL>;
355  auto gset = std::make_unique<sto_type>(m_nlms[1], Normalized);
356 
357  gset->putBasisGroup(cur);
358 
359  //need a find_cutoff for STO's, but this was previously in finalize and wiping out GTO's m_rcut_safe
360  m_rcut_safe = std::max(m_rcut_safe, static_cast<RealType>(100));
361  radTemp.push_back(std::make_unique<A2NTransformer<RealType, sto_type>>(std::move(gset)));
362  m_orbitals.RnlID.push_back(m_nlms);
363 }
364 
365 
366 /** compute the safe cutoff radius of a radial functor
367  */
368 /** temporary function to compute the cutoff without constructing NGFunctor */
369 template<typename COT>
370 template<typename Fin, typename T>
372 {
374  //WARNING Magic number, should come from input or be set somewhere more cnetral.
375  const OHMMS_PRECISION_FULL eps = 1e-6;
376  bool too_small = true;
378  int i = radial_grid_size_ - 1;
379  T r = rmax;
380  while (too_small && i > 0)
381  {
382  r = agrid(i--);
383  T x = in.f(r);
384  too_small = (std::abs(x) < eps);
385  }
386  return static_cast<OHMMS_PRECISION_FULL>(r);
387 }
388 
389 } // namespace qmcplusplus
390 #endif
typename COT::RadialOrbital_t RadialOrbitalType
multivalue implementation for OneDimQuintic Real valued only calling any eval method with r >= r_max ...
T rmin() const
return the first grid point
A2NTransformer(std::unique_ptr< FnIn > in)
void set(T ri, T rf, int n)
Base class for any object which needs to know about a MPI communicator.
Definition: MPIObjectBase.h:26
QuantumNumberType m_nlms
the quantum number of this node
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
void convert(const PL &lat, const PV &pin, PV &pout)
static std::unique_ptr< GridType > createGrid(xmlNodePtr cur)
return a GridType*
std::ostream & app_log()
Definition: OutputManager.h:65
bool put(xmlNodePtr cur)
assign attributes to the set
Definition: AttributeSet.h:55
Build a set of radial orbitals at the origin.
T find_cutoff(Fin &in, T rmax)
compute the safe cutoff radius of a radial functor
class to handle hdf file
Definition: hdf_archive.h:51
declaration of MPIObjectBase
virtual void convert(grid_type &agrid, FnOut &multiset, int ispline, int order)=0
convert input 1D functor to the multi set
Define a base class for one-dimensional functions with optimizable variables.
std::vector< std::unique_ptr< TransformerBase< RealType > > > radTemp
radial functors to be finalized
bool addGrid(xmlNodePtr cur, const std::string &rad_type)
add a grid
RealType m_rcut
maximum cutoff for an orbital, could come from XML always set to -1 by constructor ...
An abstract base class to implement a One-Dimensional grid.
Wrapping information on parallelism.
Definition: Communicate.h:68
abstract class to defer generation of spline functors
void finalize()
This is when the radial orbitals are actually created.
class to handle a set of attributes of an xmlNode
Definition: AttributeSet.h:24
bool addRadialOrbital(xmlNodePtr cur, const std::string &m_infunctype, const QuantumNumberType &nlms)
add a radial functor
bool putBasisGroup(xmlNodePtr cur)
bool putBasisGroupH5(hdf_archive &hin, Communicate &myComm)
RealType m_rcut_safe
safe common cutoff radius
hdf_archive hin
hdf file only for numerical basis h5 file generated by SQD
std::tuple< int, double, double > grid_param_in
QMCTraits::RealType RealType
GridType
The different types of grids that we currently allow.
Definition: Grid.h:29
void add_spline(int ispline, OneDimQuinticSpline< T1 > &in)
int size() const
returns the size of the grid
bool putBasisGroup(xmlNodePtr cur)
T rmax() const
return the last grid point
virtual std::unique_ptr< OneDimGridBase< T, CT > > makeClone() const =0
RadialOrbitalSetBuilder(Communicate *comm, COT &aos, int radial_grid_size=1001)
constructor
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 convert(grid_type &agrid, FnOut &multiset, int ispline, int order) override
convert input 1D functor to the multi 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 Normalized
true, if the RadialOrbitalType is normalized
bool addRadialOrbitalH5(hdf_archive &hin, const std::string &radtype, const QuantumNumberType &nlms)
std::unique_ptr< GridType > input_grid
input grid in case transform is needed
int radial_grid_size_
Number of grid points.
Assume that coeffs.D1 and the LogLightGrid r_values.size() are equal Therefore r must be < r_max...