From 11f24f0556fb770c58d6b6f73b672a43d35f9fa6 Mon Sep 17 00:00:00 2001 From: Simon Pintarelli Date: Tue, 16 Jul 2019 17:38:15 +0200 Subject: [PATCH] upf2json: change signature in v1 to read from string Add `parse_upf1_from_string` (upf2 was already there). Change wrapper function in `upf_to_json` to use the converters taking a string as input. Minimal changes in upf1_to_json.py: changed parse_xxx to take upf as a string and then use io.StringIO to pretend it is a file. --- apps/upf/upf1_to_json.py | 188 +++++++++++++++++++-------------------- apps/upf/upf_to_json.py | 28 +++--- 2 files changed, 109 insertions(+), 107 deletions(-) diff --git a/apps/upf/upf1_to_json.py b/apps/upf/upf1_to_json.py index aeb9b4cd2..88717b59e 100644 --- a/apps/upf/upf1_to_json.py +++ b/apps/upf/upf1_to_json.py @@ -1,25 +1,26 @@ # Copyright (c) 2013 Anton Kozhevnikov, Thomas Schulthess # All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import json import sys import re +import io def read_until(fin, tag): while True: @@ -28,7 +29,7 @@ def read_until(fin, tag): print ("Unexpected end of file") sys.exit(-1) if tag in line: return - + def read_mesh_data(in_file, npoints): out_data = [] while True: @@ -37,25 +38,23 @@ def read_mesh_data(in_file, npoints): if len(out_data) == npoints: break return out_data -def parse_header(upf_dict, fname): +def parse_header(upf_dict, upf_str): #print "parsing header" upf_dict["header"] = {} - - upf = open(fname, "r") - + upf = io.StringIO(upf_str) read_until(upf, "") s = upf.readline().split() #upf_dict["header"]["version"] = int(s[0]); - + s = upf.readline().split() upf_dict['header']['element'] = s[0].strip() - + s = upf.readline().split() upf_dict['header']['pseudo_type'] = s[0] - + s = upf.readline().split() upf_dict['header']['core_correction'] = (s[0][0] == 'T' or s[0][0] == 't') or 0 @@ -64,20 +63,20 @@ def parse_header(upf_dict, fname): s = upf.readline().split() upf_dict['header']['z_valence'] = float(s[0]) - + s = upf.readline().split() #upf_dict["header"]["etotps"] = float(s[0]) - + s = upf.readline().split() #upf_dict["header"]["ecutwfc"] = float(s[0]) #upf_dict["header"]["ecutrho"] = float(s[1]) s = upf.readline().split() upf_dict['header']['l_max'] = int(s[0]) - + s = upf.readline().split() upf_dict['header']['mesh_size'] = int(s[0]) - + s = upf.readline().split() upf_dict["header"]["number_of_wfc"] = int(s[0]) upf_dict['header']['number_of_proj'] = int(s[1]) @@ -91,33 +90,32 @@ def parse_header(upf_dict, fname): # upf_dict["header"]["wavefunctions"][i]["els"] = s[0] # upf_dict["header"]["wavefunctions"][i]["lchi"] = int(s[1]) # upf_dict["header"]["wavefunctions"][i]["oc"] = float(s[2]) - + upf.close(); -# +# # QE subroutine read_pseudo_mesh # -def parse_mesh(upf_dict, fname): - - #print "parsing mesh" +def parse_mesh(upf_dict, upf_str): - upf = open(fname, "r") + #print "parsing mesh" + upf = io.StringIO(upf_str) read_until(upf, "") - # ================================================================= - # call scan_begin (iunps, "R", .false.) + # ================================================================= + # call scan_begin (iunps, "R", .false.) # read (iunps, *, err = 100, end = 100) (upf%r(ir), ir=1,upf%mesh ) - # call scan_end (iunps, "R") + # call scan_end (iunps, "R") # ================================================================= upf_dict['radial_grid'] = read_mesh_data(upf, upf_dict['header']['mesh_size']) read_until(upf, "") # =================================================================== - # call scan_begin (iunps, "RAB", .false.) + # call scan_begin (iunps, "RAB", .false.) # read (iunps, *, err = 101, end = 101) (upf%rab(ir), ir=1,upf%mesh ) - # call scan_end (iunps, "RAB") + # call scan_end (iunps, "RAB") # =================================================================== #upf_dict["mesh"]["rab"] = read_mesh_data(upf, upf_dict["header"]["nmesh"]) @@ -126,12 +124,11 @@ def parse_mesh(upf_dict, fname): # # QE subroutine read_pseudo_nlcc # -def parse_nlcc(upf_dict, fname): +def parse_nlcc(upf_dict, upf_str): #print "parsing nlcc" - - upf = open(fname, "r") + upf = io.StringIO(upf_str) read_until(upf, "") # ======================================================================= @@ -145,13 +142,12 @@ def parse_nlcc(upf_dict, fname): # # QE subroutine read_pseudo_local # -def parse_local(upf_dict, fname): +def parse_local(upf_dict, upf_str): #print "parsing local" upf_dict['local_potential'] = [] - - upf = open(fname, "r") + upf = io.StringIO(upf_str) read_until(upf, "") @@ -165,31 +161,30 @@ def parse_local(upf_dict, fname): upf.close() # -# QE subroutine read_pseudo_nl +# QE subroutine read_pseudo_nl # -def parse_non_local(upf_dict, fname): +def parse_non_local(upf_dict, upf_str): #print "parsing non-local" upf_dict['beta_projectors'] = [] upf_dict['D_ion'] = [] - - upf = open(fname, "r") + upf = io.StringIO(upf_str) read_until(upf, "") - # ====================================================================== - # do nb = 1, upf%nbeta - # call scan_begin (iunps, "BETA", .false.) + # ====================================================================== + # do nb = 1, upf%nbeta + # call scan_begin (iunps, "BETA", .false.) # read (iunps, *, err = 100, end = 100) idum, upf%lll(nb), dummy - # read (iunps, *, err = 100, end = 100) ikk + # read (iunps, *, err = 100, end = 100) ikk # upf%kbeta(nb) = ikk - # upf%kkbeta = MAX ( upf%kkbeta, upf%kbeta(nb) ) + # upf%kkbeta = MAX ( upf%kkbeta, upf%kbeta(nb) ) # read (iunps, *, err = 100, end = 100) (upf%beta(ir,nb), ir=1,ikk) - # + # # read (iunps, *, err=200,iostat=ios) upf%rcut(nb), upf%rcutus(nb) # read (iunps, *, err=200,iostat=ios) upf%els_beta(nb) - # call scan_end (iunps, "BETA") + # call scan_end (iunps, "BETA") # 200 continue # enddo # ====================================================================== @@ -208,7 +203,7 @@ def parse_non_local(upf_dict, fname): upf_dict['beta_projectors'][i]['cutoff_radius'] = 0.0 upf_dict['beta_projectors'][i]['ultrasoft_cutoff_radius'] = 0.0 - + #line = upf.readline() #if not "" in line: #s = line.split() @@ -218,13 +213,13 @@ def parse_non_local(upf_dict, fname): #if not "" in line: upf_dict['beta_projectors'][i]['els_beta'] = float(s[0]) # ================================================================ - # call scan_begin (iunps, "DIJ", .false.) - # read (iunps, *, err = 101, end = 101) nd, dummy + # call scan_begin (iunps, "DIJ", .false.) + # read (iunps, *, err = 101, end = 101) nd, dummy # do icon = 1, nd # read (iunps, *, err = 101, end = 101) nb, mb, upf%dion(nb,mb) - # upf%dion (mb,nb) = upf%dion (nb,mb) + # upf%dion (mb,nb) = upf%dion (nb,mb) # enddo - # call scan_end (iunps, "DIJ") + # call scan_end (iunps, "DIJ") # ================================================================ nb = upf_dict['header']['number_of_proj'] dij = [0 for i in range(nb * nb)] @@ -239,13 +234,13 @@ def parse_non_local(upf_dict, fname): dij[j * nb + i] = float(s[2]) / 2 # convert to Hartree upf_dict['D_ion'] = dij - + if upf_dict['header']['pseudo_type'] != "US": return upf_dict['augmentation'] = [] - # ============================================= - # call scan_begin (iunps, "QIJ", .false.) + # ============================================= + # call scan_begin (iunps, "QIJ", .false.) # read (iunps, *, err = 102, end = 102) upf%nqf # upf%nqlc = 2 * upf%lmax + 1 # ============================================= @@ -256,9 +251,9 @@ def parse_non_local(upf_dict, fname): # ======================================================================= # if ( upf%nqf /= 0) then - # call scan_begin (iunps, "RINNER", .false.) + # call scan_begin (iunps, "RINNER", .false.) # read (iunps,*,err=103,end=103) ( idum, upf%rinner(i), i=1,upf%nqlc ) - # call scan_end (iunps, "RINNER") + # call scan_end (iunps, "RINNER") # end if # ======================================================================= if num_q_coef != 0: @@ -268,8 +263,8 @@ def parse_non_local(upf_dict, fname): s = upf.readline().split() R_inner.append(float(s[1])) read_until(upf, "") - - # ================================================================================== + + # ================================================================================== # do nb = 1, upf%nbeta # do mb = nb, upf%nbeta # read (iunps,*,err=102,end=102) idum, idum, ldum, dummy @@ -279,7 +274,7 @@ def parse_non_local(upf_dict, fname): # end if # read (iunps,*,err=104,end=104) upf%qqq(nb,mb), dummy # ! "Q_int" - # upf%qqq(mb,nb) = upf%qqq(nb,mb) + # upf%qqq(mb,nb) = upf%qqq(nb,mb) # ! ijv is the combined (nb,mb) index # ijv = mb * (mb-1) / 2 + nb # IF (upf%q_with_l .or. upf%tpawp) THEN @@ -293,7 +288,7 @@ def parse_non_local(upf_dict, fname): # read (iunps, *, err=105, end=105) (upf%qfunc(n,ijv), n=1,upf%mesh) # ENDIF # ================================================================================== - + nb = upf_dict['header']['number_of_proj'] l_max = upf_dict['header']['l_max'] @@ -301,24 +296,24 @@ def parse_non_local(upf_dict, fname): li = upf_dict['beta_projectors'][i]['angular_momentum'] for j in range(i, nb): lj = upf_dict['beta_projectors'][j]['angular_momentum'] - + s = upf.readline().split() if int(s[2]) != lj: print("inconsistent angular momentum") sys.exit(-1) - if int(s[0]) != i + 1 or int(s[1]) != j + 1: + if int(s[0]) != i + 1 or int(s[1]) != j + 1: print("inconsistent ij indices") sys.exit(-1) - + s = upf.readline().split() qij = read_mesh_data(upf, upf_dict['header']['mesh_size']) - + # ====================================================================== # if ( upf%nqf > 0 ) then - # call scan_begin (iunps, "QFCOEF", .false.) + # call scan_begin (iunps, "QFCOEF", .false.) # read (iunps,*,err=106,end=106) & # ( ( upf%qfcoef(i,lp,nb,mb), i=1,upf%nqf ), lp=1,upf%nqlc ) # do i = 1, upf%nqf @@ -326,7 +321,7 @@ def parse_non_local(upf_dict, fname): # upf%qfcoef(i,lp,mb,nb) = upf%qfcoef(i,lp,nb,mb) # end do # end do - # call scan_end (iunps, "QFCOEF") + # call scan_end (iunps, "QFCOEF") # end if #======================================================================= if num_q_coef > 0: @@ -335,7 +330,7 @@ def parse_non_local(upf_dict, fname): q_coefs = read_mesh_data(upf, num_q_coef * (2 * l_max + 1)) read_until(upf, "") - + if num_q_coef > 0: # constuct Qij(r) for each l for l in range(abs(li-lj), li+lj+1): @@ -357,28 +352,27 @@ def parse_non_local(upf_dict, fname): qij_dict['j'] = j qij_dict['angular_momentum'] = l upf_dict['augmentation'].append(qij_dict) - - + + upf.close() # # QE subroutine read_pseudo_pswfc # -def parse_pswfc(upf_dict, fname): - +def parse_pswfc(upf_dict, upf_str): + #print "parsing wfc" upf_dict['atomic_wave_functions'] = [] - upf = open(fname, "r") - + upf = io.StringIO(upf_str) read_until(upf, "") # ======================================================================= # ALLOCATE( upf%chi( upf%mesh, MAX( upf%nwfc, 1 ) ) ) # upf%chi = 0.0_DP - # do nb = 1, upf%nwfc + # do nb = 1, upf%nwfc # read (iunps, *, err=100, end=100) dummy !Wavefunction labels # read (iunps, *, err=100, end=100) ( upf%chi(ir,nb), ir=1,upf%mesh ) # enddo @@ -397,12 +391,10 @@ def parse_pswfc(upf_dict, fname): # # QE subroutine read_pseudo_rhoatom # -def parse_rhoatom(upf_dict, fname): +def parse_rhoatom(upf_dict, upf_str): #print "parsing rhoatm" - - upf = open(fname, "r") - + upf = io.StringIO(upf_str) read_until(upf, "") # ================================================================ @@ -413,17 +405,17 @@ def parse_rhoatom(upf_dict, fname): upf.close() - -def parse_upf1_from_file(upf1_fname): + +def parse_upf1_from_string(upf1_str): upf_dict = {} - parse_header(upf_dict, upf1_fname) - parse_mesh(upf_dict, upf1_fname) - if upf_dict['header']['core_correction'] == 1: parse_nlcc(upf_dict, upf1_fname) - parse_local(upf_dict, upf1_fname) - parse_non_local(upf_dict, upf1_fname) - parse_pswfc(upf_dict, upf1_fname) - parse_rhoatom(upf_dict, upf1_fname) + parse_header(upf_dict, upf1_str) + parse_mesh(upf_dict, upf1_str) + if upf_dict['header']['core_correction'] == 1: parse_nlcc(upf_dict, upf1_str) + parse_local(upf_dict, upf1_str) + parse_non_local(upf_dict, upf1_str) + parse_pswfc(upf_dict, upf1_str) + parse_rhoatom(upf_dict, upf1_str) pp_dict = {} pp_dict['pseudo_potential'] = upf_dict @@ -431,13 +423,15 @@ def parse_upf1_from_file(upf1_fname): return pp_dict def main(): - - pp_dict = parse_upf1_from_file(sys.argv[1]) + + with open(sys.argv[1], 'r') as fh: + upf = fh.read() + pp_dict = parse_upf1_from_string(upf) fout = open(sys.argv[1] + ".json", "w") - # Match comma, space, newline and an arbitrary number of spaces ',\s\n\s*' with the - # following conditions: a digit before (?<=[0-9]) and a minus or a digit after (?=[-|0-9]). + # Match comma, space, newline and an arbitrary number of spaces ',\s\n\s*' with the + # following conditions: a digit before (?<=[0-9]) and a minus or a digit after (?=[-|0-9]). # Replace found sequence with comma and space. fout.write(re.sub(r"(?<=[0-9]),\s\n\s*(?=[-|0-9])", r", ", json.dumps(pp_dict, indent=2))) fout.close() diff --git a/apps/upf/upf_to_json.py b/apps/upf/upf_to_json.py index f7c8cb3f9..446806824 100644 --- a/apps/upf/upf_to_json.py +++ b/apps/upf/upf_to_json.py @@ -1,29 +1,37 @@ import json import sys import re -import upf1_to_json -import upf2_to_json +import os +from upf1_to_json import parse_upf1_from_string +from upf2_to_json import parse_upf2_from_string -def get_upf_version(file_name): - with open(file_name) as inp: - line = inp.readline() +def get_upf_version(upf): + line = upf.split('\n')[0] if "" in line: return 1 elif "UPF version" in line: return 2 return 0 -def parse_upf_from_file(file_name): - version = get_upf_version(file_name) +def parse_upf_from_string(upf_str): + version = get_upf_version(upf_str) if version == 0: return None if version == 1: - return upf1_to_json.parse_upf1_from_file(file_name) + return parse_upf1_from_string(upf_str) if version == 2: - return upf2_to_json.parse_upf2_from_file(file_name) + return parse_upf2_from_string(upf_str) def main(): - pp_dict = parse_upf_from_file(sys.argv[1]) + + fname = sys.argv[1] + if not os.path.exists(fname): + raise FileNotFoundError('invalid path for UPF file') + + with open(sys.argv[1], 'r') as fh: + upf_str = fh.read() + + pp_dict = parse_upf_from_string(upf_str) element = pp_dict['pseudo_potential']['header']['element'] pp_dict['pseudo_potential']['header']['original_upf_file'] = sys.argv[1]