1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2009-2017 The Regents of the University of California
4 //
5 // This file is part of Qbox
6 //
7 // Qbox is distributed under the terms of the GNU General Public License
8 // as published by the Free Software Foundation, either version 2 of
9 // the License, or (at your option) any later version.
10 // See the file COPYING in the root directory of this distribution
11 // or <http://www.gnu.org/licenses/>.
12 //
13 ////////////////////////////////////////////////////////////////////////////////
14 //
15 // upf2qso.cpp: transform a UPF pseudopotential to QSO format
16 // the QSO format is defined at http://www.quantum-simulation.org
17 // This program accepts both the original UPF format and the "2.0.1" format
18 //
19 ////////////////////////////////////////////////////////////////////////////////
20 //
21 // use: upf2qso rcut(a.u.) < pot.UPF > pot.xml
22 // The potentials in pot.xml are given on a radial linear grid up to rcut,
23 // with grid spacing of 0.01 (a.u.)
24 //
25 #include <iostream>
26 #include <iomanip>
27 #include <fstream>
28 #include <sstream>
29 #include <string>
30 #include <algorithm>
31 #include <vector>
32 #include <cmath>
33 #include <cassert>
34 #include <cstdlib>
35 #include <stdexcept>
36 #include "spline.h"
37 #include "isodate.h"
38 #include "PeriodicTable.h"
39 using namespace std;
40
41 ////////////////////////////////////////////////////////////////////////////////
find_start_element(string name)42 string find_start_element(string name)
43 {
44 // return the contents of the tag at start of element "name"
45 string buf, token;
46 string search_str = "<" + name;
47 do
48 {
49 cin >> token;
50 }
51 while ( !cin.eof() && token.find(search_str) == string::npos );
52 if ( cin.eof() )
53 {
54 cerr << " EOF reached before start element " << name << endl;
55 throw invalid_argument(name);
56 }
57
58 buf = token;
59 if ( buf[buf.length()-1] == '>' )
60 return buf;
61
62 // read until ">" is found
63 bool found = false;
64 char ch;
65 do
66 {
67 cin.get(ch);
68 found = ch == '>';
69 buf += ch;
70 }
71 while ( !cin.eof() && !found );
72 if ( cin.eof() )
73 {
74 cerr << " EOF reached before > " << name << endl;
75 throw invalid_argument(name);
76 }
77 return buf;
78 }
79
80 ////////////////////////////////////////////////////////////////////////////////
find_end_element(string name)81 void find_end_element(string name)
82 {
83 string buf, token;
84 string search_str = "</" + name + ">";
85 do
86 {
87 cin >> token;
88 if ( token.find(search_str) != string::npos ) return;
89 }
90 while ( !cin.eof() );
91 cerr << " EOF reached before end element " << name << endl;
92 throw invalid_argument(name);
93 }
94
95 ////////////////////////////////////////////////////////////////////////////////
seek_str(string tag)96 void seek_str(string tag)
97 {
98 // Read tokens from stdin until tag is found.
99 // Throw an exception if tag not found before eof()
100 bool done = false;
101 string token;
102 int count = 0;
103
104 do
105 {
106 cin >> token;
107 if ( token.find(tag) != string::npos ) return;
108 }
109 while ( !cin.eof() );
110
111 cerr << " EOF reached before " << tag << endl;
112 throw invalid_argument(tag);
113 }
114
115 ////////////////////////////////////////////////////////////////////////////////
get_attr(string buf,string attr)116 string get_attr(string buf, string attr)
117 {
118 //cerr << " get_attr: searching for: " << attr << endl;
119 //cerr << " in buffer: " << endl;
120 //cerr << buf << endl;
121 bool done = false;
122 string s, search_string = attr + "=";
123
124 // find attribute name in buf
125 string::size_type p = buf.find(search_string);
126 if ( p != string::npos )
127 {
128 // process attribute
129 string::size_type b = buf.find_first_of("\"",p);
130 string::size_type e = buf.find_first_of("\"",b+1);
131 if ( b == string::npos || e == string::npos )
132 {
133 cerr << " get_attr: attribute not found: " << attr << endl;
134 throw invalid_argument(attr);
135 }
136 s = buf.substr(b+1,e-b-1);
137 // remove white space
138 s.erase(remove_if(s.begin(),s.end(),::isspace),s.end());
139 return s;
140 }
141 else
142 {
143 cerr << " get_attr: attribute not found: " << attr << endl;
144 throw invalid_argument(attr);
145 }
146 return s;
147 }
148
149 ////////////////////////////////////////////////////////////////////////////////
skipln(void)150 void skipln(void)
151 {
152 char ch;
153 bool found = false;
154 while ( !cin.eof() && !found )
155 {
156 cin.get(ch);
157 found = ch == '\n';
158 }
159 }
160
161 ////////////////////////////////////////////////////////////////////////////////
162 const string release="1.10";
163
main(int argc,char ** argv)164 int main(int argc, char** argv)
165 {
166 cerr << " upf2qso " << release << endl;
167 if ( argc != 2 )
168 {
169 cerr << " usage: upf2qso rcut < file.upf > file.xml" << endl;
170 return 1;
171 }
172 assert(argc==2);
173 const double rcut = atof(argv[1]);
174
175 PeriodicTable pt;
176 string buf,s;
177 istringstream is;
178
179 // determine UPF version
180 int upf_version = 0;
181
182 // The first line of the UPF potential file contains either of the following:
183 // <PP_INFO> (for UPF version 1)
184 // <UPF version="2.0.1"> (for UPF version 2)
185 string::size_type p;
186 getline(cin,buf);
187 p = buf.find("<PP_INFO>");
188 if ( p != string::npos )
189 upf_version = 1;
190 else
191 {
192 p = buf.find("<UPF version=\"2.0.1\">");
193 if ( p != string::npos )
194 upf_version = 2;
195 }
196 if ( upf_version == 0 )
197 {
198 cerr << " Format of UPF file not recognized " << endl;
199 cerr << " First line of file: " << buf << endl;
200 return 1;
201 }
202
203 cerr << " UPF version: " << upf_version << endl;
204
205 if ( upf_version == 1 )
206 {
207 // process UPF version 1 potential
208 string upf_pp_info;
209 bool done = false;
210 while (!done)
211 {
212 getline(cin,buf);
213 is.clear();
214 is.str(buf);
215 is >> s;
216 done = ( s == "</PP_INFO>" );
217 if ( !done )
218 {
219 upf_pp_info += buf + '\n';
220 }
221 }
222
223 // remove all '<' and '>' characters from the PP_INFO field
224 // for XML compatibility
225 p = upf_pp_info.find_first_of("<>");
226 while ( p != string::npos )
227 {
228 upf_pp_info[p] = ' ';
229 p = upf_pp_info.find_first_of("<>");
230 }
231
232 seek_str("<PP_HEADER>");
233 skipln();
234
235 // version number (ignore)
236 getline(cin,buf);
237
238 // element symbol
239 string upf_symbol;
240 getline(cin,buf);
241 is.clear();
242 is.str(buf);
243 is >> upf_symbol;
244
245 // get atomic number and mass
246 const int atomic_number = pt.z(upf_symbol);
247 const double mass = pt.mass(upf_symbol);
248
249 // NC flag
250 string upf_ncflag;
251 getline(cin,buf);
252 is.clear();
253 is.str(buf);
254 is >> upf_ncflag;
255 if ( upf_ncflag != "NC" )
256 {
257 cerr << " not a Norm-conserving potential" << endl;
258 cerr << " NC flag: " << upf_ncflag << endl;
259 return 1;
260 }
261
262 // NLCC flag
263 string upf_nlcc_flag;
264 getline(cin,buf);
265 is.clear();
266 is.str(buf);
267 is >> upf_nlcc_flag;
268 if ( upf_nlcc_flag == "T" )
269 {
270 cerr << " Potential includes a non-linear core correction" << endl;
271 }
272
273 // XC functional (add in description)
274 string upf_xcf[4];
275 getline(cin,buf);
276 is.clear();
277 is.str(buf);
278 is >> upf_xcf[0] >> upf_xcf[1] >> upf_xcf[2] >> upf_xcf[3];
279
280 // add XC functional information to description
281 upf_pp_info += upf_xcf[0] + ' ' + upf_xcf[1] + ' ' +
282 upf_xcf[2] + ' ' + upf_xcf[3] + '\n';
283
284 // Z valence
285 double upf_zval;
286 getline(cin,buf);
287 is.clear();
288 is.str(buf);
289 is >> upf_zval;
290
291 // Total energy (ignore)
292 getline(cin,buf);
293
294 // suggested cutoff (ignore)
295 getline(cin,buf);
296
297 // max angular momentum
298 int upf_lmax;
299 getline(cin,buf);
300 is.clear();
301 is.str(buf);
302 is >> upf_lmax;
303
304 // number of points in mesh
305 int upf_mesh_size;
306 getline(cin,buf);
307 is.clear();
308 is.str(buf);
309 is >> upf_mesh_size;
310
311 // number of wavefunctions, number of projectors
312 int upf_nwf, upf_nproj;
313 getline(cin,buf);
314 is.clear();
315 is.str(buf);
316 is >> upf_nwf >> upf_nproj;
317
318 // Wavefunctions
319 vector<string> upf_shell(upf_nwf);
320 vector<int> upf_l(upf_nwf);
321 vector<double> upf_occ(upf_nwf);
322 // skip header
323 getline(cin,buf);
324 for ( int ip = 0; ip < upf_nwf; ip++ )
325 {
326 getline(cin,buf);
327 is.clear();
328 is.str(buf);
329 is >> upf_shell[ip] >> upf_l[ip] >> upf_occ[ip];
330 }
331 seek_str("</PP_HEADER>");
332
333 // read mesh
334 seek_str("<PP_MESH>");
335 seek_str("<PP_R>");
336 skipln();
337 vector<double> upf_r(upf_mesh_size);
338 for ( int i = 0; i < upf_mesh_size; i++ )
339 cin >> upf_r[i];
340 seek_str("</PP_R>");
341 seek_str("<PP_RAB>");
342 skipln();
343 vector<double> upf_rab(upf_mesh_size);
344 for ( int i = 0; i < upf_mesh_size; i++ )
345 cin >> upf_rab[i];
346 seek_str("</PP_RAB>");
347 seek_str("</PP_MESH>");
348
349 vector<double> upf_nlcc;
350 if ( upf_nlcc_flag == "T" )
351 {
352 upf_nlcc.resize(upf_mesh_size);
353 seek_str("<PP_NLCC>");
354 skipln();
355 for ( int i = 0; i < upf_mesh_size; i++ )
356 cin >> upf_nlcc[i];
357 seek_str("</PP_NLCC>");
358 }
359
360 seek_str("<PP_LOCAL>");
361 skipln();
362 vector<double> upf_vloc(upf_mesh_size);
363 for ( int i = 0; i < upf_mesh_size; i++ )
364 cin >> upf_vloc[i];
365 seek_str("</PP_LOCAL>");
366
367 seek_str("<PP_NONLOCAL>");
368 skipln();
369 vector<vector<double> > upf_vnl;
370 upf_vnl.resize(upf_nproj);
371 vector<int> upf_proj_l(upf_nproj);
372 for ( int j = 0; j < upf_nproj; j++ )
373 {
374 seek_str("<PP_BETA>");
375 skipln();
376 int ip, l, np;
377 cin >> ip >> l;
378 skipln();
379 assert(ip-1 < upf_nproj);
380 assert(l <= upf_lmax);
381 upf_proj_l[ip-1] = l;
382 cin >> np;
383 upf_vnl[j].resize(upf_mesh_size);
384 for ( int i = 0; i < np; i++ )
385 cin >> upf_vnl[j][i];
386 seek_str("</PP_BETA>");
387 skipln();
388 }
389 seek_str("<PP_DIJ>");
390 skipln();
391 int upf_ndij;
392 cin >> upf_ndij;
393 skipln();
394 if ( upf_ndij != upf_nproj )
395 {
396 cerr << " Number of non-zero Dij differs from number of projectors"
397 << endl;
398 return 1;
399 }
400
401 vector<double> upf_d(upf_ndij);
402 for ( int i = 0; i < upf_ndij; i++ )
403 {
404 int m,n;
405 cin >> m >> n >> upf_d[i];
406 if ( m != n )
407 {
408 cerr << " Non-local Dij has off-diagonal elements" << endl;
409 cerr << " m=" << m << " n=" << n << endl;
410 return 1;
411 }
412 }
413 seek_str("</PP_DIJ>");
414
415 seek_str("</PP_NONLOCAL>");
416
417 // make table iproj[l] mapping l to iproj
418 // vnl(l) is in vnl[iproj[l]] if iproj[l] > -1
419 // vlocal if iproj[llocal] = -1
420 vector<int> iproj(upf_lmax+2);
421 for ( int l = 0; l <= upf_lmax+1; l++ )
422 iproj[l] = -1;
423 for ( int j = 0; j < upf_nproj; j++ )
424 iproj[upf_proj_l[j]] = j;
425
426 // determine angular momentum of local potential in UPF file
427 int upf_llocal;
428 // reverse loop to get correct upf_llocal when upf_nproj < upf_lmax
429 for ( int l = upf_lmax+1; l >= 0; l-- )
430 if ( iproj[l] == -1 )
431 upf_llocal = l;
432 // increase lmax if there are more projectors than wavefunctions
433 int qso_lmax = upf_lmax;
434 if (upf_lmax < upf_llocal)
435 {
436 qso_lmax = upf_lmax+1;
437 }
438
439 seek_str("<PP_PSWFC>");
440 skipln();
441 vector<vector<double> > upf_wf;
442 vector<int> upf_wf_l(upf_nwf);
443 vector<double> upf_wf_occ(upf_nwf);
444 upf_wf.resize(upf_nwf);
445 for ( int j = 0; j < upf_nwf; j++ )
446 {
447 upf_wf[j].resize(upf_mesh_size);
448 string label;
449 cin >> label >> upf_wf_l[j] >> upf_wf_occ[j];
450 skipln();
451 for ( int i = 0; i < upf_mesh_size; i++ )
452 cin >> upf_wf[j][i];
453 }
454 seek_str("</PP_PSWFC>");
455
456 // output original data in file upf.dat
457 ofstream upf("upf.dat");
458 upf << "# vloc" << endl;
459 for ( int i = 0; i < upf_vloc.size(); i++ )
460 upf << upf_r[i] << " " << upf_vloc[i] << endl;
461 upf << endl << endl;
462 for ( int j = 0; j < upf_nproj; j++ )
463 {
464 upf << "# proj j=" << j << endl;
465 for ( int i = 0; i < upf_vnl[j].size(); i++ )
466 upf << upf_r[i] << " " << upf_vnl[j][i] << endl;
467 upf << endl << endl;
468 }
469 for ( int j = 0; j < upf_nwf; j++ )
470 {
471 upf << "# wf j=" << j << endl;
472 for ( int i = 0; i < upf_wf[j].size(); i++ )
473 upf << upf_r[i] << " " << upf_wf[j][i] << endl;
474 upf << endl << endl;
475 }
476 upf.close();
477
478
479 // print summary
480 cerr << "PP_INFO:" << endl << upf_pp_info << endl;
481 cerr << "Element: " << upf_symbol << endl;
482 cerr << "NC: " << upf_ncflag << endl;
483 cerr << "NLCC: " << upf_nlcc_flag << endl;
484 cerr << "XC: " << upf_xcf[0] << " " << upf_xcf[1] << " "
485 << upf_xcf[2] << " " << upf_xcf[3] << endl;
486 cerr << "Zv: " << upf_zval << endl;
487 cerr << "lmax: " << qso_lmax << endl;
488 cerr << "llocal: " << upf_llocal << endl;
489 cerr << "nwf: " << upf_nwf << endl;
490 cerr << "mesh_size: " << upf_mesh_size << endl;
491
492 // compute delta_vnl[l][i] on the upf log mesh
493
494 // divide the projector function by the wavefunction, except if
495 // the wavefunction amplitude is smaller than tol, outside of rcut_divide.
496 const double tol = 1.e-5;
497 const double rcut_divide = 1.0;
498 vector<vector<double> > delta_vnl;
499 delta_vnl.resize(upf_nproj);
500 for ( int j = 0; j < upf_nproj; j++ )
501 {
502 delta_vnl[j].resize(upf_wf[j].size());
503 for ( int i = 0; i < delta_vnl[j].size(); i++ )
504 {
505 double num = upf_vnl[j][i];
506 double den = upf_wf[upf_proj_l[j]][i];
507
508 delta_vnl[j][i] = 0.0;
509 if ( upf_r[i] < rcut_divide )
510 {
511 // near the origin
512 if ( i == 0 && fabs(den) < tol )
513 {
514 // i = 0 for linear mesh, r = 0.0: use nearest value
515 delta_vnl[j][i] = upf_vnl[j][1] / upf_wf[upf_proj_l[j]][1];
516 }
517 else
518 {
519 // other points near the origin
520 delta_vnl[j][i] = num / den;
521 }
522 }
523 else
524 {
525 // wavefunction gets small at large r.
526 // Assume that delta_vnl is zero when that happens
527 if ( fabs(den) > tol )
528 delta_vnl[j][i] = num / den;
529 }
530 }
531 }
532
533 vector<vector<double> > vps;
534 vps.resize(upf_nproj+1);
535 for ( int j = 0; j < upf_nproj; j++ )
536 {
537 vps[j].resize(upf_mesh_size);
538 for ( int i = 0; i < delta_vnl[j].size(); i++ )
539 vps[j][i] = upf_vloc[i] + delta_vnl[j][i];
540 }
541
542 // interpolate functions on linear mesh
543 const double mesh_spacing = 0.01;
544 int nplin = (int) (rcut / mesh_spacing);
545 vector<double> f(upf_mesh_size), fspl(upf_mesh_size);
546
547 vector<double> nlcc_lin(nplin);
548 // interpolate NLCC
549 if ( upf_nlcc_flag == "T" )
550 {
551 assert(upf_mesh_size==upf_nlcc.size());
552 for ( int i = 0; i < upf_nlcc.size(); i++ )
553 f[i] = upf_nlcc[i];
554 int n = upf_nlcc.size();
555 int bcnat_left = 0;
556 double yp_left = 0.0;
557 int bcnat_right = 1;
558 double yp_right = 0.0;
559 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
560 bcnat_left,bcnat_right,&fspl[0]);
561
562 for ( int i = 0; i < nplin; i++ )
563 {
564 double r = i * mesh_spacing;
565 if ( r >= upf_r[0] )
566 splint(n,&upf_r[0],&f[0],&fspl[0],r,&nlcc_lin[i]);
567 else
568 // use value closest to the origin for r=0
569 nlcc_lin[i] = upf_nlcc[0];
570 if ( fabs(nlcc_lin[i]) < 1.e-12 )
571 nlcc_lin[i] = 0.0;
572 }
573 }
574
575 // interpolate vloc
576 // factor 0.5: convert from Ry in UPF to Hartree in QSO
577 for ( int i = 0; i < upf_vloc.size(); i++ )
578 f[i] = 0.5 * upf_vloc[i];
579
580 int n = upf_vloc.size();
581 int bcnat_left = 0;
582 double yp_left = 0.0;
583 int bcnat_right = 1;
584 double yp_right = 0.0;
585 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
586 bcnat_left,bcnat_right,&fspl[0]);
587
588 vector<double> vloc_lin(nplin);
589 for ( int i = 0; i < nplin; i++ )
590 {
591 double r = i * mesh_spacing;
592 if ( r >= upf_r[0] )
593 splint(n,&upf_r[0],&f[0],&fspl[0],r,&vloc_lin[i]);
594 else
595 // use value closest to the origin for r=0
596 vloc_lin[i] = 0.5 * upf_vloc[0];
597 }
598
599 // interpolate vps[j], j=0, nproj-1
600 vector<vector<double> > vps_lin;
601 vps_lin.resize(vps.size());
602 for ( int j = 0; j < vps.size(); j++ )
603 {
604 vps_lin[j].resize(nplin);
605 }
606
607 for ( int j = 0; j < upf_nproj; j++ )
608 {
609 // factor 0.5: convert from Ry in UPF to Hartree in QSO
610 for ( int i = 0; i < upf_vloc.size(); i++ )
611 f[i] = 0.5 * vps[j][i];
612
613 int n = upf_vloc.size();
614 int bcnat_left = 0;
615 double yp_left = 0.0;
616 int bcnat_right = 1;
617 double yp_right = 0.0;
618 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
619 bcnat_left,bcnat_right,&fspl[0]);
620
621 for ( int i = 0; i < nplin; i++ )
622 {
623 double r = i * mesh_spacing;
624 if ( r >= upf_r[0] )
625 splint(n,&upf_r[0],&f[0],&fspl[0],r,&vps_lin[j][i]);
626 else
627 vps_lin[j][i] = 0.5 * vps[j][0];
628 }
629 }
630
631 // write potentials in gnuplot format on file vlin.dat
632 ofstream vlin("vlin.dat");
633 for ( int l = 0; l <= qso_lmax; l++ )
634 {
635 vlin << "# v, l=" << l << endl;
636 if ( iproj[l] == -1 )
637 {
638 // l == llocal
639 for ( int i = 0; i < nplin; i++ )
640 vlin << i*mesh_spacing << " " << vloc_lin[i] << endl;
641 vlin << endl << endl;
642 }
643 else
644 {
645 for ( int i = 0; i < nplin; i++ )
646 vlin << i*mesh_spacing << " " << vps_lin[iproj[l]][i] << endl;
647 vlin << endl << endl;
648 }
649 }
650
651 // interpolate wavefunctions on the linear mesh
652
653 vector<vector<double> > wf_lin;
654 wf_lin.resize(upf_nwf);
655 for ( int j = 0; j < upf_nwf; j++ )
656 {
657 wf_lin[j].resize(nplin);
658 assert(upf_wf[j].size()<=f.size());
659 for ( int i = 0; i < upf_wf[j].size(); i++ )
660 {
661 if ( upf_r[i] > 0.0 )
662 f[i] = upf_wf[j][i] / upf_r[i];
663 else
664 {
665 // value at origin, depending on angular momentum
666 if ( upf_wf_l[j] == 0 )
667 {
668 // l=0: take value closest to r=0
669 f[i] = upf_wf[j][1]/upf_r[1];
670 }
671 else
672 {
673 // l>0:
674 f[i] = 0.0;
675 }
676 }
677 }
678
679 int n = upf_wf[j].size();
680 // choose boundary condition at origin depending on angular momentum
681 int bcnat_left = 0;
682 double yp_left = 0.0;
683 if ( upf_wf_l[j] == 1 )
684 {
685 bcnat_left = 1; // use natural bc
686 double yp_left = 0.0; // not used
687 }
688 int bcnat_right = 1;
689 double yp_right = 0.0;
690 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
691 bcnat_left,bcnat_right,&fspl[0]);
692
693 for ( int i = 0; i < nplin; i++ )
694 {
695 double r = i * mesh_spacing;
696 if ( r >= upf_r[0] )
697 splint(n,&upf_r[0],&f[0],&fspl[0],r,&wf_lin[j][i]);
698 else
699 {
700 // r < upf_r[0]
701 assert(upf_r[0]>0.0);
702 // compute value near origin, depending on angular momentum
703 if ( upf_wf_l[j] == 0 )
704 {
705 // l=0: take value closest to r=0
706 wf_lin[j][i] = upf_wf[j][0]/upf_r[0];
707 }
708 else
709 {
710 // l>0:
711 wf_lin[j][i] = upf_wf[j][0] * r / ( upf_r[0] * upf_r[0] );
712 }
713 }
714 }
715
716 vlin << "# phi, l=" << upf_l[j] << endl;
717 for ( int i = 0; i < nplin; i++ )
718 vlin << i*mesh_spacing << " " << wf_lin[j][i] << endl;
719 vlin << endl << endl;
720 }
721
722 cerr << " interpolation done" << endl;
723
724 #if 1
725 // output potential on log mesh
726 ofstream vout("v.dat");
727 for ( int l = 0; l <= qso_lmax; l++ )
728 {
729 vout << "# v, l=" << l << endl;
730 if ( iproj[l] == -1 )
731 {
732 // l == llocal
733 for ( int i = 0; i < upf_vloc.size(); i++ )
734 vout << upf_r[i] << " " << 0.5*upf_vloc[i] << endl;
735 vout << endl << endl;
736 }
737 else
738 {
739 for ( int i = 0; i < vps[iproj[l]].size(); i++ )
740 vout << upf_r[i] << " " << 0.5*vps[iproj[l]][i] << endl;
741 vout << endl << endl;
742 }
743 }
744 vout << endl << endl;
745 vout.close();
746 #endif
747
748 // Generate QSO file
749
750 // output potential in QSO format
751 cout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
752 cout << "<fpmd:species xmlns:fpmd=\"http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0\"" << endl;
753 cout << " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" << endl;
754 cout << " xsi:schemaLocation=\"http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0" << endl;
755 cout << " species.xsd\">" << endl;
756 cout << "<description>" << endl;
757 cout << "Translated from UPF format by upf2qso " << release
758 << " on " << isodate() << endl;
759 cout << upf_pp_info;
760 cout << "</description>" << endl;
761 cout << "<symbol>" << upf_symbol << "</symbol>" << endl;
762 cout << "<atomic_number>" << atomic_number << "</atomic_number>" << endl;
763 cout << "<mass>" << mass << "</mass>" << endl;
764 cout << "<norm_conserving_pseudopotential>" << endl;
765 cout << "<valence_charge>" << upf_zval << "</valence_charge>" << endl;
766 cout << "<lmax>" << qso_lmax << "</lmax>" << endl;
767 cout << "<llocal>" << upf_llocal << "</llocal>" << endl;
768 cout << "<nquad>0</nquad>" << endl;
769 cout << "<rquad>0.0</rquad>" << endl;
770 cout << "<mesh_spacing>" << mesh_spacing << "</mesh_spacing>" << endl;
771
772 cout.setf(ios::scientific,ios::floatfield);
773 if ( upf_nlcc_flag == "T" )
774 {
775 cout << "<core_density size=\"" << nplin << "\">" << endl;
776 for ( int i = 0; i < nplin; i++ )
777 cout << setprecision(10) << nlcc_lin[i] << endl;
778 cout << "</core_density>" << endl;
779 }
780
781 for ( int l = 0; l <= qso_lmax; l++ )
782 {
783 cout << "<projector l=\"" << l << "\" size=\"" << nplin << "\">"
784 << endl;
785 cout << "<radial_potential>" << endl;
786 if ( iproj[l] == -1 )
787 {
788 // l == llocal
789 for ( int i = 0; i < nplin; i++ )
790 cout << setprecision(10) << vloc_lin[i] << endl;
791 }
792 else
793 {
794 for ( int i = 0; i < nplin; i++ )
795 cout << setprecision(10) << vps_lin[iproj[l]][i] << endl;
796 }
797 cout << "</radial_potential>" << endl;
798 // find index j corresponding to angular momentum l
799 int j = 0;
800 while ( upf_wf_l[j] != l && j < upf_nwf ) j++;
801 // check if found
802 const bool found = ( j != upf_nwf );
803 // print wf only if found
804 if ( found )
805 {
806 cout << "<radial_function>" << endl;
807 for ( int i = 0; i < nplin; i++ )
808 cout << setprecision(10) << wf_lin[j][i] << endl;
809 cout << "</radial_function>" << endl;
810 }
811 cout << "</projector>" << endl;
812 }
813 cout << "</norm_conserving_pseudopotential>" << endl;
814 cout << "</fpmd:species>" << endl;
815
816 }
817 else if ( upf_version == 2 )
818 {
819 // process UPF version 2 potential
820 seek_str("<PP_INFO>");
821 string upf_pp_info;
822 bool done = false;
823 while (!done)
824 {
825 getline(cin,buf);
826 is.clear();
827 is.str(buf);
828 is >> s;
829 done = ( s == "</PP_INFO>" );
830 if ( !done )
831 {
832 upf_pp_info += buf + '\n';
833 }
834 }
835
836 // remove all '<' and '>' characters from the PP_INFO field
837 // for XML compatibility
838 p = upf_pp_info.find_first_of("<>");
839 while ( p != string::npos )
840 {
841 upf_pp_info[p] = ' ';
842 p = upf_pp_info.find_first_of("<>");
843 }
844
845 string tag = find_start_element("PP_HEADER");
846
847 // get attribute "element"
848 string upf_symbol = get_attr(tag,"element");
849 cerr << " upf_symbol: " << upf_symbol << endl;
850
851 // get atomic number and mass
852 const int atomic_number = pt.z(upf_symbol);
853 const double mass = pt.mass(upf_symbol);
854
855 // check if potential is norm-conserving or semi-local
856 string pseudo_type = get_attr(tag,"pseudo_type");
857 cerr << " pseudo_type = " << pseudo_type << endl;
858 if ( pseudo_type!="NC" && pseudo_type!="SL" )
859 {
860 cerr << " pseudo_type must be NC or SL" << endl;
861 return 1;
862 }
863
864 // NLCC flag
865 string upf_nlcc_flag = get_attr(tag,"core_correction");
866 if ( upf_nlcc_flag == "T" )
867 {
868 cerr << " Potential includes a non-linear core correction" << endl;
869 }
870 cerr << " upf_nlcc_flag = " << upf_nlcc_flag << endl;
871
872 // XC functional (add in description)
873 string upf_functional = get_attr(tag,"functional");
874 // add XC functional information to description
875 upf_pp_info += "functional = " + upf_functional + '\n';
876 cerr << " upf_functional = " << upf_functional << endl;
877
878 // valence charge
879 double upf_zval = 0.0;
880 string buf = get_attr(tag,"z_valence");
881 is.clear();
882 is.str(buf);
883 is >> upf_zval;
884 cerr << " upf_zval = " << upf_zval << endl;
885
886 // max angular momentum
887 int upf_lmax;
888 buf = get_attr(tag,"l_max");
889 is.clear();
890 is.str(buf);
891 is >> upf_lmax;
892 cerr << " upf_lmax = " << upf_lmax << endl;
893
894 // local angular momentum
895 int upf_llocal;
896 buf = get_attr(tag,"l_local");
897 is.clear();
898 is.str(buf);
899 is >> upf_llocal;
900 cerr << " upf_llocal = " << upf_llocal << endl;
901
902 // number of points in mesh
903 int upf_mesh_size;
904 buf = get_attr(tag,"mesh_size");
905 is.clear();
906 is.str(buf);
907 is >> upf_mesh_size;
908 cerr << " upf_mesh_size = " << upf_mesh_size << endl;
909
910 // number of wavefunctions
911 int upf_nwf;
912 buf = get_attr(tag,"number_of_wfc");
913 is.clear();
914 is.str(buf);
915 is >> upf_nwf;
916 cerr << " upf_nwf = " << upf_nwf << endl;
917
918 // number of projectors
919 int upf_nproj;
920 buf = get_attr(tag,"number_of_proj");
921 is.clear();
922 is.str(buf);
923 is >> upf_nproj;
924 cerr << " upf_nproj = " << upf_nproj << endl;
925
926 vector<int> upf_l(upf_nwf);
927
928 // read mesh
929 find_start_element("PP_MESH");
930 find_start_element("PP_R");
931 vector<double> upf_r(upf_mesh_size);
932 for ( int i = 0; i < upf_mesh_size; i++ )
933 cin >> upf_r[i];
934 find_end_element("PP_R");
935 find_start_element("PP_RAB");
936 vector<double> upf_rab(upf_mesh_size);
937 for ( int i = 0; i < upf_mesh_size; i++ )
938 cin >> upf_rab[i];
939 find_end_element("PP_RAB");
940 find_end_element("PP_MESH");
941
942 find_start_element("PP_LOCAL");
943 vector<double> upf_vloc(upf_mesh_size);
944 for ( int i = 0; i < upf_mesh_size; i++ )
945 cin >> upf_vloc[i];
946 find_end_element("PP_LOCAL");
947
948 find_start_element("PP_NONLOCAL");
949 vector<vector<double> > upf_vnl;
950 upf_vnl.resize(upf_nproj);
951 vector<int> upf_proj_l(upf_nproj);
952
953 ostringstream os;
954 for ( int j = 0; j < upf_nproj; j++ )
955 {
956 int index, angular_momentum;
957 os.str("");
958 os << j+1;
959 string element_name = "PP_BETA." + os.str();
960 tag = find_start_element(element_name);
961 cerr << tag << endl;
962
963 buf = get_attr(tag,"index");
964 is.clear();
965 is.str(buf);
966 is >> index;
967 cerr << " index = " << index << endl;
968
969 buf = get_attr(tag,"angular_momentum");
970 is.clear();
971 is.str(buf);
972 is >> angular_momentum;
973 cerr << " angular_momentum = " << angular_momentum << endl;
974
975 assert(angular_momentum <= upf_lmax);
976 upf_proj_l[index-1] = angular_momentum;
977
978 upf_vnl[j].resize(upf_mesh_size);
979 for ( int i = 0; i < upf_mesh_size; i++ )
980 cin >> upf_vnl[j][i];
981
982 find_end_element(element_name);
983 }
984
985 // compute number of projectors for each l
986 // nproj_l[l] is the number of projectors having angular momentum l
987 vector<int> nproj_l(upf_lmax+1);
988 for ( int l = 0; l <= upf_lmax; l++ )
989 {
990 nproj_l[l] = 0;
991 for ( int ip = 0; ip < upf_nproj; ip++ )
992 if ( upf_proj_l[ip] == l ) nproj_l[l]++;
993 }
994
995 tag = find_start_element("PP_DIJ");
996 int size;
997 buf = get_attr(tag,"size");
998 is.clear();
999 is.str(buf);
1000 is >> size;
1001 cerr << "PP_DIJ size = " << size << endl;
1002
1003 if ( size != upf_nproj*upf_nproj )
1004 {
1005 cerr << " Number of non-zero Dij differs from number of projectors"
1006 << endl;
1007 return 1;
1008 }
1009 int upf_ndij = size;
1010
1011 vector<double> upf_d(upf_ndij);
1012 for ( int i = 0; i < upf_ndij; i++ )
1013 {
1014 cin >> upf_d[i];
1015 }
1016 int imax = sqrt(size+1.e-5);
1017 assert(imax*imax==size);
1018
1019 // Check if Dij has non-diagonal elements
1020 // non-diagonal elements are not supported
1021 for ( int m = 0; m < imax; m++ )
1022 for ( int n = 0; n < imax; n++ )
1023 if ( (m != n) && (upf_d[n*imax+m] != 0.0) )
1024 {
1025 cerr << " Non-local Dij has off-diagonal elements" << endl;
1026 cerr << " m=" << m << " n=" << n << endl;
1027 return 1;
1028 }
1029
1030 find_end_element("PP_DIJ");
1031
1032 find_end_element("PP_NONLOCAL");
1033
1034 // make table iproj[l] mapping l to iproj
1035 // vnl(l) is in vnl[iproj[l]] if iproj[l] > -1
1036 // vlocal if iproj[llocal] = -1
1037 vector<int> iproj(upf_lmax+2);
1038 for ( int l = 0; l <= upf_lmax+1; l++ )
1039 iproj[l] = -1;
1040 for ( int j = 0; j < upf_nproj; j++ )
1041 iproj[upf_proj_l[j]] = j;
1042
1043 // determine angular momentum of local potential in UPF file
1044 // upf_llocal is the angular momentum of the local potential
1045 // increase lmax if there are more projectors than wavefunctions
1046 int qso_lmax = upf_lmax;
1047 if (upf_lmax < upf_llocal)
1048 {
1049 qso_lmax = upf_lmax+1;
1050 }
1051
1052 if ( pseudo_type == "SL" )
1053 {
1054 find_start_element("PP_PSWFC");
1055 vector<vector<double> > upf_wf;
1056 vector<int> upf_wf_l(upf_nwf);
1057 upf_wf.resize(upf_nwf);
1058 for ( int j = 0; j < upf_nwf; j++ )
1059 {
1060 int index, l;
1061 os.str("");
1062 os << j+1;
1063 string element_name = "PP_CHI." + os.str();
1064 tag = find_start_element(element_name);
1065 cerr << tag << endl;
1066
1067 buf = get_attr(tag,"index");
1068 is.clear();
1069 is.str(buf);
1070 is >> index;
1071 cerr << " index = " << index << endl;
1072
1073 buf = get_attr(tag,"l");
1074 is.clear();
1075 is.str(buf);
1076 is >> l;
1077 cerr << " l = " << l << endl;
1078
1079 assert(l <= upf_lmax);
1080 upf_proj_l[index-1] = l;
1081 upf_wf[j].resize(upf_mesh_size);
1082 for ( int i = 0; i < upf_mesh_size; i++ )
1083 cin >> upf_wf[j][i];
1084 }
1085 find_end_element("PP_PSWFC");
1086
1087 // NLCC
1088 vector<double> upf_nlcc;
1089 if ( upf_nlcc_flag == "T" )
1090 {
1091 find_start_element("PP_NLCC");
1092 upf_nlcc.resize(upf_mesh_size);
1093 for ( int i = 0; i < upf_mesh_size; i++ )
1094 cin >> upf_nlcc[i];
1095 find_end_element("PP_NLCC");
1096 }
1097
1098 // output original data in file upf.dat
1099 ofstream upf("upf.dat");
1100 upf << "# vloc" << endl;
1101 for ( int i = 0; i < upf_vloc.size(); i++ )
1102 upf << upf_r[i] << " " << upf_vloc[i] << endl;
1103 upf << endl << endl;
1104 for ( int j = 0; j < upf_nproj; j++ )
1105 {
1106 upf << "# proj j=" << j << endl;
1107 for ( int i = 0; i < upf_vnl[j].size(); i++ )
1108 upf << upf_r[i] << " " << upf_vnl[j][i] << endl;
1109 upf << endl << endl;
1110 }
1111 for ( int j = 0; j < upf_nwf; j++ )
1112 {
1113 upf << "# wf j=" << j << endl;
1114 for ( int i = 0; i < upf_wf[j].size(); i++ )
1115 upf << upf_r[i] << " " << upf_wf[j][i] << endl;
1116 upf << endl << endl;
1117 }
1118 upf.close();
1119
1120 // print summary
1121 cerr << "PP_INFO:" << endl << upf_pp_info << endl;
1122 cerr << "Element: " << upf_symbol << endl;
1123 cerr << "NLCC: " << upf_nlcc_flag << endl;
1124 //cerr << "XC: " << upf_xcf[0] << " " << upf_xcf[1] << " "
1125 // << upf_xcf[2] << " " << upf_xcf[3] << endl;
1126 cerr << "Zv: " << upf_zval << endl;
1127 cerr << "lmax: " << qso_lmax << endl;
1128 cerr << "llocal: " << upf_llocal << endl;
1129 cerr << "nwf: " << upf_nwf << endl;
1130 cerr << "mesh_size: " << upf_mesh_size << endl;
1131
1132 // compute delta_vnl[l][i] on the upf log mesh
1133
1134 // divide the projector function by the wavefunction, except if
1135 // the wavefunction amplitude is smaller than tol, outside of rcut_divide.
1136 const double tol = 1.e-5;
1137 const double rcut_divide = 1.0;
1138 vector<vector<double> > delta_vnl;
1139 delta_vnl.resize(upf_nproj);
1140 for ( int j = 0; j < upf_nproj; j++ )
1141 {
1142 delta_vnl[j].resize(upf_wf[j].size());
1143 for ( int i = 0; i < delta_vnl[j].size(); i++ )
1144 {
1145 double num = upf_vnl[j][i];
1146 double den = upf_wf[upf_proj_l[j]][i];
1147
1148 delta_vnl[j][i] = 0.0;
1149 if ( upf_r[i] < rcut_divide )
1150 {
1151 // near the origin
1152 if ( i == 0 && fabs(den) < tol )
1153 {
1154 // i = 0 for linear mesh, r = 0.0: use nearest value
1155 delta_vnl[j][i] = upf_vnl[j][1] / upf_wf[upf_proj_l[j]][1];
1156 }
1157 else
1158 {
1159 // other points near the origin
1160 delta_vnl[j][i] = num / den;
1161 }
1162 }
1163 else
1164 {
1165 // wavefunction gets small at large r.
1166 // Assume that delta_vnl is zero when that happens
1167 if ( fabs(den) > tol )
1168 delta_vnl[j][i] = num / den;
1169 }
1170 }
1171 }
1172
1173 vector<vector<double> > vps;
1174 vps.resize(upf_nproj+1);
1175 for ( int j = 0; j < upf_nproj; j++ )
1176 {
1177 vps[j].resize(upf_mesh_size);
1178 for ( int i = 0; i < delta_vnl[j].size(); i++ )
1179 vps[j][i] = upf_vloc[i] + delta_vnl[j][i];
1180 }
1181
1182 // interpolate functions on linear mesh
1183 const double mesh_spacing = 0.01;
1184 int nplin = (int) (rcut / mesh_spacing);
1185 vector<double> f(upf_mesh_size), fspl(upf_mesh_size);
1186
1187 // interpolate NLCC
1188 vector<double> nlcc_lin(nplin);
1189 if ( upf_nlcc_flag == "T" )
1190 {
1191 assert(upf_mesh_size==upf_nlcc.size());
1192 for ( int i = 0; i < upf_nlcc.size(); i++ )
1193 f[i] = upf_nlcc[i];
1194 int n = upf_nlcc.size();
1195 int bcnat_left = 0;
1196 double yp_left = 0.0;
1197 int bcnat_right = 1;
1198 double yp_right = 0.0;
1199 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
1200 bcnat_left,bcnat_right,&fspl[0]);
1201
1202 for ( int i = 0; i < nplin; i++ )
1203 {
1204 double r = i * mesh_spacing;
1205 if ( r >= upf_r[0] )
1206 splint(n,&upf_r[0],&f[0],&fspl[0],r,&nlcc_lin[i]);
1207 else
1208 // use value closest to the origin for r=0
1209 nlcc_lin[i] = upf_nlcc[0];
1210 if ( fabs(nlcc_lin[i]) < 1.e-12 )
1211 nlcc_lin[i] = 0.0;
1212 }
1213 }
1214
1215 // interpolate vloc
1216 // factor 0.5: convert from Ry in UPF to Hartree in QSO
1217 for ( int i = 0; i < upf_vloc.size(); i++ )
1218 f[i] = 0.5 * upf_vloc[i];
1219
1220 int n = upf_vloc.size();
1221 int bcnat_left = 0;
1222 double yp_left = 0.0;
1223 int bcnat_right = 1;
1224 double yp_right = 0.0;
1225 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
1226 bcnat_left,bcnat_right,&fspl[0]);
1227
1228 vector<double> vloc_lin(nplin);
1229 for ( int i = 0; i < nplin; i++ )
1230 {
1231 double r = i * mesh_spacing;
1232 if ( r >= upf_r[0] )
1233 splint(n,&upf_r[0],&f[0],&fspl[0],r,&vloc_lin[i]);
1234 else
1235 // use value closest to the origin for r=0
1236 vloc_lin[i] = 0.5 * upf_vloc[0];
1237 }
1238
1239 // interpolate vps[j], j=0, nproj-1
1240 vector<vector<double> > vps_lin;
1241 vps_lin.resize(vps.size());
1242 for ( int j = 0; j < vps.size(); j++ )
1243 {
1244 vps_lin[j].resize(nplin);
1245 }
1246
1247 for ( int j = 0; j < upf_nproj; j++ )
1248 {
1249 // factor 0.5: convert from Ry in UPF to Hartree in QSO
1250 for ( int i = 0; i < upf_vloc.size(); i++ )
1251 f[i] = 0.5 * vps[j][i];
1252
1253 int n = upf_vloc.size();
1254 int bcnat_left = 0;
1255 double yp_left = 0.0;
1256 int bcnat_right = 1;
1257 double yp_right = 0.0;
1258 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
1259 bcnat_left,bcnat_right,&fspl[0]);
1260
1261 for ( int i = 0; i < nplin; i++ )
1262 {
1263 double r = i * mesh_spacing;
1264 if ( r >= upf_r[0] )
1265 splint(n,&upf_r[0],&f[0],&fspl[0],r,&vps_lin[j][i]);
1266 else
1267 vps_lin[j][i] = 0.5 * vps[j][0];
1268 }
1269 }
1270
1271 // write potentials in gnuplot format on file vlin.dat
1272 ofstream vlin("vlin.dat");
1273 for ( int l = 0; l <= qso_lmax; l++ )
1274 {
1275 vlin << "# v, l=" << l << endl;
1276 if ( iproj[l] == -1 )
1277 {
1278 // l == llocal
1279 for ( int i = 0; i < nplin; i++ )
1280 vlin << i*mesh_spacing << " " << vloc_lin[i] << endl;
1281 vlin << endl << endl;
1282 }
1283 else
1284 {
1285 for ( int i = 0; i < nplin; i++ )
1286 vlin << i*mesh_spacing << " " << vps_lin[iproj[l]][i] << endl;
1287 vlin << endl << endl;
1288 }
1289 }
1290
1291 // interpolate wavefunctions on the linear mesh
1292
1293 vector<vector<double> > wf_lin;
1294 wf_lin.resize(upf_nwf);
1295 for ( int j = 0; j < upf_nwf; j++ )
1296 {
1297 wf_lin[j].resize(nplin);
1298 assert(upf_wf[j].size()<=f.size());
1299 for ( int i = 0; i < upf_wf[j].size(); i++ )
1300 {
1301 if ( upf_r[i] > 0.0 )
1302 f[i] = upf_wf[j][i] / upf_r[i];
1303 else
1304 {
1305 // value at origin, depending on angular momentum
1306 if ( upf_wf_l[j] == 0 )
1307 {
1308 // l=0: take value closest to r=0
1309 f[i] = upf_wf[j][1]/upf_r[1];
1310 }
1311 else
1312 {
1313 // l>0:
1314 f[i] = 0.0;
1315 }
1316 }
1317 }
1318
1319 int n = upf_wf[j].size();
1320 // choose boundary condition at origin depending on angular momentum
1321 int bcnat_left = 0;
1322 double yp_left = 0.0;
1323 if ( upf_wf_l[j] == 1 )
1324 {
1325 bcnat_left = 1; // use natural bc
1326 double yp_left = 0.0; // not used
1327 }
1328 int bcnat_right = 1;
1329 double yp_right = 0.0;
1330 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
1331 bcnat_left,bcnat_right,&fspl[0]);
1332
1333 for ( int i = 0; i < nplin; i++ )
1334 {
1335 double r = i * mesh_spacing;
1336 if ( r >= upf_r[0] )
1337 splint(n,&upf_r[0],&f[0],&fspl[0],r,&wf_lin[j][i]);
1338 else
1339 {
1340 // r < upf_r[0]
1341 assert(upf_r[0]>0.0);
1342 // compute value near origin, depending on angular momentum
1343 if ( upf_wf_l[j] == 0 )
1344 {
1345 // l=0: take value closest to r=0
1346 wf_lin[j][i] = upf_wf[j][0]/upf_r[0];
1347 }
1348 else
1349 {
1350 // l>0:
1351 wf_lin[j][i] = upf_wf[j][0] * r / ( upf_r[0] * upf_r[0] );
1352 }
1353 }
1354 }
1355
1356 vlin << "# phi, l=" << upf_l[j] << endl;
1357 for ( int i = 0; i < nplin; i++ )
1358 vlin << i*mesh_spacing << " " << wf_lin[j][i] << endl;
1359 vlin << endl << endl;
1360 }
1361
1362 cerr << " interpolation done" << endl;
1363
1364 #if 1
1365 // output potential on log mesh
1366 ofstream vout("v.dat");
1367 for ( int l = 0; l <= qso_lmax; l++ )
1368 {
1369 vout << "# v, l=" << l << endl;
1370 if ( iproj[l] == -1 )
1371 {
1372 // l == llocal
1373 for ( int i = 0; i < upf_vloc.size(); i++ )
1374 vout << upf_r[i] << " " << 0.5*upf_vloc[i] << endl;
1375 vout << endl << endl;
1376 }
1377 else
1378 {
1379 for ( int i = 0; i < vps[iproj[l]].size(); i++ )
1380 vout << upf_r[i] << " " << 0.5*vps[iproj[l]][i] << endl;
1381 vout << endl << endl;
1382 }
1383 }
1384 vout << endl << endl;
1385 vout.close();
1386 #endif
1387
1388 // Generate QSO file
1389
1390 // output potential in QSO format
1391 cout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
1392 cout << "<fpmd:species xmlns:fpmd=\"http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0\"" << endl;
1393 cout << " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" << endl;
1394 cout << " xsi:schemaLocation=\"http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0" << endl;
1395 cout << " species.xsd\">" << endl;
1396 cout << "<description>" << endl;
1397 cout << "Translated from UPF format by upf2qso " << release
1398 << " on " << isodate() << endl;
1399 cout << upf_pp_info;
1400 cout << "</description>" << endl;
1401 cout << "<symbol>" << upf_symbol << "</symbol>" << endl;
1402 cout << "<atomic_number>" << atomic_number << "</atomic_number>" << endl;
1403 cout << "<mass>" << mass << "</mass>" << endl;
1404 cout << "<norm_conserving_pseudopotential>" << endl;
1405 cout << "<valence_charge>" << upf_zval << "</valence_charge>" << endl;
1406 cout << "<lmax>" << qso_lmax << "</lmax>" << endl;
1407 cout << "<llocal>" << upf_llocal << "</llocal>" << endl;
1408 cout << "<nquad>0</nquad>" << endl;
1409 cout << "<rquad>0.0</rquad>" << endl;
1410 cout << "<mesh_spacing>" << mesh_spacing << "</mesh_spacing>" << endl;
1411
1412 cout.setf(ios::scientific,ios::floatfield);
1413 if ( upf_nlcc_flag == "T" )
1414 {
1415 cout << "<core_density size=\"" << nplin << "\">" << endl;
1416 for ( int i = 0; i < nplin; i++ )
1417 cout << setprecision(10) << nlcc_lin[i] << endl;
1418 cout << "</core_density>" << endl;
1419 }
1420
1421 for ( int l = 0; l <= qso_lmax; l++ )
1422 {
1423 cout << "<projector l=\"" << l << "\" size=\"" << nplin << "\">"
1424 << endl;
1425 cout << "<radial_potential>" << endl;
1426 if ( iproj[l] == -1 )
1427 {
1428 // l == llocal
1429 for ( int i = 0; i < nplin; i++ )
1430 cout << setprecision(10) << vloc_lin[i] << endl;
1431 }
1432 else
1433 {
1434 for ( int i = 0; i < nplin; i++ )
1435 cout << setprecision(10) << vps_lin[iproj[l]][i] << endl;
1436 }
1437 cout << "</radial_potential>" << endl;
1438 // find index j corresponding to angular momentum l
1439 int j = 0;
1440 while ( upf_wf_l[j] != l && j < upf_nwf ) j++;
1441 // check if found
1442 const bool found = ( j != upf_nwf );
1443 // print wf only if found
1444 if ( found )
1445 {
1446 cout << "<radial_function>" << endl;
1447 for ( int i = 0; i < nplin; i++ )
1448 cout << setprecision(10) << wf_lin[j][i] << endl;
1449 cout << "</radial_function>" << endl;
1450 }
1451 cout << "</projector>" << endl;
1452 }
1453 cout << "</norm_conserving_pseudopotential>" << endl;
1454 cout << "</fpmd:species>" << endl;
1455 } // if SL
1456
1457 if ( pseudo_type == "NC" )
1458 {
1459 // NLCC
1460 vector<double> upf_nlcc;
1461 if ( upf_nlcc_flag == "T" )
1462 {
1463 find_start_element("PP_NLCC");
1464 upf_nlcc.resize(upf_mesh_size);
1465 for ( int i = 0; i < upf_mesh_size; i++ )
1466 cin >> upf_nlcc[i];
1467 find_end_element("PP_NLCC");
1468 }
1469
1470 cerr << " NC potential" << endl;
1471 // output original data in file upf.dat
1472 ofstream upf("upf.dat");
1473 upf << "# vloc" << endl;
1474 for ( int i = 0; i < upf_vloc.size(); i++ )
1475 upf << upf_r[i] << " " << upf_vloc[i] << endl;
1476 upf << endl << endl;
1477 for ( int j = 0; j < upf_nproj; j++ )
1478 {
1479 upf << "# proj j=" << j << endl;
1480 for ( int i = 0; i < upf_vnl[j].size(); i++ )
1481 upf << upf_r[i] << " " << upf_vnl[j][i] << endl;
1482 upf << endl << endl;
1483 }
1484
1485 upf << "# dij " << endl;
1486 for ( int j = 0; j < upf_d.size(); j++ )
1487 {
1488 upf << j << " " << upf_d[j] << endl;
1489 }
1490 upf.close();
1491
1492 // print summary
1493 cerr << "PP_INFO:" << endl << upf_pp_info << endl;
1494 cerr << "Element: " << upf_symbol << endl;
1495 cerr << "NLCC: " << upf_nlcc_flag << endl;
1496 // cerr << "XC: " << upf_xcf[0] << " " << upf_xcf[1] << " "
1497 // << upf_xcf[2] << " " << upf_xcf[3] << endl;
1498 cerr << "Zv: " << upf_zval << endl;
1499 cerr << "lmax: " << qso_lmax << endl;
1500 cerr << "nproj: " << upf_nproj << endl;
1501 cerr << "mesh_size: " << upf_mesh_size << endl;
1502
1503 // interpolate functions on linear mesh
1504 const double mesh_spacing = 0.01;
1505 int nplin = (int) (rcut / mesh_spacing);
1506 vector<double> f(upf_mesh_size), fspl(upf_mesh_size);
1507
1508 // interpolate NLCC
1509 vector<double> nlcc_lin(nplin);
1510 if ( upf_nlcc_flag == "T" )
1511 {
1512 assert(upf_mesh_size==upf_nlcc.size());
1513 for ( int i = 0; i < upf_nlcc.size(); i++ )
1514 f[i] = upf_nlcc[i];
1515 int n = upf_nlcc.size();
1516 int bcnat_left = 0;
1517 double yp_left = 0.0;
1518 int bcnat_right = 1;
1519 double yp_right = 0.0;
1520 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
1521 bcnat_left,bcnat_right,&fspl[0]);
1522
1523 for ( int i = 0; i < nplin; i++ )
1524 {
1525 double r = i * mesh_spacing;
1526 if ( r >= upf_r[0] )
1527 splint(n,&upf_r[0],&f[0],&fspl[0],r,&nlcc_lin[i]);
1528 else
1529 // use value closest to the origin for r=0
1530 nlcc_lin[i] = upf_nlcc[0];
1531 if ( fabs(nlcc_lin[i]) < 1.e-12 )
1532 nlcc_lin[i] = 0.0;
1533 }
1534 }
1535
1536 // interpolate vloc
1537 // factor 0.5: convert from Ry in UPF to Hartree in QSO
1538 for ( int i = 0; i < upf_vloc.size(); i++ )
1539 f[i] = 0.5 * upf_vloc[i];
1540
1541 int n = upf_vloc.size();
1542 int bcnat_left = 0;
1543 double yp_left = 0.0;
1544 int bcnat_right = 1;
1545 double yp_right = 0.0;
1546 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
1547 bcnat_left,bcnat_right,&fspl[0]);
1548
1549 vector<double> vloc_lin(nplin);
1550 for ( int i = 0; i < nplin; i++ )
1551 {
1552 double r = i * mesh_spacing;
1553 if ( r >= upf_r[0] )
1554 splint(n,&upf_r[0],&f[0],&fspl[0],r,&vloc_lin[i]);
1555 else
1556 // use value closest to the origin for r=0
1557 vloc_lin[i] = 0.5 * upf_vloc[0];
1558 }
1559
1560 // interpolate vnl[j], j=0, nproj-1
1561 vector<vector<double> > vnl_lin;
1562 vnl_lin.resize(upf_nproj);
1563 for ( int j = 0; j < vnl_lin.size(); j++ )
1564 {
1565 vnl_lin[j].resize(nplin);
1566 }
1567
1568 for ( int j = 0; j < upf_nproj; j++ )
1569 {
1570 // interpolate projectors
1571 // note: upf_vnl contains r*projector
1572 // See UPF documentation at http://www.quantum-espresso.org/
1573 // pseudopotentials/unified-pseudopotential-format
1574 assert(f.size()>=upf_vnl[j].size());
1575 for ( int i = 0; i < upf_vnl[j].size(); i++ )
1576 f[i] = upf_vnl[j][i];
1577
1578 int n = f.size();
1579 int bcnat_left = 1;
1580 double yp_left = 0.0;
1581 int bcnat_right = 1;
1582 double yp_right = 0.0;
1583 spline(n,&upf_r[0],&f[0],yp_left,yp_right,
1584 bcnat_left,bcnat_right,&fspl[0]);
1585
1586 for ( int i = 0; i < nplin; i++ )
1587 {
1588 double r = i * mesh_spacing;
1589 if ( r >= upf_r[0] )
1590 splint(n,&upf_r[0],&f[0],&fspl[0],r,&vnl_lin[j][i]);
1591 else
1592 vnl_lin[j][i] = upf_vnl[j][0];
1593 if ( fabs(vnl_lin[j][i]) < 1.e-12 )
1594 vnl_lin[j][i] = 0.0;
1595 }
1596 }
1597
1598 // write local potential and projectors in gnuplot format on file vlin.dat
1599 ofstream vlin("vlin.dat");
1600 vlin << "# vlocal" << endl;
1601 for ( int i = 0; i < nplin; i++ )
1602 vlin << vloc_lin[i] << endl;
1603 vlin << endl << endl;
1604 for ( int iproj = 0; iproj < vnl_lin.size(); iproj++ )
1605 {
1606 vlin << "# projector, l=" << upf_proj_l[iproj] << endl;
1607 for ( int i = 0; i < nplin; i++ )
1608 vlin << i*mesh_spacing << " " << vnl_lin[iproj][i] << endl;
1609 vlin << endl << endl;
1610 }
1611
1612 // Generate QSO file
1613
1614 // output potential in QSO format
1615 cout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
1616 cout << "<fpmd:species xmlns:fpmd=\"http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0\"" << endl;
1617 cout << " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" << endl;
1618 cout << " xsi:schemaLocation=\"http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0" << endl;
1619 cout << " species.xsd\">" << endl;
1620 cout << "<description>" << endl;
1621 cout << "Translated from UPF format by upf2qso " << release
1622 << " on " << isodate() << endl;
1623 cout << upf_pp_info;
1624 cout << "</description>" << endl;
1625 cout << "<symbol>" << upf_symbol << "</symbol>" << endl;
1626 cout << "<atomic_number>" << atomic_number << "</atomic_number>" << endl;
1627 cout << "<mass>" << mass << "</mass>" << endl;
1628 cout << "<norm_conserving_semilocal_pseudopotential>" << endl;
1629 cout << "<valence_charge>" << upf_zval << "</valence_charge>" << endl;
1630 cout << "<mesh_spacing>" << mesh_spacing << "</mesh_spacing>" << endl;
1631
1632 cout.setf(ios::scientific,ios::floatfield);
1633 if ( upf_nlcc_flag == "T" )
1634 {
1635 cout << "<core_density size=\"" << nplin << "\">" << endl;
1636 for ( int i = 0; i < nplin; i++ )
1637 cout << setprecision(10) << nlcc_lin[i] << endl;
1638 cout << "</core_density>" << endl;
1639 }
1640
1641 // local potential
1642 cout << "<local_potential size=\"" << nplin << "\">" << endl;
1643 for ( int i = 0; i < nplin; i++ )
1644 cout << setprecision(10) << vloc_lin[i] << endl;
1645 cout << "</local_potential>" << endl;
1646
1647 // projectors
1648 // note: vnl_lin contains r[i]*projector[i]
1649 int ip = 0;
1650 for ( int l = 0; l <= upf_lmax; l++ )
1651 {
1652 for ( int i = 0; i < nproj_l[l]; i++ )
1653 {
1654 cout << "<projector l=\"" << l << "\" i=\""
1655 << i+1 << "\" size=\"" << nplin << "\">"
1656 << endl;
1657 // value at r=0:
1658 // quadratic extrapolation of vnl_lin(r)/r to r=0 if l==0
1659 if ( l == 0 )
1660 {
1661 // use quadratic extrapolation to zero
1662 const double h = mesh_spacing;
1663 const double v = (4.0/3.0)*vnl_lin[ip][1]/h -
1664 (1.0/3.0)*vnl_lin[ip][2]/(2*h);
1665 cout << setprecision(10) << v << endl;
1666 }
1667 else
1668 {
1669 cout << setprecision(10) << 0.0 << endl;
1670 }
1671 for ( int j = 1; j < nplin; j++ )
1672 {
1673 const double r = j * mesh_spacing;
1674 cout << setprecision(10) << vnl_lin[ip][j]/r << endl;
1675 }
1676 ip++;
1677 cout << "</projector>" << endl;
1678 }
1679 }
1680
1681 // d_ij
1682 int ibase = 0;
1683 int jbase = 0;
1684 for ( int l = 0; l <= upf_lmax; l++ )
1685 {
1686 for ( int i = 0; i < upf_nproj; i++ )
1687 for ( int j = 0; j < upf_nproj; j++ )
1688 {
1689 if ( (upf_proj_l[i] == l) && (upf_proj_l[j] == l) )
1690 {
1691 int ij = i + j*upf_nproj;
1692 cout << "<d_ij l=\"" << l << "\""
1693 << " i=\"" << i-ibase+1 << "\" j=\"" << j-jbase+1
1694 << "\"> " << setprecision(10) << 0.5*upf_d[ij] << " </d_ij>"
1695 << endl;
1696 }
1697 }
1698 ibase += nproj_l[l];
1699 jbase += nproj_l[l];
1700 }
1701
1702 cout << "</norm_conserving_semilocal_pseudopotential>" << endl;
1703 cout << "</fpmd:species>" << endl;
1704 }
1705 } // version 1 or 2
1706 return 0;
1707 }
1708