Current implementation of `Base.parse(T::Type{<:Namelist}, content::AbstractString)`
Closed this issue · 2 comments
The current implementation of Base.parse(T::Type{<:Namelist}, content::AbstractString)
has this code at the end:
function Base.parse(T::Type{<:Namelist}, content::AbstractString)
...
final = merge(to_dict(T()), result)
return T((final[f] for f in fieldnames(T))...)
end
First, construct a T
instance and convert it to a Dict
, then merge it with the user-modified Dict
result
. And then supply a new T
with this final
Dict
. This uses the 2nd usage of Parameters.jl:
MM(;r=1000,a=error("no default for a")) = MM(r,a) # outer kw, so no type-paras are needed when calling
However, this is semantically equivalent to the following code:
function Base.parse(T::Type{<:Namelist}, content::AbstractString)
...
return T(T(); result...)
end
i.e., the 3rd usage of Parameters.jl
MM(m::MM; kws...) = reconstruct(mm,kws)
Or, equivalently, even simpler,
function Base.parse(T::Type{<:Namelist}, content::AbstractString)
...
return T(T(), result)
end
that is, the 4th usage of
MM(m::MM, di::Union{AbstractDict, Tuple{Symbol,Any}}) = reconstruct(mm, di)
since
function reconstruct(pp::T, di) where T
di = !isa(di, AbstractDict) ? Dict(di) : copy(di)
if pp isa AbstractDict
for (k,v) in di
!haskey(pp, k) && error("Field $k not in type $T")
pp[k] = v
end
return pp
else
# Also uses the order of `fieldnames`
ns = fieldnames(T)
args = []
for (i,n) in enumerate(ns)
push!(args, pop!(di, n, getfield(pp, n)))
end
length(di)!=0 && error("Fields $(keys(di)) not in type $T")
return pp isa NamedTuple ? T(Tuple(args)) : T(args...) # Just expand by the order mentioned
end
end
reconstruct(pp; kws...) = reconstruct(pp, kws)
The current implementation will cause the following error. If we have an input like
&control
calculation='scf',
restart_mode='from_scratch',
prefix='silicon'
pseudo_dir = '$PSEUDO_DIR/',
outdir='$TMP_DIR/'
/
&system
ibrav = 2, celldm(1) =10.20, nat= 2, ntyp= 1,
ecutwfc = 18.0
/
&electrons
mixing_beta = 0.7
conv_thr = 1.0d-8
/
ATOMIC_SPECIES
Si 28.086 Si.pz-vbc.UPF
ATOMIC_POSITIONS (alat)
Si 0.00 0.00 0.00
Si 0.25 0.25 0.25
K_POINTS (tpiba)
10
0.1250000 0.1250000 0.1250000 1.00
0.1250000 0.1250000 0.3750000 3.00
0.1250000 0.1250000 0.6250000 3.00
0.1250000 0.1250000 0.8750000 3.00
0.1250000 0.3750000 0.3750000 3.00
0.1250000 0.3750000 0.6250000 6.00
0.1250000 0.3750000 0.8750000 6.00
0.1250000 0.6250000 0.6250000 3.00
0.3750000 0.3750000 0.3750000 1.00
0.3750000 0.3750000 0.6250000 3.00
After parsing we get
julia> pw.system
QuantumESPRESSOBase.Namelists.PWscf.SystemNamelist
ibrav: Int64 2
celldm: Array{Union{Missing, Float64}}((1,))
A: Float64 0.0
B: Float64 0.0
C: Float64 0.0
cosAB: Float64 0.0
cosAC: Float64 0.0
cosBC: Float64 0.0
nat: Int64 2
ntyp: Int64 1
nbnd: Int64 0
tot_charge: Float64 0.0
starting_charge: Array{Union{Missing, Float64}}((0,))
tot_magnetization: Float64 -1.0
starting_magnetization: Array{Union{Missing, Float64}}((0,))
ecutwfc: Float64 18.0
ecutrho: Float64 0.0
ecutfock: Float64 0.0
nr1: Int64 0
nr2: Int64 0
nr3: Int64 0
nr1s: Int64 0
nr2s: Int64 0
nr3s: Int64 0
nosym: Bool false
nosym_evc: Bool false
noinv: Bool false
no_t_rev: Bool false
force_symmorphic: Bool false
use_all_frac: Bool false
occupations: String "fixed"
one_atom_occupations: Bool false
starting_spin_angle: Bool false
degauss: Float64 0.0
smearing: String "gaussian"
nspin: Int64 1
noncolin: Bool false
ecfixed: Float64 0.0
qcutz: Float64 0.0
q2sigma: Float64 0.1
input_dft: String "none"
exx_fraction: Float64 0.25
screening_parameter: Float64 0.106
exxdiv_treatment: String "gygi-baldereschi"
x_gamma_extrapolation: Bool true
ecutvcut: Float64 0.0
nqx1: Int64 1
nqx2: Int64 1
nqx3: Int64 1
localization_thr: Float64 0.0
lda_plus_u: Bool false
lda_plus_u_kind: Int64 0
Hubbard_U: Array{Union{Missing, Float64}}((0,))
Hubbard_J0: Array{Union{Missing, Float64}}((0,))
Hubbard_alpha: Array{Union{Missing, Float64}}((0,))
Hubbard_beta: Array{Union{Missing, Float64}}((0,))
Hubbard_J: Array{Union{Missing, Float64}}((0,))
starting_ns_eigenvalue: Float64 -1.0
U_projection_type: String "atomic"
edir: Int64 1
emaxpos: Float64 0.5
eopreg: Float64 0.1
eamp: Float64 0.001
angle1: Array{Union{Missing, Float64}}((0,))
angle2: Array{Union{Missing, Float64}}((0,))
constrained_magnetization: String "none"
fixed_magnetization: Array{Union{Missing, Float64}}((3,))
lambda: Float64 1.0
report: Int64 100
lspinorb: Bool false
assume_isolated: String "none"
esm_bc: String "pbc"
esm_w: Float64 0.0
esm_efield: Float64 0.0
esm_nfit: Int64 4
fcp_mu: Float64 0.0
vdw_corr: String "none"
london: Bool false
london_s6: Float64 0.75
london_c6: Array{Union{Missing, Float64}}((0,))
london_rvdw: Array{Union{Missing, Float64}}((0,))
london_rcut: Float64 200.0
ts_vdw_econv_thr: Float64 1.0e-6
ts_vdw_isolated: Bool false
xdm: Bool false
xdm_a1: Float64 0.6836
xdm_a2: Float64 1.5045
space_group: Int64 0
uniqueb: Bool false
origin_choice: Int64 1
rhombohedral: Bool true
zgate: Float64 0.5
relaxz: Bool false
block: Bool false
block_1: Float64 0.45
block_2: Float64 0.55
block_height: Float64 0.1
As can be seen, ntyp = 1
. But angle2
, etc., are still vectors of 0
elements (the default value of a SystemNamelist
). That means the length checking will fail. The parameter angle2
should have length of ntyp
. This is a big problem.
This bug is now fixed by commit "858dca36dea8153028ee741874b304b506da1292". A minor change but a powerful one. I follow the instruction on this answer.
Parsing the above-mentioned input
&control
calculation='scf',
restart_mode='from_scratch',
prefix='silicon'
pseudo_dir = '$PSEUDO_DIR/',
outdir='$TMP_DIR/'
/
&system
ibrav = 2, celldm(1) =10.20, nat= 2, ntyp= 1,
ecutwfc = 18.0
/
&electrons
mixing_beta = 0.7
conv_thr = 1.0d-8
/
ATOMIC_SPECIES
Si 28.086 Si.pz-vbc.UPF
ATOMIC_POSITIONS (alat)
Si 0.00 0.00 0.00
Si 0.25 0.25 0.25
K_POINTS (tpiba)
10
0.1250000 0.1250000 0.1250000 1.00
0.1250000 0.1250000 0.3750000 3.00
0.1250000 0.1250000 0.6250000 3.00
0.1250000 0.1250000 0.8750000 3.00
0.1250000 0.3750000 0.3750000 3.00
0.1250000 0.3750000 0.6250000 6.00
0.1250000 0.3750000 0.8750000 6.00
0.1250000 0.6250000 0.6250000 3.00
0.3750000 0.3750000 0.3750000 1.00
0.3750000 0.3750000 0.6250000 3.00
will result in
julia> parse(QuantumESPRESSOBase.Namelists.PWscf.SystemNamelist, str)
QuantumESPRESSOBase.Namelists.PWscf.SystemNamelist
ibrav: Int64 2
celldm: Array{Union{Nothing, Float64}}((1,))
A: Float64 0.0
B: Float64 0.0
C: Float64 0.0
cosAB: Float64 0.0
cosAC: Float64 0.0
cosBC: Float64 0.0
nat: Int64 2
ntyp: Int64 1
nbnd: Int64 0
tot_charge: Float64 0.0
starting_charge: Array{Union{Nothing, Float64}}((1,))
tot_magnetization: Float64 -1.0
starting_magnetization: Array{Union{Nothing, Float64}}((1,))
ecutwfc: Float64 18.0
ecutrho: Float64 0.0
ecutfock: Float64 0.0
nr1: Int64 0
nr2: Int64 0
nr3: Int64 0
nr1s: Int64 0
nr2s: Int64 0
nr3s: Int64 0
nosym: Bool false
nosym_evc: Bool false
noinv: Bool false
no_t_rev: Bool false
force_symmorphic: Bool false
use_all_frac: Bool false
occupations: String "fixed"
one_atom_occupations: Bool false
starting_spin_angle: Bool false
degauss: Float64 0.0
smearing: String "gaussian"
nspin: Int64 1
noncolin: Bool false
ecfixed: Float64 0.0
qcutz: Float64 0.0
q2sigma: Float64 0.1
input_dft: String "none"
exx_fraction: Float64 0.25
screening_parameter: Float64 0.106
exxdiv_treatment: String "gygi-baldereschi"
x_gamma_extrapolation: Bool true
ecutvcut: Float64 0.0
nqx1: Int64 1
nqx2: Int64 1
nqx3: Int64 1
localization_thr: Float64 0.0
lda_plus_u: Bool false
lda_plus_u_kind: Int64 0
Hubbard_U: Array{Union{Nothing, Float64}}((1,))
Hubbard_J0: Array{Union{Nothing, Float64}}((1,))
Hubbard_alpha: Array{Union{Nothing, Float64}}((1,))
Hubbard_beta: Array{Union{Nothing, Float64}}((1,))
Hubbard_J: Array{Union{Nothing, Float64}}((1,))
starting_ns_eigenvalue: Float64 -1.0
U_projection_type: String "atomic"
edir: Int64 1
emaxpos: Float64 0.5
eopreg: Float64 0.1
eamp: Float64 0.001
angle1: Array{Union{Nothing, Float64}}((1,))
angle2: Array{Union{Nothing, Float64}}((1,))
constrained_magnetization: String "none"
fixed_magnetization: Array{Union{Nothing, Float64}}((3,))
lambda: Float64 1.0
report: Int64 100
lspinorb: Bool false
assume_isolated: String "none"
esm_bc: String "pbc"
esm_w: Float64 0.0
esm_efield: Float64 0.0
esm_nfit: Int64 4
fcp_mu: Float64 0.0
vdw_corr: String "none"
london: Bool false
london_s6: Float64 0.75
london_c6: Array{Union{Nothing, Float64}}((1,))
london_rvdw: Array{Union{Nothing, Float64}}((1,))
london_rcut: Float64 200.0
ts_vdw_econv_thr: Float64 1.0e-6
ts_vdw_isolated: Bool false
xdm: Bool false
xdm_a1: Float64 0.6836
xdm_a2: Float64 1.5045
space_group: Int64 0
uniqueb: Bool false
origin_choice: Int64 1
rhombohedral: Bool true
zgate: Float64 0.5
relaxz: Bool false
block: Bool false
block_1: Float64 0.45
block_2: Float64 0.55
block_height: Float64 0.
See the comparison (red: before change, green: after change):
The Nothing
, Missing
difference was due to another change.