|
13 | 13 |
|
14 | 14 | #include "atom_type.hpp" |
15 | 15 | #include "core/ostream_tools.hpp" |
| 16 | +#include <algorithm> |
16 | 17 |
|
17 | 18 | namespace sirius { |
18 | 19 |
|
@@ -689,14 +690,277 @@ Atom_type::read_pseudo_paw(nlohmann::json const& parser) |
689 | 690 | } |
690 | 691 | } |
691 | 692 |
|
| 693 | +bool |
| 694 | +is_json_file(std::string const& str__) |
| 695 | +{ |
| 696 | + const std::string ftype = ".json"; |
| 697 | + std::string lcstr__ = str__; |
| 698 | + std::transform(lcstr__.begin(), lcstr__.end(), lcstr__.begin(), ::tolower); |
| 699 | + return lcstr__.compare(lcstr__.size()-ftype.size(), ftype.size(), ftype) == 0; |
| 700 | +} |
| 701 | + |
| 702 | +template<typename T> |
| 703 | +std::vector<T> |
| 704 | +vec_from_str(std::string const& str__, T const scaling) |
| 705 | +{ |
| 706 | + std::vector<T> vec; |
| 707 | + std::istringstream iss(str__); |
| 708 | + |
| 709 | + std::copy(std::istream_iterator<T>(iss), std::istream_iterator<T>(), std::back_inserter(vec)); |
| 710 | + std::transform(vec.begin(), vec.end(), vec.begin(), [&scaling](T val){return val*scaling;}); |
| 711 | + |
| 712 | + return vec; |
| 713 | +} |
| 714 | + |
| 715 | + |
692 | 716 | void |
693 | | -Atom_type::read_input(std::string const& str__) |
| 717 | +Atom_type::read_pseudo_uspp(pugi::xml_node const& upf) |
694 | 718 | { |
695 | | - auto parser = read_json_from_file_or_string(str__); |
696 | 719 |
|
697 | | - if (parser.empty()) { |
698 | | - return; |
| 720 | + pugi::xml_node header = upf.child("PP_HEADER"); |
| 721 | + symbol_ = header.attribute("element").as_string(); |
| 722 | + |
| 723 | + double zp; |
| 724 | + zp = header.attribute("z_valence").as_double(); |
| 725 | + zn_ = int(zp + 1e-10); |
| 726 | + |
| 727 | + int nmtp = header.attribute("mesh_size").as_int(); |
| 728 | + |
| 729 | + auto rgrid = vec_from_str<double>(upf.child("PP_MESH").child("PP_R").child_value(), 1.0); |
| 730 | + if (static_cast<int>(rgrid.size()) != nmtp) { |
| 731 | + RTE_THROW("wrong mesh size"); |
| 732 | + } |
| 733 | + /* set the radial grid */ |
| 734 | + set_radial_grid(nmtp, rgrid.data()); |
| 735 | + |
| 736 | + local_potential(vec_from_str<double>(upf.child("PP_LOCAL").child_value(), 0.5)); |
| 737 | + |
| 738 | + ps_core_charge_density(vec_from_str<double>(upf.child("PP_NLCC").child_value(), 1.0)); |
| 739 | + |
| 740 | + ps_total_charge_density(vec_from_str<double>(upf.child("PP_RHOATOM").child_value(), 1.0)); |
| 741 | + |
| 742 | + if (local_potential().size() != rgrid.size() || ps_core_charge_density().size() != rgrid.size() || |
| 743 | + ps_total_charge_density().size() != rgrid.size()) { |
| 744 | + std::cout << local_potential().size() << " " << ps_core_charge_density().size() << " " |
| 745 | + << ps_total_charge_density().size() << std::endl; |
| 746 | + RTE_THROW("wrong array size"); |
| 747 | + } |
| 748 | + |
| 749 | + spin_orbit_coupling_ = header.attribute("has_so").as_bool(); |
| 750 | + |
| 751 | + int nbf = header.attribute("number_of_proj").as_int(); |
| 752 | + |
| 753 | + for (int i = 0; i < nbf; i++) { |
| 754 | + std::string bstr = "PP_BETA."+std::to_string(i+1); |
| 755 | + pugi::xml_node beta_node = upf.child("PP_NONLOCAL").child(bstr.data()); |
| 756 | + auto beta_raw = vec_from_str<double>(beta_node.child_value(), 1.0); |
| 757 | + |
| 758 | + int nr = beta_node.attribute("cutoff_radius_index").as_int(); |
| 759 | + if (nr == 0) { |
| 760 | + for(int j = beta_raw.size()-1; j >= 0; j--) { |
| 761 | + if (abs(beta_raw[j]) > 1.0e-80) { |
| 762 | + nr = j+1; |
| 763 | + break; |
| 764 | + } |
| 765 | + } |
| 766 | + } |
| 767 | + if (nr == 0) { |
| 768 | + nr = beta_raw.size(); |
| 769 | + } |
| 770 | + |
| 771 | + std::vector<double> beta(nr); |
| 772 | + std::copy(beta_raw.begin(), beta_raw.begin() + nr, beta.begin()); |
| 773 | + |
| 774 | + if (static_cast<int>(beta.size()) > num_mt_points()) { |
| 775 | + std::stringstream s; |
| 776 | + s << "wrong size of beta functions for atom type " << symbol_ << " (label: " << label_ << ")" << std::endl |
| 777 | + << "size of beta radial functions in the file: " << beta.size() << std::endl |
| 778 | + << "radial grid size: " << num_mt_points(); |
| 779 | + RTE_THROW(s); |
| 780 | + } |
| 781 | + int l = beta_node.attribute("angular_momentum").as_int(); |
| 782 | + if (spin_orbit_coupling_) { |
| 783 | + // we encode the fact that the total angular momentum j = l |
| 784 | + // -1/2 or l + 1/2 by changing the sign of l |
| 785 | + std::string bstr = "PP_RELBETA."+std::to_string(i+1); |
| 786 | + pugi::xml_node so_node = upf.child("PP_SPIN_ORB").child(bstr.data()); |
| 787 | + |
| 788 | + double j = so_node.attribute("jjj").as_double(); |
| 789 | + if (j < (double)l) { |
| 790 | + l *= -1; |
| 791 | + } |
| 792 | + } |
| 793 | + // add_beta_radial_function(l, beta); |
| 794 | + if (spin_orbit_coupling_) { |
| 795 | + if (l >= 0) { |
| 796 | + add_beta_radial_function(angular_momentum(l, 1), beta); |
| 797 | + } else { |
| 798 | + add_beta_radial_function(angular_momentum(-l, -1), beta); |
| 799 | + } |
| 800 | + } else { |
| 801 | + add_beta_radial_function(angular_momentum(l), beta); |
| 802 | + } |
| 803 | + } |
| 804 | + |
| 805 | + mdarray<double, 2> d_mtrx({nbf, nbf}); |
| 806 | + d_mtrx.zero(); |
| 807 | + auto v = vec_from_str<double>(upf.child("PP_NONLOCAL").child("PP_DIJ").child_value(), 0.5); |
| 808 | + |
| 809 | + for (int i = 0; i < nbf; i++) { |
| 810 | + for (int j = 0; j < nbf; j++) { |
| 811 | + d_mtrx(i, j) = v[j * nbf + i]; |
| 812 | + } |
| 813 | + } |
| 814 | + d_mtrx_ion(d_mtrx); |
| 815 | + |
| 816 | + pugi::xml_node nl_node = upf.child("PP_NONLOCAL"); |
| 817 | + if (!nl_node.child("PP_AUGMENTATION").empty()) { |
| 818 | + for (int i = 0; i<nbf; i++){ |
| 819 | + std::string istr = "PP_BETA."+std::to_string(i+1); |
| 820 | + pugi::xml_node inode = nl_node.child(istr.data()); |
| 821 | + int li = inode.attribute("angular_momentum").as_int(); |
| 822 | + |
| 823 | + for (int j = i; j<nbf; j++){ |
| 824 | + std::string jstr = "PP_BETA."+std::to_string(j+1); |
| 825 | + pugi::xml_node jnode = nl_node.child(jstr.data()); |
| 826 | + int lj = jnode.attribute("angular_momentum").as_int(); |
| 827 | + |
| 828 | + for (int l = abs(li - lj); l<li + lj + 1; l++){ |
| 829 | + if ((li + lj + l )%2 != 0) {continue;} |
| 830 | + |
| 831 | + std::string ijl_str = "PP_QIJL." + std::to_string(i+1) + "." |
| 832 | + + std::to_string(j+1) + "." + std::to_string(l); |
| 833 | + pugi::xml_node ijl_node = nl_node.child("PP_AUGMENTATION").child(ijl_str.data()); |
| 834 | + |
| 835 | + auto qij = vec_from_str<double>(ijl_node.child_value(), 1.0); |
| 836 | + if ((int)qij.size() != num_mt_points()) { |
| 837 | + RTE_THROW("wrong size of qij"); |
| 838 | + } |
| 839 | + add_q_radial_function(i, j, l, qij); |
| 840 | + } |
| 841 | + } |
| 842 | + } |
| 843 | + } |
| 844 | + |
| 845 | + /* read starting wave functions ( UPF CHI ) */ |
| 846 | + if (!header.attribute("number_of_wfc").empty()) { |
| 847 | + /* total number of pseudo atomic wave-functions */ |
| 848 | + size_t nwf = header.attribute("number_of_wfc").as_int(); |
| 849 | + /* loop over wave-functions */ |
| 850 | + for (size_t k = 0; k < nwf; k++) { |
| 851 | + std::string wstr = "PP_CHI."+std::to_string(k+1); |
| 852 | + pugi::xml_node wfc_node = upf.child("PP_PSWFC").child(wstr.data()); |
| 853 | + |
| 854 | + auto v = vec_from_str<double>(wfc_node.child_value(), 1.0); |
| 855 | + |
| 856 | + if ((int)v.size() != num_mt_points()) { |
| 857 | + std::stringstream s; |
| 858 | + s << "wrong size of atomic functions for atom type " << symbol_ << " (label: " << label_ << ")" |
| 859 | + << std::endl |
| 860 | + << "size of atomic radial functions in the file: " << v.size() << std::endl |
| 861 | + << "radial grid size: " << num_mt_points(); |
| 862 | + RTE_THROW(s); |
| 863 | + } |
| 864 | + |
| 865 | + int l = wfc_node.attribute("l").as_int(); |
| 866 | + int n = -1; |
| 867 | + double occ{0}; |
| 868 | + if (!wfc_node.attribute("occupation").empty()){ |
| 869 | + occ = wfc_node.attribute("occupation").as_double(); |
| 870 | + } |
| 871 | + |
| 872 | + if (!wfc_node.attribute("label").empty()) { |
| 873 | + auto c1 = wfc_node.attribute("label").as_string(); |
| 874 | + std::istringstream iss(std::string(1, c1[0])); |
| 875 | + iss >> n; |
| 876 | + } |
| 877 | + |
| 878 | + if (spin_orbit_coupling()){ |
| 879 | + std::string bstr = "PP_RELWFC."+std::to_string(k+1); |
| 880 | + pugi::xml_node so_node = upf.child("PP_SPIN_ORB").child(bstr.data()); |
| 881 | + if (!so_node.attribute("jchi").empty() && l != 0) { |
| 882 | + |
| 883 | + std::string wstr = "PP_CHI."+std::to_string(k+2); |
| 884 | + pugi::xml_node wfc_node_p1 = upf.child("PP_PSWFC").child(wstr.data()); |
| 885 | + |
| 886 | + auto v1 = vec_from_str<double>(wfc_node_p1.child_value(), 1.0); |
| 887 | + double occ1{0}; |
| 888 | + if (!wfc_node_p1.attribute("occupation").empty()) { |
| 889 | + occ1 = wfc_node_p1.attribute("occupation").as_double(); |
| 890 | + } |
| 891 | + occ += occ1; |
| 892 | + for (int ir = 0; ir < num_mt_points(); ir++) { |
| 893 | + v[ir] = 0.5 * v[ir] + 0.5 * v1[ir]; |
| 894 | + } |
| 895 | + k += 1; |
| 896 | + } |
| 897 | + } |
| 898 | + add_ps_atomic_wf(n, angular_momentum(l), v, occ); |
| 899 | + } |
| 900 | + } |
| 901 | +} |
| 902 | + |
| 903 | +void |
| 904 | +Atom_type::read_pseudo_paw(pugi::xml_node const& upf) |
| 905 | +{ |
| 906 | + is_paw_ = true; |
| 907 | + |
| 908 | + /* read core energy */ |
| 909 | + if (!upf.child("PP_PAW").attribute("core_energy").empty()) { |
| 910 | + paw_core_energy(0.5*upf.child("PP_PAW").attribute("core_energy").as_double()); |
| 911 | + } else { |
| 912 | + paw_core_energy(0); |
| 913 | + } |
| 914 | + |
| 915 | + /* cutoff index */ |
| 916 | + int cutoff_radius_index = upf.child("PP_NONLOCAL").child("PP_AUGMENTATION") |
| 917 | + .attribute("cutoff_r_index").as_int(); |
| 918 | + |
| 919 | + /* read core density and potential */ |
| 920 | + paw_ae_core_charge_density( |
| 921 | + vec_from_str<double>(upf.child("PP_PAW").child("PP_AE_NLCC").child_value(), 1.0)); |
| 922 | + |
| 923 | + /* read occupations */ |
| 924 | + paw_wf_occ( |
| 925 | + vec_from_str<double>(upf.child("PP_PAW").child("PP_OCCUPATIONS").child_value(), 1.0)); |
| 926 | + |
| 927 | + /* setups for reading AE and PS basis wave functions */ |
| 928 | + int num_wfc = num_beta_radial_functions(); |
| 929 | + |
| 930 | + /* read ae and ps wave functions */ |
| 931 | + for (int i = 0; i < num_wfc; i++) { |
| 932 | + /* read ae wave func */ |
| 933 | + std::string wstr = "PP_AEWFC."+std::to_string(i+1); |
| 934 | + pugi::xml_node wfc_node = upf.child("PP_FULL_WFC").child(wstr.data()); |
| 935 | + auto wfc = vec_from_str<double>(wfc_node.child_value(), 1.0); |
| 936 | + |
| 937 | + if ((int)wfc.size() > num_mt_points()) { |
| 938 | + std::stringstream s; |
| 939 | + s << "wrong size of ae_wfc functions for atom type " << symbol_ << " (label: " << label_ << ")" << std::endl |
| 940 | + << "size of ae_wfc radial functions in the file: " << wfc.size() << std::endl |
| 941 | + << "radial grid size: " << num_mt_points(); |
| 942 | + RTE_THROW(s); |
| 943 | + } |
| 944 | + |
| 945 | + add_ae_paw_wf(std::vector<double>(wfc.begin(), wfc.begin() + cutoff_radius_index)); |
| 946 | + |
| 947 | + wstr = "PP_PSWFC."+std::to_string(i+1); |
| 948 | + wfc_node = upf.child("PP_FULL_WFC").child(wstr.data()); |
| 949 | + wfc = vec_from_str<double>(wfc_node.child_value(), 1.0); |
| 950 | + |
| 951 | + if ((int)wfc.size() > num_mt_points()) { |
| 952 | + std::stringstream s; |
| 953 | + s << "wrong size of ps_wfc functions for atom type " << symbol_ << " (label: " << label_ << ")" << std::endl |
| 954 | + << "size of ps_wfc radial functions in the file: " << wfc.size() << std::endl |
| 955 | + << "radial grid size: " << num_mt_points(); |
| 956 | + RTE_THROW(s); |
| 957 | + } |
| 958 | + |
| 959 | + add_ps_paw_wf(std::vector<double>(wfc.begin(), wfc.begin() + cutoff_radius_index)); |
699 | 960 | } |
| 961 | +} |
| 962 | + |
| 963 | +void Atom_type::read_input(nlohmann::json const& parser){ |
700 | 964 |
|
701 | 965 | if (!parameters_.full_potential()) { |
702 | 966 | read_pseudo_uspp(parser); |
@@ -736,6 +1000,54 @@ Atom_type::read_input(std::string const& str__) |
736 | 1000 | free_atom_radial_grid_ = Radial_grid_ext<double>(static_cast<int>(fa_r.size()), fa_r.data()); |
737 | 1001 | /* read density */ |
738 | 1002 | free_atom_density_ = parser["free_atom"]["density"].get<std::vector<double>>(); |
| 1003 | + |
| 1004 | + if (!parser) { |
| 1005 | + return; |
| 1006 | + } |
| 1007 | + } |
| 1008 | +} |
| 1009 | + |
| 1010 | +void |
| 1011 | +Atom_type::read_input(pugi::xml_node const& upf){ |
| 1012 | + if (!parameters_.full_potential()) { |
| 1013 | + read_pseudo_uspp(upf); |
| 1014 | + |
| 1015 | + std::string pseudo_type = upf.child("PP_HEADER").attribute("pseudo_type").as_string(); |
| 1016 | + if (pseudo_type == "PAW") { |
| 1017 | + read_pseudo_paw(upf); |
| 1018 | + } |
| 1019 | + } else { |
| 1020 | + RTE_THROW("Full potential calculations require JSON potential files."); |
| 1021 | + } |
| 1022 | +} |
| 1023 | + |
| 1024 | +void |
| 1025 | +Atom_type::read_input(std::string const& str__) |
| 1026 | +{ |
| 1027 | + // Read from SIRIUS json potential file |
| 1028 | + if (is_json_file(str__)) { |
| 1029 | + auto parser = read_json_from_file_or_string(str__); |
| 1030 | + |
| 1031 | + if (parser.empty()) { |
| 1032 | + return; |
| 1033 | + } |
| 1034 | + |
| 1035 | + read_input(parser); |
| 1036 | + |
| 1037 | + // Read from standard UPF version 2 xml files |
| 1038 | + } else { |
| 1039 | + pugi::xml_document doc; |
| 1040 | + pugi::xml_parse_result parser = doc.load_file(str__.data()); |
| 1041 | + |
| 1042 | + if (!parser){ |
| 1043 | + return; |
| 1044 | + } |
| 1045 | + |
| 1046 | + pugi::xml_node upf = doc.child("UPF"); |
| 1047 | + if (upf.empty()){ |
| 1048 | + RTE_THROW("SIRIUS can only read UPF files with version >= 2. Use the upf_to_json tool."); |
| 1049 | + } |
| 1050 | + read_input(upf); |
739 | 1051 | } |
740 | 1052 |
|
741 | 1053 | /* it is already done in input.h; here the different constans are initialized */ |
|
0 commit comments