DL4DistancePrediction4/Scripts/PredictPairRelation4Inputs.sh
#!/bin/sh

if [[ -z "${DL4DistancePredHome}" ]]; then
        echo "ERROR: please set environmental variable DL4DistancePredHome to the install folder of DL4DistancePrediction4"
        exit 1
fi

#DeepModelFile=/mnt/data/RaptorXCommon/TrainTestData/Distance_Contact_TrainData/Jinbo_Folder/result4HBBeta/DistanceV3ModelFiles.txt
DeepModelFile=$DL4DistancePredHome/params/ModelFile4PairwisePred.txt
#ModelName=EC47C31C16CL99LargerS35V2020CbCbTwoRModels
#ModelName=EC47C37C19CL99S35V2020MidModels
GPU=-1
ResultDir=""

tplStr=""
aliStr=""

DefaultModel4FM=EC47C37C19CL99S35V2020MidModels
DefaultModel4HHP=HHEC47C37C19CL99S35PDB70Models
DefaultModel4NDT=NDTEC47C37C19CL99S35BC40Models
ModelName=""

alignmentType=0

## the amount of memory to be preallocated
GPUmemory=0

function Usage 
{
  	echo $0 " [ -f DeepModelFile | -m ModelName | -d ResultDir | -g gpu | -p preallocate_memory | -T alignmentType | -a aliStr | -t tplStr ] proteinListFile inputFolder1 [inputFolder2 inputFolder3 ...]"
	echo "	This script predicts inter-atom distance/orientation for a list of proteins, each with a set of feature files"
	echo "	proteinList: a file (ending with .list) for a list of protein names, each in one row"
	echo "	inputFolder: one or multiple folders containing features for proteins in proteinList"
	echo "	     In each folder, a protein shall have 3 feature files: *.inputFeatures.pkl, *.extraCCM.pkl and *.a2m, generated by BuildFeatures/GenDistFeaturesFromA3M.sh or BuildFeatures.sh"
	echo "	     some deep models need only the first .pkl file, some need both .pkl files and very few need the a2m file"
	echo " "
	echo "	-a: optional, specify a single alignment file, one or multiple alignment folders. When multiple folders are specified, they shall be separated by ; "
	echo "		an alignment file shall be in FASTA format and has name proteinName-*.fasta"
	echo "		Two different alignment files shall have different names even if they are in different folders"
	echo "	-t: optional, specify a template file or folder. A template file shall have name templateName.tpl.pkl and can be generated by Common/MSA2TPL.sh "
        echo "	-T: indicate how sequence-template alignments are generated: 1 for alignments generated by HHpred and 2 for alignments generated by RaptorX threading"
        echo "		This option will be used only if both alStr and tplStr are present"
	echo "	"
	echo "	-f: a file containing a set of deep model names, default $DeepModelFile"
	echo "	-m: a model name defined in DeepModelFile representing a set of deep learning models. Below is the default setting:"
        echo "		When aliFolders are not used, $DefaultModel4FM will be used"
        echo "		When aliFolders are used, if alignmentType=2, $DefaultModel4NDT will be used; otherwise $DefaultModel4HHP will be used"
	echo " "
	echo "	-d: the folder for result saving, default Dist-ListName-InputName-ModelName where ListName and InputName are the base names of proteinList and inputFolder"
	echo "	-g: -1 (select a GPU automatically), 0-3, default $GPU"
        echo "		Users shall make sure that at least one GPU has enough memory for the prediction job. Otherwise it may crash itself or other jobs"	
	echo "	-p: the amount of GPU memory to be preallocated, default $GPUmemory"
	echo "		if 0, no preallocation; if between 0 and 1, it is the fraction of memory to be preallocated; if >1, it is the actual amount of memory to be allocated"
}

while getopts ":f:m:d:g:p:T:a:t:" opt; do
        case ${opt} in
                f )
                  DeepModelFile=`readlink -f $OPTARG`
                  ;;
                m )
                  ModelName=$OPTARG
                  ;;
                d )
                  ResultDir=$OPTARG
                  ;;
                g )
                  GPU=$OPTARG
                  ;;
	        p )
                  GPUmemory=$OPTARG
                  ;;
		T )
		  alignmentType=$OPTARG
		  ;;
		a )
		  aliStr=$OPTARG
		  ;;
		t )
		  tplStr=$OPTARG
		  ;;
                \? )
                  echo "Invalid Option: -$OPTARG" 1>&2
                  exit 1
                  ;;
                : )
                  echo "Invalid Option: -$OPTARG requires an argument" 1>&2
                  exit 1
                  ;;
        esac
done
shift $((OPTIND -1))

if [ $# -lt 2 ]; then
        Usage
        exit 1
fi

proteinList=$1
if [[ "$proteinList" != *.list ]]; then
	echo 'ERROR: the protein list file shall END with .list'
	exit 1
fi
if [ ! -f $proteinList ]; then
	echo "ERROR: invalid protein list file: $proteinList"
	exit 1
fi

inputFolder=$2
if [ ! -d $inputFolder ]; then
	echo "ERROR: invalid folder for input feature files: $inputFolder"
	exit 1
fi

featureFolders=${@:3}
for fFolder in $featureFolders
do
	if [ ! -d $fFolder ]; then
		echo "ERROR: invalid folder for input feature files: $fFolder"
		exit 1
	fi
	inputFolder=$inputFolder';'$fFolder
done

program=$DL4DistancePredHome/RunPairwisePredictor.py
if [ ! -f $program ]; then
	echo ERROR: invalid program $program
	exit 1
fi

if [ ! -f $DeepModelFile ]; then
        echo "ERROR: invalid file for deep model path information: $DeepModelFile"
        exit 1
fi
. $DeepModelFile

if [ -z "$aliStr" -a -z "$tplStr" ]; then
        if [ -z "$ModelName" ]; then
                ModelName=$DefaultModel4FM
        fi

elif [ ! -z "$aliStr" -a ! -z "$tplStr" ]; then
	if [ -z "$ModelName" ]; then
                if [ $alignmentType -eq 2 ]; then
                        ModelName=$DefaultModel4NDT
                else
                        ModelName=$DefaultModel4HHP
                fi
        fi
else
        echo "ERROR: alignment and template info shall be present or absent simultaneously"
        exit 1
fi

#echo ModelName=$ModelName
ModelFiles=`eval echo '$'${ModelName}`
#echo ModelFiles=$ModelFiles
if [ $ModelFiles == "" ]; then
	echo "ERROR: ModelFiles for $ModelName is empty"
	exit 1
fi

if [ -z "${ResultDir}" ]; then
	listName=`basename proteinList .list`
	inputName=`basename $inputFolder`
	ResultDir=Dist-${listName}-${inputName}-${ModelName}
fi

if [ ! -d $ResultDir ]; then
	mkdir -p $ResultDir
fi

command=" python $program -m $ModelFiles -p $proteinList -i $inputFolder -d $ResultDir "
if [ ! -z "$aliStr" -a ! -z "$tplStr" ]; then
	command=$command" -a $aliStr -t $tplStr "
fi

if [[ -z "${CUDA_ROOT}" ]]; then
        echo "ERROR: please set environmental variable CUDA_ROOT"
        exit 1
fi

if [ $GPU == "-1" ]; then
        ## here we assume 6G is sufficient, although sometimes it is not enough
        neededRAM=6403741824
        GPU=`$ModelingHome/Utils/FindOneGPUByMemory.sh $neededRAM 40`
fi

if [ $GPU == "-1" ]; then
        echo "WARNING: cannot find an appropriate GPU to run $0 for distance/orientation prediction for $proteinList"
        exit 1
else
        GPU=cuda$GPU
fi

THEANO_FLAGS=blas.ldflags=,device=$GPU,floatX=float32,gpuarray.preallocate=$GPUmemory,dnn.include_path=${CUDA_ROOT}/include,dnn.library_path=${CUDA_ROOT}/lib64 $command
if [ $? -ne 0 ]; then
	echo "ERROR: failed to run $command"
	exit 1
fi
