1#!/bin/bash
2
3# Script to create output for multiple electrodes
4# and/or multiple chemical potentials
5
6_this=$(basename $0)
7
8function error {
9    echo "ERROR: something went wrong... Please see the following output:"
10    while [ $# -gt 0 ]; do
11	echo "$1"
12	shift
13    done
14    exit 1
15}
16
17
18# We must require to be able to use the hash-able arrays
19# This allows us to reuse the same input twice more easily
20help=0
21def=2
22tbt=0
23# Options about what to print
24print_mu=0
25print_el=0
26print_c=0
27declare -a opts
28_N=0
29volt=0
30while [ $# -gt 0 ]; do
31    opt=$1
32    case $opt in
33	--*)
34	    opt=${1:1} ;;
35    esac
36    case $opt in
37	-def|-orig|-original)
38	    # Will produce output for standard TS
39	    def=2 ; shift
40	    ;;
41	-V|-bias)
42	    volt=$1 ; shift ; shift
43	    ;;
44	-1|-2|-3|-4|-5|-6|-7|-8|-9)
45	    # Will produce output for standard TS
46	    def=${opt:1} ; shift
47	    ;;
48	-only-el|-only-elec|-only-electrode)
49	    print_el=1 ; shift
50	    ;;
51	-only-mu|-only-chem|-only-chemical)
52	    print_mu=1 ; shift
53	    ;;
54	-only-c|-only-contour)
55	    print_c=1 ; shift
56	    ;;
57	-T|-tbtrans)
58	    # Prefix with TBT instead of TS
59	    tbt=1 ; shift
60	    ;;
61	-help|-h)
62	    # We need to print help
63	    help=1 ; shift
64	    ;;
65	-*)
66	    error "Unknown option: $opt"
67	    ;;
68	*)
69	    break
70    esac
71done
72
73# Correct what to print (if the user)
74# has not specified anything
75if [ $print_el -eq 0 ] && [ $print_mu -eq 0 ] && [ $print_c -eq 0 ]; then
76    print_el=1
77    print_mu=1
78    print_c=1
79fi
80
81if [ $help -eq 1 ]; then
82    fmt="      %20s : %s\n"
83    echo "Usage:"
84    echo "    $_this <options>"
85    echo ""
86    echo "For intrinsic transiesta runs call this:"
87    echo "    $_this -2 -V <bias>"
88    echo ""
89    echo "If one wishes to divide it in several files do:"
90    echo "    $_this -only-el > ELECS.fdf"
91    echo "    $_this -only-mu > CHEMPOTS.fdf"
92    echo "    $_this -only-c  > CONTOURS.fdf"
93    echo ""
94    echo "Only print out tbtrans related options:"
95    echo "    $_this -T|--tbtrans"
96    echo ""
97    echo "For specifying the contour energy levels you can use these options:"
98    printf "$fmt" "-Emin <val>" "band bottom energy in eV (-40. eV)"
99    printf "$fmt" "-dE <val>" "real-axis distance between integration points (0.01 eV)"
100    echo ""
101    echo "There are preset creations of 2,3 and 4 electrodes, call:"
102    echo "    $_this -[2-9]"
103    echo "to create the equivalent systems, note that these options can be accompanied by further setup."
104    echo ""
105    echo "Available options for the chemical potentials:"
106    echo "    -mu<idx>-X where X is one of the following:"
107    printf "$fmt" "mu <val>" "the chemical potential value in eV, or in fractions of V (V/2, |V|/3, etc.)"
108    printf "$fmt" "name <name>" "the name of the chemical potential (to be referenced by the electrodes)"
109    echo ""
110    echo "A shorthand notation for supplying the options is:"
111    echo "    -mu<idx> Y=<val>,Z=<val> where Y,Z is one of X above"
112    echo ""
113    echo ""
114    echo "Available options for the electrodes:"
115    echo "    -el<idx>-X where X is one of the following:"
116    printf "$fmt" "mu <name>" "the chemical potential name as given by -mu-name"
117    printf "$fmt" "name <name>" "the name of the electrode"
118    printf "$fmt" "tshs <file>" "the electrode TSHS-file"
119    printf "$fmt" "semi-inf <val>" "the semi-infinite direction [-+][a-c|a[1-3]]"
120    printf "$fmt" "pos <val>" "the first atom of the electrode in the structure"
121    printf "$fmt" "end-pos <val>" "the last atom of the electrode in the structure"
122    printf "$fmt" "used-atoms|ua <val>" "number of atoms used in the electrode (all)"
123    printf "$fmt" "bloch-a[1-3] <val>" "the Bloch expansion in the equivalent direction (1)"
124    printf "$fmt" "bulk <T|F>" "whether the electrode is a bulk electrode (true)"
125    printf "$fmt" "gf <file>" "name of the Greens function file (TSGF[el<idx>-name])"
126    echo ""
127    echo "A shorthand notation for supplying the options is:"
128    echo "    -el<idx> Y=<val>,Z=<val> where Y,Z is one of X above"
129    echo ""
130    echo "You can combine -2 with additional electrode options to easily generate different schemes"
131    echo "To generate 3 electrodes and 2 chemical potentials you can do this:"
132    echo "    $_this -2 -el3 name=Top,mu=Left,inf-dir=+a2,end-pos=-1"
133    exit 1
134fi
135
136prefix=TS
137# If we are doing tbtrans output
138# we should not print the contour information
139if [ $tbt -eq 1 ]; then
140    prefix=TBT
141    print_c=0
142fi
143
144# Add an option to the option array, enables easy creations
145function add_opt {
146    local rem=0
147    [ "x$1" == "x-r" ] && rem=1 && shift
148    local opt=$1 ; shift
149    local val=$1 ; shift
150    if [ $rem -eq 1 ]; then
151	rem_opt $opt
152    fi
153    # array indices are zero-based
154    local tmp=$(get_opt $opt 1)
155    [ ${#tmp} -gt 0 ] && return 0
156    opts+=($opt)
157    opts+=($val)
158    let _N++
159    let _N++
160}
161
162# Removes an option from the option array, enables customization of the options in-code
163function rem_opt {
164    local opt=
165    local i=
166    while [ $# -gt 0 ]; do
167	opt=$1 ; shift
168	i=0
169	while [ $i -le $_N ]; do
170            local val=${opts[$i]}
171            if [ "x$val" == "x$opt" ]; then
172                #echo "Removing ($val|$opt: ${opts[$i]}"
173                unset opts[$i]
174                let i++
175                #echo "Removing: ${opts[$i]}"
176                unset opts[$i]
177		break
178            fi
179            let i++
180        done
181    done
182    opts=( "${opts[@]}" )
183    _N=${#opts[@]}
184}
185
186
187# Lower-case function
188function lc { printf "%b" "$@" | tr '[A-Z]' '[a-z]' ; }
189
190
191function get_opt {
192    # Returns the option from the array input
193    # get_opt <opt-name (with ONE dash)> [number of arguments gobbled]
194    # If [...] is 0:
195    #   0) will return 0 or 1 whether or not the option exists
196    #   1-9) will return the consecutive [...] number of elements
197    local opt="$1" ; shift
198    local count=0
199    if [ $# -gt 0 ]; then
200	count=$1 ; shift
201    fi
202    local i=0 ; local j=0
203    local ret=""
204    while [ $i -le $_N ]; do
205	local oo=$(lc ${opts[$i]})
206	#echo "searching for: $opt in $oo" 1>&2
207	if [ "x$opt" == "x$oo" ]; then
208	    if [ $count -gt 0 ]; then
209		ret=""
210		for j in `seq 1 $count` ; do
211		    let i++
212		    ret="$ret ${opts[$i]}"
213		done
214	    else
215		ret=1
216	    fi
217	    break
218	fi
219	let i++
220    done
221    [ ${#ret} -eq 0 ] && [ $count -eq 0 ] && ret=0
222    # trim white-space
223    ret=${ret%% }
224    ret=${ret## }
225    printf "%b" "$ret"
226}
227
228# Expands the "short-hand" keywords to their full equivalents
229function expand_key {
230    local nm="$1" ; shift
231    local i=1
232    local reg_opt=
233    local opt=
234    local val=
235    while : ; do
236	reg_opt=$(get_opt -$nm$i 1)
237	# If the option does not exist, we simply return
238	[ ${#reg_opt} -eq 0 ] && [ $i -gt 6 ] && break
239	# Delete, so that we only keep the wanted options (not necessary, but)
240	rem_opt -$nm$i
241	reg_opt="${reg_opt//,/ }"
242	reg_opt="${reg_opt//;/ }"
243        # Loop over comma/semi-colon separated entries
244	for reg in $reg_opt ; do
245            # Add to the option list
246            # Retrive the option and value
247	    opt=${reg%=*}
248	    val=${reg#*=}
249	    add_opt -r "-$nm$i-$opt" "$val"
250	done
251	let i++
252    done
253}
254
255function reduce {
256    local -a tmp
257    local i=0
258    local j=0
259    while [ $j -le $_N ]; do
260	if [ ${#opts[$j]} -gt 0 ]; then
261	    tmp[$i]=${opts[$j]}
262	    let i++
263	fi
264	let j++
265    done
266    opts=( "${tmp[@]}" )
267    _N=$i
268}
269
270for i in `seq 1 $def` ; do
271    # The user has requested a default setting for some electrodes
272    # We add them to the option stack
273    add_opt "-mu$i-name" "mu-$i"
274    add_opt "-mu$i-mu" "<mu-mu$i>"
275    add_opt "-el$i-name" "el-$i"
276    add_opt "-el$i-mu" "mu-$i"
277    add_opt "-el$i-pos" "<input-value>"
278    add_opt "-el$i-semi-inf" "+a3"
279done
280
281# In case of only two electrodes we have
282# the particular case of the traditional transiesta code
283case $def in
284    1)
285	add_opt -r "-mu1-name" "single"
286	add_opt -r "-mu1-mu" "0."
287	add_opt -r "-el1-name" "single"
288	add_opt -r "-el1-mu" "single"
289	rem_opt -el1-pos -el1-end-pos -el1-semi-inf
290	add_opt "-el1-pos" "1"
291	add_opt "-el1-semi-inf" "-a3"
292	;;
293    2)
294	add_opt -r "-mu1-name" "Left"
295	add_opt -r "-mu1-mu" "V/2"
296	add_opt -r "-el1-name" "Left"
297	add_opt -r "-el1-mu" "Left"
298	rem_opt -el1-pos -el1-end-pos -el1-semi-inf
299	add_opt "-el1-pos" "1"
300	add_opt "-el1-semi-inf" "-a3"
301	add_opt -r "-mu2-name" "Right"
302	add_opt -r "-mu2-mu" "-V/2"
303	add_opt -r "-el2-name" "Right"
304	add_opt -r "-el2-mu" "Right"
305	rem_opt -el2-pos -el2-end-pos -el2-semi-inf
306	add_opt "-el2-end-pos" "-1"
307	add_opt "-el2-semi-inf" "+a3"
308	;;
309esac
310
311
312# Add the user options
313while [ $# -gt 0 ]; do
314    opt=$1 ; shift
315    case $opt in
316	--*)
317	    opt=${1:1}
318	    rem_opt $opt ;;
319	-el*|-mu*)
320	    rem_opt $opt ;;
321    esac
322    let _N++
323    opts[$_N]="$opt"
324done
325
326# Expand again after the user things
327expand_key mu
328expand_key el
329reduce
330
331
332function count {
333    local nm=$1 ; shift
334    local n=0
335    local i=
336    local oldn=-1
337    local opt=
338    local j=
339    while [ $oldn -ne $n ]; do
340	oldn=$n
341	i=$n
342	let i++
343	j=0
344	while [ $j -lt $_N ]; do
345	    opt=${opts[$j]}
346	    case $opt in
347		-${nm}${i}*)
348		    n=$i ;;
349	    esac
350	    let j++
351	done
352    done
353    printf "%b" "$n"
354}
355
356# Save the options
357old_opts=( "${opts[@]}" )
358i=0
359while [ $i -lt $_N ]; do
360    case ${opts[$i]} in
361	-el*)
362	    unset opts[$i]
363	    let i++
364	    unset opts[$i]
365	    ;;
366    esac
367    let i++
368done
369# Remove empty array elements
370reduce
371
372# Energy for the contour
373emin=$(get_opt -emin 1)
374[ ${#emin} -eq 0 ] && emin=-40.
375emin="$emin eV"
376de=$(get_opt -de 1)
377[ ${#de} -eq 0 ] && de=0.01
378
379
380
381# The chemical potentials should be denoted like this option:
382# -mu1 <options for the chemical potential in comma separated list>
383# Another way of supplying information regarding the chemical potentials
384#  -mu1-name <name>
385#  -mu1-mu   <the value of the chemical potential>
386_mus=$(count mu)
387# First we need to figure out the number of chemical potentials:
388# I don't suspect ANY user will go above 10 chemical potentials
389[ $_mus -eq 0 ] && \
390    error "You have zero chemical potentials." "Please supply at least one..."
391
392# Create the chemical potential array
393_mu_names=()
394j=0
395for i in `seq 1 $_mus` ; do
396    _mu_names+=( "$(get_opt -mu$i-name 1)" )
397    let j++
398done
399
400function mu_e_correct {
401    local mu=$1 ; shift
402    if [ "x${mu:0:1}" == "x-" ]; then
403	# we have a negative sign
404	if [ "x${mu:1:2}" != "x|V" ] && [ "x${mu:1:1}" != "xV" ]; then
405	    mu="$mu eV"
406	fi
407    else
408	if [ "x${mu:0:2}" != "x|V" ] && [ "x${mu:0:1}" != "xV" ]; then
409	    mu="$mu eV"
410	fi
411    fi
412    printf "%b" "$mu"
413}
414
415if [ $print_mu -eq 1 ]; then
416
417# Print out chemical potential block:
418echo "$prefix.Voltage $volt eV"
419echo "%block $prefix.ChemPots"
420for mu in ${_mu_names[@]} ; do
421    echo "  $mu"
422done
423echo "%endblock $prefix.ChemPots"
424echo ""
425
426
427function create_mu {
428    local mu=$1 ; shift
429    local name=$(get_opt -mu$mu-name 1)
430    if [ ${#name} -eq 0 ]; then
431	error "Chemical potential: $mu" "Has not received a name (-mu$mu-name)"
432    fi
433    local chem=$(get_opt -mu$mu-mu 1)
434    if [ ${#chem} -eq 0 ]; then
435	error "Chemical potential: $mu" "Has not received a chemical potential value (-mu$mu-mu)"
436    fi
437    chem=$(mu_e_correct $chem)
438    echo "%block $prefix.ChemPot.$name"
439    echo "  mu $chem"
440    if [ $tbt -eq 0 ]; then
441	echo "  contour.eq"
442	echo "    begin"
443	echo "      C-$name"
444	echo "      T-$name"
445	echo "    end"
446    fi
447    echo "%endblock $prefix.ChemPot.$name"
448}
449for i in `seq 1 $_mus` ; do
450    create_mu $i
451done
452fi
453
454# Create all the contours
455
456if [ $print_c -eq 1 ]; then
457
458echo ""
459echo "TS.Contours.Eq.Pole 2.5 eV"
460
461for i in `seq 1 $_mus` ; do
462    mu=$(get_opt -mu$i-name 1)
463    # Create the contours
464    echo "%block TS.Contour.C-$mu"
465    echo "  part circle"
466    e=$(get_opt -mu$i-mu 1)
467    e=$(mu_e_correct $e)
468    [ ${e:0:1} != "-" ] && e="+ $e"
469    echo "   from $emin $e to -10 kT $e"
470    echo "     points 25"
471    echo "      method g-legendre"
472    echo "       opt right"
473    echo "%endblock TS.Contour.C-$mu"
474
475    # Create the contours
476    echo "%block TS.Contour.T-$mu"
477    echo "  part tail"
478    echo "   from prev to inf"
479    echo "     points 10"
480    echo "      method g-fermi"
481    echo "%endblock TS.Contour.T-$mu"
482
483done
484
485echo ""
486echo "MSG: You may need to correct the TS.Contours.nEq for signs of bias" >&2
487echo "MSG: The energies must be in increasing order (you may use |V|/2 to designate absolute values)" >&2
488
489if [ $_mus -gt 1 ]; then
490    # Create the non-equilbrium contour
491    echo "%block TS.Contours.nEq"
492    for i in `seq 1 $_mus` ; do
493	[ $i -eq $_mus ] && continue
494	echo "  neq-$i"
495    done
496    echo "%endblock TS.Contours.nEq"
497fi
498
499# Create array of chemical potentials sorted
500mus=()
501j=1
502for i in `seq $_mus -1 1` ; do
503    tmp="$(get_opt -mu$i-mu 1)"
504    tmp=${tmp//\|V\|/V}
505    tmp=${tmp//V/\|V\|}
506    mus[$j]=$(mu_e_correct $tmp)
507    let j++
508done
509
510
511# Create the contours
512if [ $_mus -gt 2 ]; then
513    echo "MSG: You can do with a single contour line in the bias window" >&2
514    echo "MSG: Use the lowest bias to the highest bias." >&2
515    echo "MSG: Here we supply as many different parts as there are chemical potentials" >&2
516fi
517
518if [ $_mus -gt 1 ]; then
519
520    i=1
521    echo "%block TS.Contour.nEq.neq-$i"
522    echo "  part line"
523    j=$((i+1))
524    if [ $j -eq $_mus ]; then
525	echo "   from ${mus[$i]} - 5 kT to ${mus[$j]} + 5 kT"
526    else
527	echo "   from ${mus[$i]} - 5 kT to ${mus[$j]}"
528    fi
529    echo "     delta $de eV"
530    echo "      method mid-rule"
531    echo "%endblock TS.Contour.nEq.neq-$i"
532
533    # Sort all chemical potentials
534    for i in `seq 3 $((_mus))` ; do
535	# Create the contours
536	echo "%block TS.Contour.nEq.neq-$((i-1))"
537	echo "  part line"
538	if [ $i -eq $_mus ]; then
539	    echo "   from prev to ${mus[$i]} + 5 kT"
540	else
541	    echo "   from prev to ${mus[$i]}"
542	fi
543	echo "     delta $de eV"
544	echo "      method mid-rule"
545	echo "%endblock TS.Contour.nEq.neq-$((i-1))"
546    done
547fi
548
549fi
550
551
552
553# Recreate the old
554opts=( "${old_opts[@]}" )
555_N=${#opts[@]}
556# remove all mu
557i=0
558while [ $i -lt $_N ]; do
559    case ${opts[$i]} in
560	-mu*)
561	    unset opts[$i]
562	    let i++
563	    unset opts[$i] ;;
564    esac
565    let i++
566done
567# Remove empty things
568reduce
569
570
571# Now we will concentrate on the electrodes
572# First we need to figure out the number of electrode
573# I don't suspect ANY user will go above 10 electrodes
574_els=$(count el)
575[ $_els -eq 0 ] && \
576    error "You have zero electrodes." "Please supply at least one..."
577[ $_els -lt $_mus ] && \
578    error "You have fewer electrodes than chemical potentials." "Please correct your input..."
579
580
581if [ $print_el -eq 1 ]; then
582
583# Print out electrodes block:
584echo ""
585echo "%block $prefix.Elecs"
586for i in `seq 1 $_els` ; do
587    echo "  $(get_opt -el$i-name 1)"
588done
589echo "%endblock $prefix.Elecs"
590echo ""
591
592# Get whether or not we should print everything
593_all=$(get_opt -print-all)
594[ $_all -eq 0 ] && _all=$(get_opt -el-all)
595
596
597function create_el {
598    local el=$1 ; shift
599    local name=$(get_opt -el$el-name 1)
600    [ ${#name} -eq 0 ] && error "Electrode: $el" "Has not received a name (-el$el-name)"
601    local chem=$(get_opt -el$el-mu 1)
602    [ ${#chem} -eq 0 ] && error "Electrode: $el" "Has not received a chemical potential reference (-el$el-mu)"
603    # Currently we don't check for the existance of
604    # the chemical potential.
605    local found=0
606    local i=$_mus
607    let i--
608    for j in `seq 0 $i` ; do
609	if [ "x${_mu_names[$j]}" == "x$chem" ]; then
610	    found=1
611	fi
612    done
613    [ $found -ne 1 ] && error "Electrode: $el could not be associated with a matching chemical potential: $chem"
614    echo "%block $prefix.Elec.$name"
615    local tshs=$(get_opt -el$el-tshs 1)
616
617    if [ ${#tshs} -ne 0 ]; then
618	echo "  HS $tshs"
619    else
620	echo "  HS <input file>"
621    fi
622    echo "  chemical-potential $chem"
623    echo "  semi-inf-direction $(get_opt -el$el-semi-inf 1)"
624    local pos=$(get_opt -el$el-pos 1)
625    if [ ${#pos} -eq 0 ]; then
626	pos=$(get_opt -el$el-end-pos 1)
627	[ ${#pos} -ne 0 ] && pos="end $pos"
628    fi
629    [ ${#pos} -eq 0 ] && pos="<set value>"
630    echo "  electrode-position $pos"
631    # Now we can set all the other things (non-important)
632    function print_if {
633	local opt=
634	for opt in ${1//:/ } ; do
635	    local val=$(get_opt -el$el-$opt 1)
636	    if [ ${#val} -gt 0 ]; then
637		echo "  $2 $val"
638		break
639	    fi
640	done
641    }
642    print_if used-atoms:ua "used-atoms"
643    print_if bloch-a:bloch-a1 "bloch-a1"
644    print_if bloch-b:bloch-a2 "bloch-a2"
645    print_if bloch-c:bloch-a3 "bloch-a3"
646    print_if bulk "bulk"
647    print_if gf "GF"
648    echo "%endblock $prefix.Elec.$name"
649}
650for i in `seq 1 $_els` ; do
651    create_el $i
652done
653
654fi
655
656
657# Recreate the options
658opts=( "${old_opts[@]}" )
659_N=${#opts[@]}
660
661