@@ -239,6 +239,100 @@ function read_k_points!(lines::AbstractVector; name::AbstractString="k_points")
239239 return name => card
240240end
241241
242+ """
243+ $(SIGNATURES)
244+
245+ Count how many valid lines from istart to iend in lines inclusive.
246+
247+ # Examples
248+ ```jldoctest; setup = :(using QuantumEspressoIO: num_valid_lines)
249+ lines = [
250+ "HUBBARD atomic",
251+ "! a comment line",
252+ "! another comment line",
253+ "U Ni-3d 5.77",
254+ "V Ni-3d O-2p 1 12 3.5",
255+ "ALPHA Ni-3d 0.05",
256+ "J0 Ni-3d 0.05",
257+ "following",
258+ ]
259+ nlines = valid_hubbard_lines(lines, 1, 8)
260+ println(nlines)
261+ # output
262+ 4
263+ """
264+ function valid_hubbard_lines (lines:: AbstractVector , istart:: Integer , iend:: Integer )
265+ i = istart
266+ num_lines = iend - istart + 1
267+ hubbard_types = [" U" , " ALPHA" , " J0" , " J" , " B" , " E2" , " E3" , " V" ]
268+ for line in lines[istart: iend]
269+ line = remove_comment (line)
270+ # valid lines should start with hubbard symbol and end with value
271+ if isempty (line) || ! (endswith (line, r" \d +$" ) && any ([startswith (line, t) for t in hubbard_types]))
272+ num_lines -= 1
273+ end
274+ end
275+ return num_lines
276+ end
277+
278+ """
279+ $(SIGNATURES)
280+
281+ Parse the `hubbard` card of `pw.x` input.
282+
283+ # Arguments
284+ - `lines::AbstractVector`: The lines of the input file.
285+ - `n_species::Integer`: The number of species in the input file.
286+
287+ # Returns
288+ - A `Pair` of card name to card content. The card option is stored under
289+ the `:option` key in the card content.
290+
291+ # Examples
292+ ```jldoctest; setup = :(using QuantumEspressoIO: read_hubbard!)
293+ lines = [
294+ "HUBBARD atomic",
295+ "! a comment line",
296+ "! another comment line",
297+ "U Ni-3d 5.77",
298+ "U Ni1-3d 5.77",
299+ "V Ni-3d O-2p 1 12 3.5",
300+ "following lines",
301+ ]
302+ card = read_hubbard!(lines)
303+ println(card)
304+ println(lines)
305+ # output
306+ :hubbard => OrderedCollections.OrderedDict{Symbol, Any}(:option => "atomic", :types => ["U", "U", "V"], :manifolds => ["Ni-3d", "Ni1-3d", "Ni-3d O-2p 1 12"], :values => [5.77, 5.77, 3.5])
307+ ["following lines"]
308+ ```
309+ """
310+ function read_hubbard! (lines:: AbstractVector )
311+ name = " hubbard"
312+ icard = find_card (lines, name)
313+ # no hubbard card found
314+ isnothing (icard) && return nothing
315+
316+ # hubbard projector must be specified
317+ # https://gitlab.com/QEF/q-e/-/blob/develop/Doc/Hubbard_input.tex?ref_type=heads
318+ # FIXME in what degree should we consider the integrity of the input?
319+ option = parse_card_option (lines[icard])
320+ if isempty (option)
321+ @warn " Hubbard project is not specified!"
322+ end
323+
324+ # number of hubbard lines is not known a priori
325+ iend = end_of_card (lines, icard)
326+ nline = valid_hubbard_lines (lines, icard, iend)
327+ content = parse_card! (lines, name, nline)
328+ card = OrderedDict {Symbol,Any} ()
329+ card[:option ] = content[1 ]
330+ card[:types ] = map (x -> String (split (x)[1 ]), content[2 ])
331+ card[:manifolds ] = map (x -> join (split (x)[2 : (end - 1 )], " " ), content[2 ])
332+ card[:values ] = map (x -> parse_float (split (x)[end ]), content[2 ])
333+ return Symbol (name) => card
334+ end
335+
242336"""
243337 $(SIGNATURES)
244338
@@ -317,6 +411,17 @@ function read_pw_in(io::Union{IO,AbstractString})
317411 return params
318412end
319413
414+ """
415+ $(SIGNATURES)
416+
417+ Read HUBBARD.dat from hp.x calculations.
418+ """
419+ function read_hubbard_dat (io:: Union{IO, AbstractString} )
420+ _, cards = read_namelists (io; all_lines= true )
421+ card = read_hubbard! (cards)
422+ return card. second
423+ end
424+
320425"""
321426 $(SIGNATURES)
322427
@@ -445,7 +550,9 @@ function write_k_points(io::IO, card::AbstractDict; name::AbstractString="K_POIN
445550 option = get (card, " option" , " " )
446551 loption = lowercase (option)
447552
448- valid_options_list = [" tpiba" , " crystal" , " tpiba_b" , " crystal_b" , " tpiba_c" , " crystal_c" ]
553+ valid_options_list = [
554+ " tpiba" , " crystal" , " tpiba_b" , " crystal_b" , " tpiba_c" , " crystal_c"
555+ ]
449556 valid_options_auto = [" automatic" ]
450557 valid_options_gamma = [" gamma" ]
451558 valid_options = vcat (valid_options_list, valid_options_auto, valid_options_gamma)
@@ -472,6 +579,48 @@ function write_k_points(io::IO, card::AbstractDict; name::AbstractString="K_POIN
472579 end
473580end
474581
582+ """
583+ $(SIGNATURES)
584+
585+ Write the `hubbard` card of `pw.x`.
586+
587+ # Examples
588+ ```jldoctest; setup = :(using QuantumEspressoIO: write_hubbard)
589+ inputs = Dict(
590+ :option => "atomic",
591+ :types => ["U", "U"],
592+ :values => [5.0, 5.0],
593+ :manifolds => ["Ni-3d", "Ni1-3d"],
594+ )
595+ write_hubbard(stdout, inputs)
596+ # output
597+ HUBBARD atomic
598+ U Ni-3d 5.0
599+ U Ni1-3d 5.0
600+ ```
601+ """
602+ function write_hubbard (io:: IO , card:: AbstractDict )
603+ option = get (card, :option , " " )
604+ # FIXME general question: how do we check for valid input?
605+ isempty (option) && @error " Hubbard projector is not specified."
606+ projector_types = Set ([" atomic" , " ortho-atomic" , " norm-atomic" , " wf" , " pseudo" ])
607+ if option in projector_types
608+ println (io, " HUBBARD $option " )
609+ else
610+ @error " Hubbard projector $option is not valid."
611+ end
612+
613+ valid_types = Set ([" U" , " J0" , " J" , " B" , " E2" , " E3" , " V" ])
614+ for t in card[:types ]
615+ if ! in (uppercase (t), valid_types)
616+ @error " Hubbard type $t is not valid"
617+ end
618+ end
619+ for (t, m, v) in zip (card[:types ], card[:manifolds ], card[:values ])
620+ println (io, " $(uppercase (t)) $m $v " )
621+ end
622+ end
623+
475624"""
476625 $(SIGNATURES)
477626
0 commit comments