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: 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 //
12 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
13 //////////////////////////////////////////////////////////////////////////////////////
14 
15 
16 #include "ECPComponentBuilder.h"
17 #include "Numerics/GaussianTimesRN.h"
18 #include "Numerics/Quadrature.h"
19 #include "QMCHamiltonians/NonLocalECPComponent.h"
20 #include "Numerics/Transform2GridFunctor.h"
21 #include "Utilities/IteratorUtility.h"
22 #include "Utilities/SimpleParser.h"
23 #include "Message/CommOperators.h"
24 #include <cmath>
25 #include "Utilities/qmc_common.h"
26 
27 
28 namespace qmcplusplus
29 {
ECPComponentBuilder(const std::string & aname,Communicate * c,int nrule)30 ECPComponentBuilder::ECPComponentBuilder(const std::string& aname, Communicate* c, int nrule)
31     : MPIObjectBase(c),
32       NumNonLocal(0),
33       Lmax(0),
34       Nrule(nrule),
35       Srule(8),
36       AtomicNumber(0),
37       Zeff(0),
38       RcutMax(-1),
39       Species(aname),
40       grid_global(0)
41 {
42   angMon["s"] = 0;
43   angMon["p"] = 1;
44   angMon["d"] = 2;
45   angMon["f"] = 3;
46   angMon["g"] = 4;
47   angMon["h"] = 5;
48   angMon["i"] = 6;
49   angMon["j"] = 7;
50   angMon["k"] = 8;
51   angMon["0"] = 0;
52   angMon["1"] = 1;
53   angMon["2"] = 2;
54   angMon["3"] = 3;
55   angMon["4"] = 4;
56   angMon["5"] = 5;
57   angMon["6"] = 6;
58   angMon["7"] = 7;
59   angMon["8"] = 8;
60 }
61 
parse(const std::string & fname,xmlNodePtr cur)62 bool ECPComponentBuilder::parse(const std::string& fname, xmlNodePtr cur)
63 {
64   const XMLAttrString cutoff_str(cur, "cutoff");
65   if (!cutoff_str.empty())
66     RcutMax = std::stod(cutoff_str);
67 
68   return read_pp_file(fname);
69 }
70 
get_file_length(std::ifstream * f) const71 int ReadFileBuffer::get_file_length(std::ifstream* f) const
72 {
73   f->seekg(0, std::ios::end);
74   int len = f->tellg();
75   f->seekg(0, std::ios::beg);
76   return len;
77 }
78 
reset()79 void ReadFileBuffer::reset()
80 {
81   if (is_open)
82   {
83     if (myComm == NULL || myComm->rank() == 0)
84     {
85       delete fin;
86       fin = NULL;
87     }
88     delete[] cbuffer;
89     cbuffer = NULL;
90     is_open = false;
91     length  = 0;
92   }
93 }
94 
open_file(const std::string & fname)95 bool ReadFileBuffer::open_file(const std::string& fname)
96 {
97   reset();
98 
99   if (myComm == NULL || myComm->rank() == 0)
100   {
101     fin = new std::ifstream(fname.c_str());
102     if (fin->is_open())
103       is_open = true;
104   }
105   if (myComm)
106     myComm->bcast(is_open);
107   return is_open;
108 }
109 
read_contents()110 bool ReadFileBuffer::read_contents()
111 {
112   if (!is_open)
113     return false;
114 
115   if (myComm == NULL || myComm->rank() == 0)
116   {
117     length = get_file_length(fin);
118   }
119   if (myComm)
120     myComm->bcast(length);
121 
122   cbuffer         = new char[length + 1];
123   cbuffer[length] = '\0';
124 
125   if (myComm == NULL || myComm->rank() == 0)
126     fin->read(cbuffer, length);
127 
128   if (myComm != NULL)
129     myComm->bcast(cbuffer, length);
130 
131   return true;
132 }
133 
134 
read_pp_file(const std::string & fname)135 bool ECPComponentBuilder::read_pp_file(const std::string& fname)
136 {
137   ReadFileBuffer buf(myComm);
138   bool okay = buf.open_file(fname);
139   if (!okay)
140     myComm->barrier_and_abort("ECPComponentBuilder::read_pp_file  Missing PP file " + fname + "\n");
141 
142   okay = buf.read_contents();
143   if (!okay)
144     myComm->barrier_and_abort("ECPComponentBuilder::read_pp_file Unable to read PP file " + fname + "\n");
145 
146   xmlDocPtr m_doc = xmlReadMemory(buf.contents(), buf.length, NULL, NULL, 0);
147 
148   if (m_doc == NULL)
149   {
150     xmlFreeDoc(m_doc);
151     myComm->barrier_and_abort("ECPComponentBuilder::read_pp_file xml file " + fname + " is invalid");
152   }
153   // Check the document is of the right kind
154   xmlNodePtr cur = xmlDocGetRootElement(m_doc);
155   if (cur == NULL)
156   {
157     xmlFreeDoc(m_doc);
158     myComm->barrier_and_abort("Empty document");
159   }
160   bool success = put(cur);
161   xmlFreeDoc(m_doc);
162   return success;
163 }
164 
put(xmlNodePtr cur)165 bool ECPComponentBuilder::put(xmlNodePtr cur)
166 {
167   //  int nk=0;
168   //vector<RealType> kpts;
169   std::vector<xmlNodePtr> semiPtr;
170   cur = cur->children;
171   while (cur != NULL)
172   {
173     std::string cname((const char*)cur->name);
174     if (cname == "header")
175     {
176       Zeff         = std::stoi(XMLAttrString{cur, "zval"});
177       AtomicNumber = std::stoi(XMLAttrString{cur, "atomic-number"});
178     }
179     else if (cname == "grid")
180     {
181       //capture the global grid
182       grid_global = createGrid(cur);
183     }
184     else if (cname == "L2")
185     {
186       buildL2(cur);
187     }
188     else if (cname == "semilocal")
189     {
190       semiPtr.push_back(cur); //save the pointer
191     }
192     else if (cname == "local")
193     {
194       buildLocal(cur);
195     }
196     cur = cur->next;
197   }
198   if (semiPtr.size())
199   {
200     if (!pp_nonloc)
201       pp_nonloc = std::make_unique<NonLocalECPComponent>();
202     if (pp_so == 0)
203       pp_so = std::make_unique<SOECPComponent>();
204     if (pp_loc)
205     {
206       for (int i = 0; i < semiPtr.size(); i++)
207         addSemiLocal(semiPtr[i]);
208     }
209     else
210       buildSemiLocalAndLocal(semiPtr);
211   }
212   if (pp_nonloc)
213   {
214     SetQuadratureRule(Nrule);
215     app_log() << "    Non-local pseudopotential parameters" << std::endl;
216     pp_nonloc->print(app_log());
217     app_log() << "    Maximum cutoff radius " << pp_nonloc->Rmax << std::endl;
218   }
219   return true;
220 }
221 
printECPTable()222 void ECPComponentBuilder::printECPTable()
223 {
224   if (!qmc_common.io_node || qmc_common.mpi_groups > 1)
225     return;
226 
227   char fname[12];
228   sprintf(fname, "%s.pp.dat", Species.c_str());
229   std::ofstream fout(fname);
230   fout.setf(std::ios::scientific, std::ios::floatfield);
231   fout.precision(12);
232   int nl      = pp_nonloc ? pp_nonloc->nlpp_m.size() : 0;
233   RealType d  = 1.7e-2;
234   RealType rt = 0.13 * d;
235   if (nl)
236   {
237     fout << "#  Lmax = " << Lmax + 1 << " nonlocal L channels" << nl << std::endl;
238     fout << "#  Units = bohr hartree " << std::endl;
239     fout << "#  r  -r*V/zeff   Vnl ... " << std::endl;
240     while (rt < 5)
241     {
242       fout << rt << std::setw(25) << pp_loc->splint(rt);
243       for (int l = 0; l < nl; l++)
244         fout << std::setw(25) << pp_nonloc->nlpp_m[l]->splint(rt);
245       fout << std::endl;
246       rt += d;
247     }
248   }
249   else
250   {
251     fout << "#  Units = bohr hartree " << std::endl;
252     fout << "#  r  -r*V/zeff " << std::endl;
253     while (rt < 5)
254     {
255       fout << rt << std::setw(25) << pp_loc->splint(rt) << std::endl;
256       ;
257       rt += d;
258     }
259   }
260 }
261 
SetQuadratureRule(int rule)262 void ECPComponentBuilder::SetQuadratureRule(int rule)
263 {
264   app_log() << "  Quadrature Nrule: " << rule << std::endl;
265   Quadrature3D<RealType> myRule(rule);
266   pp_nonloc->sgridxyz_m    = myRule.xyz_m;
267   pp_nonloc->sgridweight_m = myRule.weight_m;
268   // Allocate storage for wave function ratios
269   pp_nonloc->resize_warrays(myRule.nk, NumNonLocal, Lmax);
270   if (pp_so)
271   { //added here bc must have nonlocal terms to have SO contributions
272     pp_so->sgridxyz_m    = myRule.xyz_m;
273     pp_so->sgridweight_m = myRule.weight_m;
274     pp_so->resize_warrays(myRule.nk, NumSO, Srule);
275   }
276 }
277 
278 } // namespace qmcplusplus
279