#!/bin/sh
#############################################################################
# Author:                                                                   #
# ------                                                                    #
#  Anton Kokalj                                  Email: Tone.Kokalj@ijs.si  #
#  Department of Physical and Organic Chemistry  Phone: x 386 1 477 3523    #
#  Jozef Stefan Institute                          Fax: x 386 1 477 3811    #
#  Jamova 39, SI-1000 Ljubljana                                             #
#  SLOVENIA                                                                 #
#                                                                           #
# Source: $XCRYSDEN_TOPDIR/scripts/pwo2xsf.sh
# ------                                                                    #
# Copyright (c) 1996-2003 by Anton Kokalj                                   #
#############################################################################

# set locales to C
LANG=C 
LC_ALL=C
export LANG LC_ALL

#
# Purpose: PWscf(v2.0 or latter)-output--to--XSF conversion
# Usage:   pwo2xsf [options] pw-output-file
#
# Written by Tone Kokalj on Mon Feb  9 12:48:10 CET 2004
#            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

cat > pwo2xsfUsage.$$ <<EOF

 Usage: pwo2xsf.sh [-r dim] options [pw-output-file]

 If file is not specified then stadard input is read.

  -r dim 
     Reduce periodic dimension to dim, where dim = 2, 1, or 0.
 
 OPTIONS are:

  --inicoor|-ic [pw-output-file]
     Extract the initial (i.e. input) ionic coordinates.

  --latestcoor|-lc [pw-output-file]
     Extract the latest printed ionic coordinates from pw.x output file.

  --optcoor|-oc [pw-output-file]
     Similar to "--latestcoor" but extracts just the optimized coordinates
     if present or else nothing.

  --animxsf|-a [pw-output-file1] ...
     Extract the coordinates of all ionic steps as Animated-XSF.

  --nebcoor|-nc [PW.out]
     Extract the coordinates and forces from the \fBPW.out\fR file of NEB
     (path) calculation.

EOF


# ------------------------------------------------------------------------
# Utility functions
# ------------------------------------------------------------------------
CleanTmpFiles() {
    if test -f pwo2xsfUsage.$$ ; then rm -f pwo2xsfUsage.$$; fi
    if test -f xsf.$$ ; then rm -f xsf.$$; fi
    if test -f pw.$$ ; then rm -f pw.$$; fi
}
pwoExit() {
    # Usage: $0 exit_status
    CleanTmpFiles
    exit $1
}
pwoUsage() {
    if test $1 ; then
	echo "
Usage: $2
"
	pwoExit 1
    fi
}
pwoGetVersion() {
    grep 'Program PWSCF' $1 | tail -1 | awk '
      {  ver=$3; n=split(ver,v,"."); 
         ii=0; for(i=1; i<=n; i++) if ( v[i] ~ /[0-9]+/ ) vv[ii++]=v[i];  
         if (ii>2) printf "%d.%d%d\n", vv[0],vv[1],vv[2];
         else printf "%d.%d\n", vv[0], vv[1];
      }'
}
pwoCheckPWSCFVersion() {
    #
    # Usage: $0 option file
    #
    # Purpose: if PWSCF version < 1.3 execute the old pwo2xsf_old.sh
    #          script and exit
    version=`pwoGetVersion $input`
    result=`echo "$version < 1.3"|bc -l`
    if test x"$result" = x1 ; then
	if test -f $scriptdir/pwo2xsf_old.sh ; then
    	   # execute pwo2xsf_old.sh
	    $scriptdir/pwo2xsf_old.sh $1 $2
	    pwoExit $?
	else
	    echo "ERROR: PWscf output generated by version < 1.3 !!!"
	    pwoExit 1
	fi
    fi
}


# ------------------------------------------------------------------------
# Function: pwoGetIbrav
# Extract:  ibrav from pw.x output file
# ------------------------------------------------------------------------
pwoGetIbrav() {
    echo `egrep "bravais-lattice index  +=" $1 | tail -1 | awk '{print $NF}'`
}

pwoAnimSteps() {
    cp xsf.$$ xsf2.$$
    nsteps=`grep PRIMCOORD xsf.$$ | wc | awk '{print $1}'`    
    echo "ANIMSTEPS $nsteps" > xsf.$$
    cat xsf2.$$ >> xsf.$$
    rm -f xsf2.$$
}

# ------------------------------------------------------------------------
# Function: pwoConvVec
# Purpose: tries to assign the CONVVEC based on PRIMVEC and ibrav and
#          prints to standard output the modified XSF file that
#          contains the CONVVECs
#------------------------------------------------------------------------
pwoConvVec() {
    ibrav=`pwoGetIbrav $input`

    if test "x$ibrav" = x; then
        # ibrav not found; do nothing
        cat xsf.$$
        
    elif test "x$dim" = x3; then
        # ibrav was found and structure was not reduced; try to assign CONVVEC
        $PWO_XSF2XSF $ibrav < xsf.$$
        
    else
        # dimensionality of structure has bin reduced; do nothing
        cat xsf.$$
    fi
}


# ------------------------------------------------------------------------
# Function: pwoOptCoor
# Extract:  OPTIMIZED or LATEST coordinates
# Perform:  read PW-output file and print the XSF file according to
#           specified flags
# ------------------------------------------------------------------------
pwoOptCoor() {
    #set -x
    pwoUsage "$# -lt 1" \
	"$0 --latestcoor|-lc [pw-output-file]   or   $0 --optcoor|-oc [pw-output-file]"
    
    option=$1
    case $1 in
	--latestcoor|-lc) type=LATEST;    shift;;
	--optcoor|-oc)    type=OPTIMIZED; shift;;
    esac
    
    if test $# -eq 0 ; then
	input=pw.$$
	cat - >> $input
    else
	input=$1
    fi
    
    pwoCheckPWSCFVersion $option $input

    if test $type = "OPTIMIZED" ; then
	# Check for the presence of "Begin final coordinates"
	# and/or:
	# Check also for the PWSCF-v.1.3.0 which uses the
	# "Final estimate of positions" record
	if test \( "`grep \"Begin final coordinates\" $input`" = "" \) \
	    -a \( "`grep 'Final estimate of positions' $input`" = "" \) \
	    -a \( "`grep '     bfgs converged in' $input`" = "" \); then
	    echo "ERROR: OPTIMIZED coordinates does not exists"
	    pwoExit 1
	fi
    fi

    cat "$input" | awk -v t=$type -v dimen=$dim -f $scriptdir/pwo2xsf_opt.awk > xsf.$$

    pwoConvVec
}


# ------------------------------------------------------------------------
# Function: pwoAnimCoor
# Extract:  INITIAL or ALL coordinates
# Perform:  read PW-output file and print the XSF file according to
#           specified flags
# ------------------------------------------------------------------------

pwoAnimCoor() {
    #set -x
    pwoUsage "$# -lt 1" "$0 --animcoor|-ac|--animxsf|-a [pw-output-file1] or   $0 --inicoor|-ic [pw-output-file]"
    
    option=$1
    only_init=0
    case $1 in
	--inicoor|-ic) only_init=1; shift;;
	--animcoor|-ac|--animxsf|-a) only_init=0; shift;;
    esac

    if test $# -eq 0 ; then
	input=pw.$$
	cat - >> $input
    else
	input=$1
    fi

    pwoCheckPWSCFVersion $option $input

    ncoor=`awk '$1 ~ /ATOMIC_POSITIONS/ { npos++; } 
               END {   # add another step for initial coordinates    
                       print npos+1; }' $input`; 

    nvec=`awk '$1 ~ /CELL_PARAMETERS/ { nvec++; } END { print nvec; }' $input`
    
    cat "$input" | awk \
	-v ncoor=$ncoor \
	-v nvec=$nvec \
	-v dimen=$dim \
	-v onlyinit=$only_init -f $scriptdir/pwo2xsf_anim.awk > xsf.$$

    if test $only_init -eq 0 ; then
        # Assign the number of ANIMSTEPS here. The reason is that the
        # output file (queue runs) is the result of several job runs,
        # then some of them might be terminated on the "wrong" place,
        # and the initial ANIMSTEPS might be wrong. The most secure
        # way is to extract the sequential digit from the last
        # "PRIMCOORD id" record.
        pwoAnimSteps
    fi

    pwoConvVec
}

# ------------------------------------------------------------------------
# Function: pwoNebCoor
# Extract:  all coordinates and forces found in PW.out file
# ------------------------------------------------------------------------

pwoNebCoor() {
    #set -x
    pwoUsage "$# -lt 1" "$0 --nebcoor|-nc [PW.out]"
    
    option=$1; shift

    if test $# -eq 0 ; then
	input=pw.$$
	cat - >> $input
    else
	input=$1
    fi

    cat "$input" | awk \
	-v dimen=$dim \
	-f $scriptdir/pwo2xsf_neb.awk > xsf.$$

    # Assign the number of ANIMSTEPS here. The reason is that the
    # output file (queue runs) is the result of several job runs, then
    # some of them might be terminated on the "wrong" place, and the
    # initial ANIMSTEPS might be wrong. The most secure way is to extract the 
    # sequential digit from the last "PRIMCOORD id" record.

    pwoAnimSteps

    # conventional-vectors 
    pwoConvVec
}


#######################################################################
####                              MAIN                              ###
#######################################################################

if test "x`which readlink`" = "x"; then
    # no readlink cmd; make a function-substitute
    readlink_f() {
        file=`ls -l "$1" | awk '{print $NF}'`
        while test -h "$file"; do
            file=`ls -l "$file" | awk '{print $NF}'`
        done
        echo $file
    }
else
    readlink_f() {
        readlink -f "$1"
    }
fi


pathname() {
    file=`which "$1"`    
    if test $? -gt 0; then
        file=`type "$1"`
	if test $? -gt 0; then
	    # give-up
	    file="$1"
        else
            file=`echo $file | awk 'BEGIN {FS="is "} {print $NF}'`
        fi
    fi
    echo $file
}


pathdir() {
    file=`pathname "$1"`
    
    while test -h "$file"; do
	file=`readlink_f "$file"`
    done

    dir=`dirname "$file"`
    ( cd $dir; pwd )
}

if test -z $XCRYSDEN_TOPDIR; then
    # XCRYSDEN_TOPDIR does not exists, guess it from the process
    scriptdir=`pathdir $0`
    export XCRYSDEN_TOPDIR=`(cd $scriptdir/..; pwd)`
else
    scriptdir=$XCRYSDEN_TOPDIR/scripts
fi


AWK=`which awk`
if test "$AWK" = ""; then 
    echo "ERROR: awk program not found"
    pwoExit 1
fi

PWO_XSF2XSF=pwo_xsf2xsf
if test -f $XCRYSDEN_TOPDIR/bin/pwo_xsf2xsf ; then
    PWO_XSF2XSF=$XCRYSDEN_TOPDIR/bin/pwo_xsf2xsf
elif test -f $XCRYSDEN_LIB_BINDIR/pwo_xsf2xsf ; then
    PWO_XSF2XSF=$XCRYSDEN_LIB_BINDIR/pwo_xsf2xsf
fi

if [ $# -eq 0 ]; then
    cat pwo2xsfUsage.$$
    pwoExit 1
fi

dim=3
if test $1 = "-r"; then
    dim=$2;
    shift 2
fi

case $1 in
    --inicoor|-ic)               pwoAnimCoor $@;;
    --latestcoor|-lc)            pwoOptCoor $@;;
    --optcoor|-oc)               pwoOptCoor $@;;
    --animcoor|-ac|--animxsf|-a) pwoAnimCoor $@;;    
    --nebcoor|-nc)               pwoNebCoor $@;;
    --help|-h)                   cat pwo2xsfUsage.$$;;
    *)                           cat pwo2xsfUsage.$$; pwoExit 1;;
esac

pwoExit 0
