#!/bin/bash
dohelp=0
cutoff="0"
cmdsuffix=""
volrelaxcommand="runstruct_vasp -w vaspvol.wrap"
relaxcommand="runstruct_vasp -w vasp.wrap"
chaincommand="runstruct_vasp -w vaspneb.wrap"
staticcommand="runstruct_vasp -w vaspstatic.wrap"
infdetcommand="runstruct_vasp -p -w vaspid.wrap"
doid=0
idopt="-d"
idf="0.5"
idja="0.0"
idjc="0.0"
doneb=0
doextract=0
nimage=6
dovib=0
makevaspfiles=0
contif=0

if [[ $1 == "" || $1 == "-h" ]]
then
    cat - <<EOF
This command implements the "inflection-detection" method introduced in
A. van de Walle, Q. Hong, S. Kadkhodaei and R. Sun, "The free energy of mechanically unstable phases"
Nat. Com. 6, 7559 (2015) doi:10.1038/ncomms8559 .
and
A. van de Walle and S. Kadkhodaei and R. Sun and Q.-J. Hong, "Epicycle method for elasticity limit calculations",
Phys. Rev. B 95 144113 (2017) doi:10.1103/PhysRevB.95.144113 .

It calculates the energy of a structure that is potentially mechanically unstable.
In a nutshell: the method finds either a local minimum (for a mechanically stable phase)
or the inflection point on a path joining the unrelaxed and fully relaxed structures
(for a mechanically unstable phase).

Syntax: robustrelax_vasp [options] command_prefix
where options are
  -id             Inflection Detection method
  -idop "options" Options passed to the infdet command.
  -neb            Use the Nudged Elastic Band method to find minimum energy path
                  Otherwise: simply interpolate linearly.
  -ex             Only extract data form VASP files. Do not run anything.
  -c  [real]      Relaxation magnitude cutoff needed to activate robust relax algorithm (default: 0).
  -ni [integer]   Number of images in the minimum energy path (default: 6).
  -rc [string]    Command for full relaxation          (Default: runstruct_vasp -w vasp.wrap).
  -vc [string]    Command for volume only relaxation   (Default: runstruct_vasp -w vaspvol.wrap).
  -cc [string]    Command for chain (neb) calculations (Default: runstruct_vasp -w vaspneb.wrap).
  -sc [string]    Command for static runs              (Default: runstruct_vasp -w vaspstatic.wrap).
  -ic [string]    Command for inflection-detection runs (-id option) (Default: runstruct_vasp -p -w vaspid.wrap).
  -idf [real]     Starting point fraction for inflection detection (default: 0.5)
  -ja
  -jc             By how much to jitter atoms (-ja) and cell parameters (-jc) for the initial conditions
                  for inflection-detection method.
  -vib            Update vibrational data in svib_ht file from vol_0/svib_ht file.
  -mk             Make auxiliary vasp input files (vaspvol.wrap, vaspneb.wrap, vaspstatic.wrap, vaspf.wrap, vaspid.wrap)
                  from vasp.wrap. Does not run anything.
  -cln            clean files for a full restart.
  -cip            continue (an prior run) if possible (only implemented for -id algorithm).
  -d              Use all defaults values.
  -h              Display more help.
  command_prefix  Prefix needed for vasp to run on a remote machine or in parallel (e.g. mpirun).

Note: the commands specified by -rc,-vc,-cc,-sc can be set to empty "" to skip the corresponding
  calculation step (useful to restart an aborted run).
EOF
    if [[ $1 == "" ]]
    then
	exit
    fi
fi
while [[ $1 != "" ]]
do
    if [[ $1 == "-d" ]]
    then
	echo -n
    elif [[ $1 == "-h" ]]
    then
	dohelp=1
    elif [[ $1 == "-mk" ]]
    then
	makevaspfiles=1
    elif [[ $1 == "-cln" ]]
    then
	clnrestart=1
    elif [[ $1 == "-vib" ]]
    then
	dovib=1
    elif [[ $1 == "-cc" ]]
    then
	shift
	chaincommand="$1";
    elif [[ $1 == "-rc" ]]
    then
	shift
	relaxcommand="$1";
    elif [[ $1 == "-vc" ]]
    then
	shift
	volrelaxcommand="$1";
    elif [[ $1 == "-sc" ]]
    then
	shift
	staticcommand="$1";
    elif [[ $1 == "-ic" ]]
    then
	shift
	infdetcommand="$1";
    elif [[ $1 == "-cip" ]]
    then
	contif=1;
    elif [[ $1 == "-c" ]]
    then
	shift
	cutoff=$1
    elif [[ $1 == "-ni" ]]
    then
	shift
	nimage=$1
    elif [[ $1 == "-id" ]]
    then
	doid=1
    elif [[ $1 == "-idop" ]]
    then
	shift
	idopt="$1"
    elif [[ $1 == "-idf" ]]
    then
	shift
	idf="$1"
    elif [[ $1 == "-ja" ]]
    then
	shift
	idja="$1"
    elif [[ $1 == "-jc" ]]
    then
	shift
	idjc="$1"
    elif [[ $1 == "-neb" ]]
    then
	doneb=1
    elif [[ $1 == "-ex" ]]
    then
	doextract=1
    else
	cmdsuffix="$*"
	break
    fi
    shift
done

if [[ $dohelp == 1 ]]
then
    cat - <<EOF

This command does the following:
1) Fully relax the structure (in str_hint.out or str.out) to create str_relax.out,
   just like runstruct_vasp.
2) If the relaxation cutoff (-c=...) no exceeded, stop. Typically, should be set to -c=0.05.
3) Relax the volume only of structure in str_sup.out or str.out. Results are in directory 00/
4) Do a neb (-neb) or infection detection (-id) calculation between the two structures obtained in step 1 and 3
   or just a linear interpolation between them (if no -neb or -id). Results are in directories ??/
   Note that you need VTST Tools from http://theory.cm.utexas.edu/vtsttools/ for the neb method
   with variable cell shape.
5) Do static calculations in each directory ??/
6) Find the inflection point on the path optimized in step 4. If it does not exist, find the
   minimum energy along that path.
7) Report the energy found in 6 in the file energy and the corresponding geometry in str_relax.out

Notes:
1) str_beg.out and str_end.out contain the extremities of the path.
   If you want to restart from scratch, delete these files.
2) For high symmetry phases (e.g. bcc,fcc,hcp) you may need to break the symmetry of the phase for it to relax.
   For that purpose, you can use, e.g.,
      symbrklib W fcc bcc
   or
      cellcvrt -ja=0.01 -jc=0.01 < str.out > str_hint.out .
   Sometimes a supercell is needed (a phonon analysis will tell you that - or symbrklib for bcc,fcc,hcp).
EOF
    exit
fi

if [[ $makevaspfiles == 1 ]]
then
    if [[ ! -e vasp.wrap ]]
    then
	echo Please provide a vasp.wrap file.
	exit
    fi
    grep -v -i -e ISIF -e DOSTATIC vasp.wrap > vaspvol.wrap
    echo ISIF = 7 >> vaspvol.wrap
    grep -v -i -e  ISMEAR -e SIGMA -e NSW -e IBRION -e ISIF -e DOSTATIC vasp.wrap > vaspstatic.wrap
    cat - >> vaspstatic.wrap <<EOF
ISMEAR = -5
IBRION = -1
ISIF = 2
EOF
    grep -v -i -e IBRION -e DOSTATIC vasp.wrap > vaspneb.wrap
    echo IMAGES = $(( nimage -2 )) >> vaspneb.wrap
	cat - >>vaspneb.wrap <<EOF
SPRING = -5
LCLIMB = .FALSE.
LNEBCELL = .TRUE.
IBRION = 3
POTIM = 0
EDIFFG = -5e-2
IOPT = 3
EOF
    grep -v -i -e NSW -e IBRION -e ISIF -e DOSTATIC vasp.wrap > vaspf.wrap
    cat - >> vaspf.wrap <<EOF
LREAL = AUTO
ICHARG = 1
ISTART = 2
IBRION = -1
ISIF = 2
EOF
    grep -v -i -e NSW -e IBRION -e ISIF -e DOSTATIC -e KPPRA -e EDIFF -e EDIFFG vasp.wrap > vaspid.wrap
    cat - >> vaspid.wrap <<EOF
IBRION = -1
ISIF = 2
ICHARG = 1
KPPRA = UPDIR
ISYM = 0
EDIFF = 1e-5
ISTART = 2
EOF
    exit
fi

if [[ $clnrestart == 1 ]]
then
    rm str_beg.out str_end.out
    rm -r [0-9][0-9]
    exit
fi

if [[ $contif == 1 ]]
then
    if [[ -e OSZICAR && ! -e str_relax.out ]]
    then
	runstruct_vasp -ex
	rm -f error
	if [[ -e str_relax.out ]]
	then
	    if [[ -e str_hint.out ]]
	    then
		cp str_hint.out str_hint.out.org
	    fi
	    echo Re-relaxing pre-relaxed geometry...
	    mv -f str_relax.out str_hint.out
	fi
    fi
    if [[ -e str_end.out ]]
    then
	relaxcommand="";
	echo Skipping relax step...
	if [[ -e str_beg.out ]]
	then
	    volrelaxcommand="";
	    echo Skipping volume relax step...
	    if [[ -e 01/cstr_relax.out ]]
	    then
		infdetcommand="";
		echo Skipping inflection detection step...
		diff 01/cstr_relax.out str_relax.out > /dev/null
		if [[ $? == 0 ]]
		then
		    staticcommand="";
		    echo Skipping static run step...
		fi
	    fi
	fi
    fi
fi

if [[ $dovib == 1 ]]
then
    for subdir in vol_0 smsqs/vol_0
    do
	if [[ -e ${subdir}/svib_ht ]]
	then
	    if [[ ! -e confmult.in ]]
	    then
		echo using scaled ${subdir}/svib_ht
		echo `cat ${subdir}/svib_ht` `cellcvrt -pn < str.out` `cellcvrt -pn < ${subdir}/str_relax.out` | awk '{print $1*$2/$3}' > svib_ht
	    else
		echo using scaled ${subdir}/svib_ht and confmult.in
		echo `cat ${subdir}/svib_ht` `cellcvrt -pn < str.out` `cellcvrt -pn < ${subdir}/str_relax.out` `cat confmult.in` | awk '{print $1*$2/$3+$2*log($4)}' > svib_ht
	    fi
	    exit
	fi
    done
    echo No svib_ht file in `pwd`/vol_0 or `pwd`/smsqs/vol_0
    exit
fi


if [[ $doextract == 0 ]]
then
    if [[  $relaxcommand != "" ]]
    then
	echo $relaxcommand $cmdsuffix
	$relaxcommand $cmdsuffix
    fi
    if [[ -e error ]]
    then
	echo Error during relaxation run.
	exit 1
    fi

    relmag=`checkrelax -1`

#    if [[ ! (( $relmag > $cutoff || -e str_sup.out )) ]]
    if [[ ! (( $relmag > $cutoff )) ]]
    then
	if [[ $relaxcommand != "" ]]
	then
	    mv energy energy_sup
	    echo `cat energy_sup` `cellcvrt -pn < str.out` `cellcvrt -pn < str_relax.out` | awk '{print $1*$2/$3}' > energy
	fi
    else
	if [[ $relaxcommand != "" ]]
	then
	    mv energy energy_end
	    if [[ ! -e str_end.out ]]
	    then
		cp str_relax.out str_end.out
	    fi
	fi
	mkdir 00
	if [[ $volrelaxcommand != "" ]]
	then
	    if [[ -e str_sup.out ]]
	    then
		cp str_sup.out 00/str.out
	    else
		cp str.out 00/
	    fi
	    cd 00
	    echo "Now working in" `pwd`
	    echo $volrelaxcommand $cmdsuffix
	    $volrelaxcommand $cmdsuffix
	    if [[ -e error ]]
	    then
		echo Error during static run in 00/
		touch ../error
		exit 1
	    fi
	    cd ..
	fi
	if [[ ! -e str_beg.out ]]
	then
	    cp 00/str_relax.out str_beg.out
	fi
	if [[ $doid == 1 ]]
	then
	    if [[ ! -e KPOINTS ]]
	    then
		cp KPOINTS.static KPOINTS
	    fi

	    mkdir 01
	    if [[ -e 01/str_hint.in ]]
	    then
		cp 01/str_hint.in 01/str.in
	    else
		strpath -s1=str_beg.out -s2=str_end.out -f=${idf} | cellcvrt -ja=$idja -jc=$idjc > 01/str.in
	    fi
	    if [[ $infdetcommand != "" ]]
	    then
		pushd 01 > /dev/null
		echo "Now working in" `pwd`
		if [[ -e str_hint.in ]]
		then
		    cp str_hint.in str.in
		fi
		if [[ -e busy ]]
		then
		    rm busy
		fi
		echo Running infdet $idopt
		rm -f error stop busy
                if [[ -e infdet.log ]]
                then
                    for (( baknum=1 ; ; baknum++ ))
                    do
                        if [[ ! -e infdet.save${baknum} ]]
                        then
                            cp infdet.log infdet.save${baknum}
                            break;
                        fi
                    done
                fi
		( infdet $idopt > infdet.log ; if [[ $? == 1 ]] ; then touch error ; fi ; touch stop )  &
		while [[ 1 ]]
		do
		    while [[ ! -e busy && ! -e stop && ! -e error ]]
		    do
			sleep 2
		    done
		    if [[ -e stop || -e error ]]
		    then
			break
		    fi
		    echo vasp
		    rm stress.out force.out > /dev/null
		    $infdetcommand $cmdsuffix
		    cat stress.out force.out
		    rm busy
		    echo waiting
		done
		rm -f stop busy
		if [[ -e error ]]
		then
                    echo Error during inflection detection run in 01/
		    touch ../error
                    exit 1
		fi
		if [[ ! -e cstr_relax.out ]]
		then
		    cp str_current.out cstr_relax.out
		fi
		popd
	    fi
	    if [[ $staticcommand != "" ]]
	    then
		pushd 01
		cp cstr_relax.out str.out
		echo "$staticcommand $cmdsuffix"
		$staticcommand $cmdsuffix
		popd
	    fi
            if [[ -e error ]]
            then
                echo Error during static run in 01/
                exit 1
            fi
	    echo `cat 01/energy` `cellcvrt -pn < str.out` `cellcvrt -pn < 01/str_relax.out` | awk '{print $1*$2/$3}' > energy
	    ( echo `cellcvrt -pn < str.out` `cellcvrt -pn < 01/str_relax.out` ; cat 01/dos.out )| awk 'BEGIN {getline; sc=$1/$2; getline; print  $1*sc,$2,$3} {print $1*sc;}' > dos.out
	    cp 01/cstr_relax.out str_relax.out
	    exit 0
	elif [[ $doneb == 1 ]]
	then
	    strpath -s1=str_beg.out -s2=str_end.out -ni=$nimage
	    if [[ $chaincommand != "" ]]
	    then
		lastdir=`ls -d -1 ?? | sort -n | tail -n -1`
		cp ${lastdir}/str.out ${lastdir}/str_relax.out

		echo "$chaincommand -nr"
		foreachfile str.out "$chaincommand -nr"
		for file in POTCAR KPOINTS INCAR vasp.in
		do
		    rm ??/${file}
		done
		echo  $chaincommand "$cmdsuffix"
		$chaincommand "$cmdsuffix"
		foreachfile str.out "$chaincommand -ex"
		foreachfile str_relax.out cp str_relax.out str_hint.out
		foreachfile str_relax.out cp OSZICAR OSZICAR.neb
		cp OUTCAR OUTCAR.neb \; gzip OUTCAR.neb
		if [[ $staticcommand != "" ]]
		then
		    echo "$staticcommand $cmdsuffix"
		    foreachfile str_relax.out "$staticcommand $cmdsuffix"
		fi
	    fi
	else
	    strpath -s1=str_beg.out -s2=str_end.out -ni=$nimage
	    if [[ $volrelaxcommand != "" ]]
	    then
		echo "$volrelaxcommand $cmdsuffix"
		foreachfile str.out "$volrelaxcommand $cmdsuffix"
	    fi
	    if [[ $staticcommand != "" ]]
	    then
		echo "$staticcommand $cmdsuffix"
		foreachfile str_relax.out "$staticcommand $cmdsuffix"
	    fi
	fi
    fi
fi
if [[ $doextract == 1 || (( $relmag > $cutoff || -e str_sup.out )) ]]
then
    if [[ ! -e 00 ]]
    then
	runstruct_vasp -ex
	cp energy energy_end
	echo `cat energy_end` `cellcvrt -pn < str.out` `cellcvrt -pn < str_relax.out` | awk '{print $1*$2/$3}' > energy
    else
	if [[ ! -e energy_end ]]
	then
	    cp energy energy_end
	fi
	lastenergy=`ls -d -1 ?? | sort -n | tail -n -1`
#echo $lastenergy
	if [[ ! -e ${lastenergy}/energy ]]
	then
	    cp energy_end ${lastenergy}/energy
	fi
	((curnimage=lastenergy+0))
#echo $curnimage
	cat `ls -1 ??/energy | sort -n` > epath.out
#    cat epath.out | strpath -ci > energy
	echo `cat epath.out | strpath -ci` `cellcvrt -pn < str.out` `cellcvrt -pn < str_beg.out` | awk '{print $1*$2/$3}' > energy
	iploc=$(cat epath.out | strpath -cil | awk '{print $1*('$curnimage')}')
#echo $iploc
	dirb=$(echo $iploc | awk '{n=int($1); printf("%02i",n)}')
#echo $dirb
	if [[ $iploc == $curnimage ]]
	then
#echo cp only
	    cp ${dirb}/str_relax.out .
	else
	    dire=$(echo $iploc | awk '{n=int($1)+1; printf("%02i",n)}')
#echo $dire
	    frac=$(echo $iploc | awk '{print $1-int($1);}')
#echo $frac
	    strpath -f=${frac} -s1=${dirb}/str_relax.out -s2=${dire}/str_relax.out > str_relax.out
	    echo	strpath -f=${frac} -s1=${dirb}/str_relax.out -s2=${dire}/str_relax.out 
	fi
    fi

fi
