#!/usr/bin/env bash
# (note: Classic Bourne shell (#!/bin/sh) also worked at some point.)
#
# Author: Andrew Jewett (jewett.aij at g mail)
#         http://www.moltemplate.org
#         http://jensenlab.caltech.edu
#         http://www.chem.ucsb.edu/~sheagroup
# License: 3-clause BSD License  (See LICENSE.txt)
# Copyright (c) 2012, Regents of the University of California
# All rights reserved.

G_PROGRAM_NAME="emoltemplate.sh"
G_VERSION="1.0.5"
G_DATE="2017-2-01"

echo "${G_PROGRAM_NAME} v${G_VERSION} ${G_DATE}" >&2
echo "" >&2

# Check for python:
# I prefer python over python3 because python3 requires slightly
# more memory.  Use regular python (ie 2.7) when available.

if which python > /dev/null; then 
    PYTHON_COMMAND='python'
elif which python3 > /dev/null; then 
    PYTHON_COMMAND='python3'
else
    echo "Error:  $G_PROGRAM_NAME requires python or python3" >&2
    exit 1
fi
  

# First, determine the directory in which the python scripts are located.
# (such as ttree.py).  It could either be the directory where the script
# file is located, OR it could be the parent of this directory.
PY_SCR_DIR=`dirname "$0"`
if [ ! -s "${PY_SCR_DIR}/ttree.py" ]; then
    PY_SCR_DIR="$PY_SCR_DIR/.."
fi
MOLTEMPLATE_SCRIPT_DIR="$SCRIPT_DIR/../moltemplate/src"


MSG_BAD_INSTALL=$(cat <<EOF

INSTALLATION ERROR:
Follow the instructions in the "Installation" chapter of the emoltemplate manual
(Note: You may need to log out and log in again before the changes take effect.)

EOF
)


ERR_BAD_INSTALL()
{
  echo "$MSG_BAD_INSTALL" >&2
  exit 1
}


ERR_INTERNAL()
{
  echo "    !!!!!!   Possible internal error  !!!!!!" >&2
  echo "This could be a bug in emoltemplate." >&2
  echo "Please report this error." >&2
  echo "(And please include the last few lines of emoltemplate output preceeding this.)" >&2
  echo "  Thank you." >&2
  exit 100
}


MOLTEMPLATE_FILES_NEEDED=$(cat <<EOF
ttree.py
nbody_by_type.py
nbody_fix_ttree_assignments.py
nbody_reorder_atoms.py
pdbsort.py
remove_duplicate_atoms.py
remove_duplicates_nbody.py
renumber_DATA_first_column.py
ttree_render.py
EOF
)


# (I might add these files later: ettree_check.py, ettree_postprocess.py)


OIFS=$IFS
#IFS=$'\n'
IFS="
"

# command that invokes ettree.py
TTREE_COMMAND="$PYTHON_COMMAND \"${SCRIPT_DIR}/ettree.py\""

# command that invokes ettree_check.py
TTREE_CHECK_COMMAND="$PYTHON_COMMAND \"${SCRIPT_DIR}/ettree_check.py\""

# command that invokes ettree_postprocess.py
TTREE_POSTPROCESS_COMMAND="$PYTHON_COMMAND \"${SCRIPT_DIR}/ettree_postprocess.py\""



# What is the name of the .ET file we are reading?
for LAST_ARG; do true; done
# (I copied this code from a web page:
# http://stackoverflow.com/questions/1853946/getting-the-last-argument-passed-to-a-shell-script)

# Check to see if this string ends in .et or .ET
# If so, then set the base name of the output files
# to equal the base name of the .ET file being read.
# (Being careful here.
#  Sometimes the last argument is not the .et or .ET file.
#  Sometimes that file appears earlier in the argument list.
#  I want to supply a default value.)
#
#   Note, in bash you can use: 
# if [ "${LAST_ARG/%.et/}" -neq "$LAST_ARG" ]; then
#     OUT_FILE_BASE="${LAST_ARG/%.et/}"
# But in the original bourn shell (sh), this does not work. 
# Instead we use a hack involving basename and dirname:
ETFILE="$LAST_ARG"
ETFILE_DIR=`dirname "$ETFILE"`
ETFILE_BASE=`basename "$ETFILE" .et`
ETFILE_NO_EXT="${ETFILE_DIR}/${ETFILE_BASE}"
OUT_FILE_BASE="system"
if [ "$ETFILE_NO_EXT" != "$ETFILE" ]; then
    OUT_FILE_BASE="$ETFILE_BASE"
else
    ETFILE_BASE=`basename "$LAST_ARG" .ET`
    ETFILE_NO_EXT="${ETFILE_DIR}/${ETFILE_BASE}"
    if [ "$ETFILE_NO_EXT" != "$ETFILE" ]; then
	OUT_FILE_BASE="$ETFILE_BASE"
    fi
fi
OUT_FILE_TCL="${OUT_FILE_BASE}.tcl"

rm -f "$OUT_FILE_TCL"


















# -----------------------------------------------------------
# If everything works, then running ttree usually 
# generates the following files:
#
# Users of ettree typically generate the following files:
# The variable below refer to file names generated by 
# write() and write_once() commands in a ettree-file.
# (I keep changing my mind what I want these names to be.)
data_prefix="Data "
data_prefix_no_space="Data"
data_atoms="Data Atoms"
data_bonds="Data Bonds"
data_bond_list="Data Bond List"
data_angles="Data Angles"
data_dihedrals="Data Dihedrals"
data_impropers="Data Impropers"
data_bond_coeffs="Data Bond Coeffs"
data_angle_coeffs="Data Angle Coeffs"
data_dihedral_coeffs="Data Dihedral Coeffs"
data_improper_coeffs="Data Improper Coeffs"
data_pair_coeffs="Data Pair Coeffs"

# interactions-by-type (not id. This is not part of the LAMMPS standard.)
data_bonds_by_type="Data Bonds By Type"
data_angles_by_type="Data Angles By Type"
data_dihedrals_by_type="Data Dihedrals By Type"
data_impropers_by_type="Data Impropers By Type"

# periodic boundary conditions
data_boundary="Data Boundary"

# ---------------------------------------------------------------
# Note: The files above are fragments of a LAMMPS data file.
# In addition, emoltemplate will probably also generate the following files:
# (These files represent different sections of the LAMMPS input script.)
# ---------------------------------------------------------------

in_prefix="In "
in_prefix_no_space="In"
in_init="In Init"
in_settings="In Settings"
in_coords="In Coords"

#     If present, the various "In " files contain commands which should be 
#     included by the user in their LAMMPS input script. (This task is left
#     to the user.) However, the "Data " files are processed and pasted together
#     automatically in order to build a LAMMPS data file.
# ---------------------------------------------------------------

tmp_atom_coords="tmp_atom_coords.dat"  #<-temporary file for storing coordinates



MOLTEMPLATE_TEMP_FILES=$(cat <<EOF
*.template
ttree_assignments.txt
$tmp_atom_coords
$data_atoms
$data_bonds
$data_bond_list
$data_angles
$data_dihedrals
$data_impropers
$data_bond_coeffs
$data_angle_coeffs
$data_dihedral_coeffs
$data_improper_coeffs
$data_pair_coeffs
$data_bonds_by_type
$data_angles_by_type
$data_dihedrals_by_type
$data_impropers_by_type
$data_boundary
$in_init
$in_settings
EOF
)

OIFS=$IFS
#IFS=$'\n'
IFS="
"
for f in $MOLTEMPLATE_TEMP_FILES; do
    #echo "removing [$f]"
    rm -f "$f"
done
IFS=$OIFS

rm -rf output_ttree




SYNTAX_MSG=$(cat <<EOF
Syntax example: 
Usage:

emoltemplate.sh [-pdb/-xyz coord_file] \
                [-a assignments.txt] file.lt

Optional arguments:

-xyz xyz_file   An optional xyz_file argument can be supplied as an argument
                following "-xyz". (This must come before all other arguments.)
                This file should contain the atomic coordinates in xyz format.
                (The atoms must appear in the same order in the data file.)

-pdb pdb_file   An optional pdb_file argument can be supplied as an argument
                following "-pdb". (This must come before all other arguments.)

                This should be a PDB file (with ATOM or HETATM records) with
                the coordinates you wish to appear in the LAMMPS data file. 
                (The atoms must appear in the same order in the data file.)

                If the PDB file contains periodic boundary box information 
                (ie., a "CRYST1" record), this information is also copied 
                to the LAMMPS data file.  
                (Support for triclinic cells is experimental as of 2012-2-13.
                 Other molecular structure formats may be supported later.)
-a "@atom:x 1"
-a assignments.txt
                The user can customize the numbers assigned to atom, bond,
                angle, dihedral, and improper types or id numbers by using
                   -a "VARIABLE_NAME VALUE"
                for each variable you want to modify.  If there are many
                variables you want to modify, you can save them in a file
                (one variable per line).  For an example of the file format
                run emoltemplat.sh once and search for a file named
                "ttree_assignments.txt".  (This file is often located in
                the "output_ttree/" directory.) Once assigned, the remaining
                variables in the same category will be automatically assigned
                to values which do not overlap with your chosen values.
-b assignments.txt
                "-b" is similar to "-a". However, in this case, no attempt 
                is made to assign exclusive (unique) values to each variable.
-nocheck
               Normally emoltemplate.sh checks for common errors and typos and
               halts if it thinks it has found one.  This forces the variables
               and categories as well as write(file) and write_once(file) 
               commands to obey standard naming conventions.  The "-nocheck"
               argument bypasses these checks and eliminates these restrictions.
               Note: this argument must appear first in the list, for example:
               emoltemplate -nocheck -pdb f.pdb -a "$atom:res1/CA 1" system.lt
EOF
)

# --- Periodic boundary box information (default) ---

# We will determine these numbers later.
TRICLINIC=""
BOXSIZE_MINX=0.0
BOXSIZE_MINY=0.0
BOXSIZE_MINZ=0.0
BOXSIZE_MAXX=""
BOXSIZE_MAXY=""
BOXSIZE_MAXZ=""
BOXSIZE_XY=0.0
BOXSIZE_XZ=0.0
BOXSIZE_YZ=0.0



if [ "$1" = "--help" ]; then 
    echo "$SYNTAX_MSG" >&2
    exit 0
fi



# --- Did the user specify a file containing atomic coordinates?

rm -f "$tmp_atom_coords"

# Optional files containing atom coordinates:
PDB_FILE=""
XYZ_FILE=""
# REMOVE_DUPLICATE variables:
# ...If true (default), then any duplicate entries in the lists of bonds
# bonds, angles, dihedrals, or impropers in the LAMMPS DATA file
# are removed, giving priority to the most recent entry in the list.
# (This might not be necessary, but I want to be careful.)
REMOVE_DUPLICATE_BONDS="true"
REMOVE_DUPLICATE_ANGLES="true"
REMOVE_DUPLICATE_DIHEDRALS="true"
REMOVE_DUPLICATE_IMPROPERS="true"


ARGC=0
for A in "$@"; do
    ARGC=$((ARGC+1))
    eval ARGV${ARGC}=\"$A\"
done

TTREE_ARGS=""

i=0
while [ "$i" -lt "$ARGC" ]; do
    i=$((i+1))
    eval A=\${ARGV${i}}
    if [ "$A" = "-nocheck" ]; then
	# Disable syntax checking by undefining ETTREE_CHECK_COMMAND
	unset ETTREE_CHECK_COMMAND
    elif [ "$A" = "-overlay-bonds" ]; then
	# In that case, do not remove duplicate bond interactions
	unset REMOVE_DUPLICATE_BONDS
    elif [ "$A" = "-overlay-angles" ]; then
	# In that case, do not remove duplicate angle interactions
	unset REMOVE_DUPLICATE_ANGLES
    elif [ "$A" = "-overlay-dihedrals" ]; then
	# In that case, do not remove duplicate dihedral interactions
	unset REMOVE_DUPLICATE_DIHEDRALS
    elif [ "$A" = "-overlay-impropers" ]; then
	# In that case, do not remove duplicate improper interactions
	unset REMOVE_DUPLICATE_IMPROPERS
    elif [ "$A" = "-raw" ]; then
        if [ "$i" -eq "$ARGC" ]; then
            echo "$SYNTAX_MSG" >&2
            exit 7
        fi
        i=$((i+1))
        eval A=\${ARGV${i}}
        RAW_FILE=$A
        if [ ! -s "$RAW_FILE" ]; then
            echo "$SYNTAX_MSG" >&2
            echo "-----------------------" >&2
            echo "" >&2
            echo "Error: Unable to open RAW-file \"$RAW_FILE\"." >&2
            echo "       (File is empty or does not exist.)" >&2
            exit 8
        fi
        #echo "  (extracting coordinates from \"$RAW_FILE\")" >&2
        awk '{if (NF==3) {print $0}}' < "$RAW_FILE" > "$tmp_atom_coords"
    elif [ "$A" = "-xyz" ]; then
        if [ "$i" -eq "$ARGC" ]; then
            echo "$SYNTAX_MSG" >&2
            exit 2
        fi
	# "isnum(x)" returns 1 or 0 depending upon whether or not
	# a string is numeric.
	#http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#AWK
        i=$((i+1))
        eval A=\${ARGV${i}}
	XYZ_FILE=$A
        if [ ! -s "$XYZ_FILE" ]; then
            echo "$SYNTAX_MSG" >&2
            echo "-----------------------" >&2
            echo "" >&2
            echo "Error: Unable to open XYZ-file \"$XYZ_FILE\"." >&2
            echo "       (File is empty or does not exist.)" >&2
            exit 3
        fi
	#echo "  (extracting coordinates from \"$XYZ_FILE\")" >&2
	awk 'function isnum(x){return(x==x+0)} BEGIN{targetframe=1;framecount=0} {if (isnum($0)) {framecount++} else{if (framecount==targetframe){  if (NF>0) { if ((NF==3) && isnum($1)) {print $1" "$2" "$3} else if ((NF==4) && isnum($2)) {print $2" "$3" "$4} }}}}' < "$XYZ_FILE" > "$tmp_atom_coords"

    elif [ "$A" = "-pdb" ]; then 
        if [ "$i" -eq "$ARGC" ]; then
            echo "$SYNTAX_MSG" >&2
            exit 2
        fi
        i=$((i+1))
        eval A=\${ARGV${i}}
        PDB_FILE=$A
        if [ ! -s "$PDB_FILE" ]; then
            echo "$SYNTAX_MSG" >&2
            echo "-----------------------" >&2
            echo "" >&2
            echo "Error: Unable to open PDB-file \"$PDB_FILE\"." >&2
            echo "       (File is empty or does not exist.)" >&2
            exit 3
        fi
	#echo "  (extracting coordinates from \"$PDB_FILE\")" >&2
	if grep -q '^ATOM  \|^HETATM' "$PDB_FILE"; then
            # Extract the coords from the "ATOM" records in the PDB file
            pdbsort.py < "$PDB_FILE" | awk '/^ATOM  |^HETATM/{print substr($0,31,8)" "substr($0,39,8)" "substr($0,47,8)}' > "$tmp_atom_coords"
        else
            echo "$SYNTAX_MSG" >&2
            echo "-----------------------" >&2
            echo "" >&2
            echo "Error: File \"$PDB_FILE\" is not a valid PDB file." >&2
            exit 4
        fi
        # Now extract the periodic bounding-box informatio from the PDB file
        # The CRYST1 records are described at:
        # http://deposit.rcsb.org/adit/docs/pdb_atom_format.html
	BOXSIZE_A=-1.0
	BOXSIZE_B=-1.0
	BOXSIZE_C=-1.0
	ALPHA=" 90.00"  #Note: The space before the number in " 90.00" is intentional.
	BETA=" 90.00"   #      Later we will check to see if the system is triclinic
	GAMMA=" 90.00"  #      by comparing these strings for equality with " 90.00"
        if grep -qF "CRYST1" "$PDB_FILE"; then
            BOXSIZE_A=`awk '/CRYST1/{print substr($0,8,8)}' < "$PDB_FILE"`
            BOXSIZE_B=`awk '/CRYST1/{print substr($0,17,8)}' < "$PDB_FILE"`
            BOXSIZE_C=`awk '/CRYST1/{print substr($0,26,8)}' < "$PDB_FILE"`
            ALPHA=`awk '/CRYST1/{print substr($0,35,6)}' < "$PDB_FILE"`
            BETA=`awk '/CRYST1/{print substr($0,42,6)}' < "$PDB_FILE"`
            GAMMA=`awk '/CRYST1/{print substr($0,49,6)}' < "$PDB_FILE"`
        fi
        if [ `echo "$ALPHA!=90.0"|bc` -eq 1 ] || [ `echo "$BETA!=90.0"|bc` -eq 1 ] || [ `echo "$GAMMA!=90.0"|bc` -eq 1 ]; then
            # I transform the parameters from one format to the other by inverting
            # the transformation formula from the LAMMPS documentation (which matches
            # http://www.ccl.net/cca/documents/molecular-modeling/node4.html)
            # Disclaimer:
            # As of September 2012, I have not tested the code below. I think the
            # equations are correct, but I don't know if their are special cases 
            # that require the coordinates to be rotated or processed beforehand.
            # This is an experimental feature.
	    TRICLINIC="True"
	    PI=3.1415926535897931
	    BOXSIZE_X=$BOXSIZE_A
	    BOXSIZE_Y=`awk "BEGIN{print $BOXSIZE_B*sin($GAMMA*$PI/180.0)}"`
	    BOXSIZE_XY=`awk "BEGIN{print $BOXSIZE_B*cos($GAMMA*$PI/180.0)}"`
	    BOXSIZE_XZ=`awk "BEGIN{print $BOXSIZE_C*cos($BETA*$PI/180.0)}"`
	    BOXSIZE_YZ=`awk "BEGIN{ca=cos($ALPHA*$PI/180.0); cb=cos($BETA*$PI/180.0); cg=cos($GAMMA*$PI/180.0); sg=sin($GAMMA*$PI/180.0); c=$BOXSIZE_C; print c*(ca-(cg*cb))/sg}"`
	    BOXSIZE_Z=`awk "BEGIN{print sqrt(($BOXSIZE_C**2)-(($BOXSIZE_XZ**2)+($BOXSIZE_YZ**2)))}"`
        else
	    BOXSIZE_X=$BOXSIZE_A
	    BOXSIZE_Y=$BOXSIZE_B
	    BOXSIZE_Z=$BOXSIZE_C
	    BOXSIZE_XY=0.0
	    BOXSIZE_XZ=0.0
	    BOXSIZE_YZ=0.0
	fi
	BOXSIZE_MINX=0.0
	BOXSIZE_MINY=0.0
	BOXSIZE_MINZ=0.0
	BOXSIZE_MAXX=$BOXSIZE_X
	BOXSIZE_MAXY=$BOXSIZE_Y
	BOXSIZE_MAXZ=$BOXSIZE_Z

    #else:  If the arguments are not understood in this script, then
    #       pass them on to "ettree.py"
    elif [ "$i" -lt "$ARGC" ]; then
	if [ -z "$TTREE_ARGS" ]; then
	    TTREE_ARGS="\"$A\""
        else
            TTREE_ARGS="${TTREE_ARGS} \"$A\""
        fi
    fi
done





# --------------------------------------------------------------------
# --- Now run ttree/ettree to generate the file fragments we need. ---
# ------  (Afterwards, we will paste these fragments together.)  -----
# --------------------------------------------------------------------


# COMMENTING OUT.  NO ERROR CHECKING YET (-Andrew 2012-10-11)
#
# If checking is not disabled, then first check for common spelling errors.
#
#if [ -n "$TTREE_CHECK_COMMAND" ]; then
#    #if ! "$TTREE_CHECK_COMMAND" "$TTREE_FILE"; then
#    if ! eval $TTREE_CHECK_COMMAND $TTREE_ARGS; then
#        exit 1
#    fi
#fi


#   --- Run ttree. ---
#
# 3, 2, 1, ...

if ! eval "$TTREE_COMMAND" $TTREE_ARGS "$ETFILE"; then
    exit 1
fi

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# > Traceback (most recent call last):
# >   File "./ttree.py", line...
#            .-.
#           (0.0)
#         '=.|m|.='
#         .='`"``=.
#
# Hopefully this does not happen.
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!




# Attempt to remove any the DOS return-cairrage characters
# from inside the standard LAMMPS files generated by the user:
# (Users are free to put whatever weird characters they want in other
#  (custom) auxilliary files.  But not in the standard LAMMPS files.)
OIFS=$IFS
#IFS=$'\n'
IFS="
"
for file in $MOLTEMPLATE_TEMP_FILES; do
    if [ -e "$file" ]; then
        #dos2unix < "$file" > "$file.dos2unix"
        tr -d '\r' < "$file" > "$file.dos2unix"
        rm -f "$file" >/dev/null 2>&1 || true
	mv -f "$file.dos2unix" "$file"
    fi
done
IFS=$OIFS



# ---------------- Interactions By Type -----------------
# At the time of writing, bonded-interactions-by-atom-type were not 
# understood by ESPresSo.  These features require auxilliary python scripts.
# These data sections must be processed before everything else (because
# they effect the other data sections, and the ttree_assignments.txt file.)
# -------------------------------------------------------

if [ -s "${data_bond_list}.template" ]; then

    if [ ! -s "$data_bonds_by_type" ]; then
        echo "Error: You have a \"Data Bond List\", section somewhere\n"
        echo "       without a \"Data Bonds By Type\" section to support it.\n"
        echo "       (Did you mean to use \"Data Bonds\" instead?)\n"
        echo "Details:"
        echo "       Unlike the \"Data Bonds\" section, the \"Data Bond List\" section\n"
        echo "       allows the user to omit the bond types.  Instead emoltemplate attempts\n"
        echo "       to infer the type of bond by considering the pair of atom types.\n"
        echo "       However you must define a \"Data Bonds By Type\" section\n"
        echo "       to make this feature work (or use \"Data Bonds\" instead).\n"

        exit 15
    fi


    if ! $PYTHON_COMMAND "${SCRIPT_DIR}/extract_espresso_atom_types.py" \
        < "${data_atoms}.template" \
        > "${data_atoms}.template.minimal"; then
	exit 4
    fi

    # Note: The 3 lines above are usually equivalent to:
    #awk '{print $2" "$8}' \
    #    < "${data_atoms}.template" \
    #    > "${data_atoms}.template.minimal"
    awk '{print NR" "$1" "$2}' \
        < "${data_bond_list}.template" \
        > "${data_bond_list}.template.minimal"

    echo "Looking up bond types according to atom type" >&2
    #-- Generate a file containing bondid bondtype atomid1 atomid2 --
    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/bonds_by_type.py" \
            -atom-style "id type" \
            -atoms "${data_atoms}.template.minimal" \
            -bond-list "${data_bond_list}.template.minimal" \
            -bondsbytype "${data_bonds_by_type}.template" \
            -prefix '$/bond:b_bytype' > gen_bonds.template.minimal.tmp; then
        exit 4
    #WARNING: DO NOT REPLACE THIS WITH
    #if ! $NBODY_COMMAND ...<-this sometimes causes a shell quotes-related error
    fi

    rm "${data_atoms}.template.minimal"
    rm "${data_bond_list}.template.minimal"

    awk '{print "part "$3" bond "$2" "$4}' \
        < gen_bonds.template.minimal.tmp  \
        > gen_bonds.template.tmp

    # ---- cleanup: ----
    # ---- Create or re-build the "${data_bonds}.template" file ----
    # Instert these lines into the "${data_bonds}.template" file which includes
    # the newly generated interactions. (Note: these are in .template format)

    cp gen_bonds.template.tmp new_bonds.template.tmp
    if [ -s "${data_bonds}.template" ]; then
        # Then append existing "Bonds" to the end of the generated interactions
        # (Hopefully this way they will override those interactions.)
        cat "${data_bonds}.template" >> new_bonds.template.tmp 
    fi
    mv -f new_bonds.template.tmp "${data_bonds}.template"

    #  ------  THE NEXT STEP IS NOT CURRENTLY NEEDED ------
    # All of the $bond variables have already been created, they just lack types
    # However we will need to do this if the user wants to omits the bond-ids.
    # In case I plan to allow the user to omit bond-ids, I leave this code here.
    #
    #echo "(Repairing ttree_assignments.txt file after bonds added.)" >&2
    #
    ## ---- Repair the ttree_assignments.txt file ----
    ## The next 2 lines extract the variable names from data_new.template.tmp
    ## and instert them into the appropriate place in ttree_assignments.txt 
    ## (renumbering the relevant variable-assignments to avoid clashes).
    #if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/nbody_fix_ttree_assignments.py" \
    #      '/bond' gen_bonds.template.tmp \
    #      < ttree_assignments.txt \
    #      > ttree_assignments.tmp; then
    #    exit 5
    #fi
    #
    #echo "(Rendering ttree_assignments.tmp file after bonds added.)" >&2
    #mv -f ttree_assignments.tmp ttree_assignments.txt
    #  ----------------------------------------------------



    # ---- Re-build (render) the "$data_bonds" file ----
    # Now substitute these variable values (assignments) into the variable 
    # names present in the .template file.  (We want to convert the file from 
    # a .template format into an ordinary (numeric) LAMMPS data-section format.)

    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/ttree_render.py" \
           ttree_assignments.txt \
           < "${data_bonds}.template" \
           > "$data_bonds"; then
        exit 6
    fi

    echo "" >&2

    rm -f gen_bonds.template*.tmp new_bonds.template*.tmp 
fi







for FILE in "$data_angles_by_type"*.template; do
    if [ ! -s "$FILE" ] || [ ! -s "$data_bonds" ]; then
        break;  # This handles with the special cases that occur when 
                # 1) There are no bonds in your system
                # 2) "$data_angles_by_type"*.template matches nothing
    fi

    echo "Generating 3-body angle interactions by atom/bond type" >&2

    # Extract the text between parenthesis (if present, empty-str otherwise)
    # Example: FILE="Data Angles By Type (gaff_angle.py)"
    SUBGRAPH_SCRIPT=`echo "$FILE" | awk '/\(.*\)/ {print $0}' | cut -d'(' -f2-| cut -d')' -f 1`
    # Example: (continued) SUBGRAPH_SCRIPT should equal "gaff_angle.py"

    if [ -z "$SUBGRAPH_SCRIPT" ]; then
        SUBGRAPH_SCRIPT="nbody_Angles.py"
    else
        echo "(using the rules in \"$SUBGRAPH_SCRIPT\")" >&2
        #if [ ! -s "${MOLTEMPLATE_SCRIPT_DIR}/nbody_alt_symmetry/$SUBGRAPH_SCRIPT" ]; then
        #    echo "Error: File \"$SUBGRAPH_SCRIPT\" not found.\n" >&2
	#    echo "       It should be located in this directory:\n" >&2
        #    echo "       ${MOLTEMPLATE_SCRIPT_DIR}/nbody_alt_symmetry/\n" >&2
        #    exit 4
        #fi
    fi

    #-- Generate a file containing the list of interactions on separate lines --

    # The first step is to strip out the espresso-specific junk from each
    # section so we end up with a simple multi-column file containing only 
    # the symbols we care about (which identify atom ids, atom and bond types)
    if ! $PYTHON_COMMAND "${SCRIPT_DIR}/extract_espresso_atom_types.py" \
        < "${data_atoms}.template" \
        > "${data_atoms}.template.minimal"; then
	exit 4
    fi
    # Note: The 3 lines above are usually equivalent to:
    #awk '{print $2" "$8}' \
    #    < "${data_atoms}.template" \
    #    > "${data_atoms}.template.minimal"
    awk '{print NR" "$4" "$2" "$5}' \
        < "${data_bonds}.template" \
        > "${data_bonds}.template.minimal"

    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/nbody_by_type.py" \
            -subgraph "${SUBGRAPH_SCRIPT}" \
            -section "Angles" \
            -sectionbytype "Angles By Type" \
            -atom-style "id type" \
            -atoms "${data_atoms}.template.minimal" \
            -bonds "${data_bonds}.template.minimal" \
            -nbodybytype "${FILE}" \
            -prefix '$/bond:a_bytype' > gen_angles.template.minimal.tmp; then
        exit 4
    #WARNING: DO NOT REPLACE THIS WITH
    #if ! $NBODY_COMMAND ...<-this sometimes causes a shell quotes-related error
    fi


    # Then put the espresso-specific syntax back in:
    awk '{print "part "$4" bond "$2" "$3" "$5}' \
        < gen_angles.template.minimal.tmp  \
        > gen_angles.template.tmp
    # (See this section from the espresso manual "5.5. Bond-angle interactions")


    # ---- cleanup: ----
    # ---- Re-build the "${data_angles}.template" file ----
    # Instert these lines into the "${data_angles}.template" file which includes
    # the newly generated interactions. (Note: these are in .template format)

    cp gen_angles.template.tmp new_angles.template.tmp
    if [ -s "${data_angles}.template" ]; then
        # Then append existing "Angles" to the end of the generated interactions
        # (Hopefully this way they will override those interactions.)
        cat "${data_angles}.template" >> new_angles.template.tmp 
    fi
    mv -f new_angles.template.tmp "${data_angles}.template"

    ###  THE FOLLOWING STEPS ARE NOT NEEDED  ###
    # (Espresso does not ask us to supply unique ID numbers for each
    #  bonded interaction, so we don't generate counter-variables for
    #  them, and we don't need to update the ttree_assignments.txt file.)
    ###  COMMENTING OUT OLD LAMMPS-SPECIFIC CODE ###
    #echo "(Repairing ttree_assignments.txt file after angles added.)" >&2
    #
    ## ---- Repair the ttree_assignments.txt file ----
    ## The next 2 lines extract the variable names from data_new.template.tmp
    ## and instert them into the appropriate place in ttree_assignments.txt 
    ## (renumbering the relevant variable-assignments to avoid clashes).
    #if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/nbody_fix_ttree_assignments.py" \
    #      '/angle' gen_angles.template.tmp \
    #      < ttree_assignments.txt \
    #      > ttree_assignments.tmp; then
    #    exit 5
    #fi

    echo "(Rendering \"$data_angles\" section after angles added.)" >&2
    
    # ---- Re-build (render) the "$data_angles" file ----
    # Now substitute these variable values (assignments) into the variable 
    # names present in the .template file.  (We want to convert the file from 
    # a .template format into an ordinary (numeric) LAMMPS data-section format)
    
    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/ttree_render.py" \
           ttree_assignments.txt \
           < "$data_angles.template" \
           > "$data_angles"; then
        exit 6
    fi
    echo "" >&2

    rm -f gen_angles.template*.tmp new_angles.template*.tmp 
done






for FILE in "$data_dihedrals_by_type"*.template; do
    if [ ! -s "$FILE" ] || [ ! -s "$data_bonds" ]; then
        break;  # This handles with the special cases that occur when 
                # 1) There are no bonds in your system
                # 2) "$data_dihedrals_by_type"*.template matches nothing
    fi

    echo "Generating 4-body dihedral interactions by atom/bond type" >&2

    # Extract the text between parenthesis (if present, empty-str otherwise)
    # Example: FILE="Data Dihedrals By Type (gaff_dih.py)"
    SUBGRAPH_SCRIPT=`echo "$FILE" | awk '/\(.*\)/ {print $0}' | cut -d'(' -f2-| cut -d')' -f 1`
    # Example: (continued) SUBGRAPH_SCRIPT should equal "gaff_dih.py"

    if [ -z "$SUBGRAPH_SCRIPT" ]; then
        SUBGRAPH_SCRIPT="nbody_Dihedrals.py"
    else
        echo "(using the rules in \"$SUBGRAPH_SCRIPT\")" >&2
        #if [ ! -s "${MOLTEMPLATE_SCRIPT_DIR}/nbody_alt_symmetry/$SUBGRAPH_SCRIPT" ]; then
        #    echo "Error: File \"$SUBGRAPH_SCRIPT\" not found.\n" >&2
	#    echo "       It should be located in this directory:\n" >&2
        #    echo "       ${MOLTEMPLATE_SCRIPT_DIR}/nbody_alt_symmetry/\n" >&2
        #    exit 4
        #fi
    fi

    #-- Generate a file containing the list of interactions on separate lines --

    # The first step is to strip out the espresso-specific junk from each
    # section so we end up with a simple multi-column file containing only 
    # the symbols we care about (which identify atom ids, atom and bond types)
    if ! $PYTHON_COMMAND "${SCRIPT_DIR}/extract_espresso_atom_types.py" \
        < "${data_atoms}.template" \
        > "${data_atoms}.template.minimal"; then
	exit 4
    fi
    # Note: The 3 lines above are usually equivalent to:
    #awk '{print $2" "$8}' \
    #    < "${data_atoms}.template" \
    #    > "${data_atoms}.template.minimal"
    awk '{print NR" "$4" "$2" "$5}' \
        < "${data_bonds}.template" \
        > "${data_bonds}.template.minimal"

    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/nbody_by_type.py" \
            -subgraph "${SUBGRAPH_SCRIPT}" \
            -section "Dihedrals" \
            -sectionbytype "Dihedrals By Type" \
            -atom-style "id type" \
            -atoms "${data_atoms}.template.minimal" \
            -bonds "${data_bonds}.template.minimal" \
            -nbodybytype "${FILE}" \
            -prefix '$/bond:d_bytype' > gen_dihedrals.template.minimal.tmp; then
        exit 4
    #WARNING: DO NOT REPLACE THIS WITH
    #if ! $NBODY_COMMAND ...<-this sometimes causes a shell quotes-related error
    fi


    # Then put the espresso-specific syntax back in:
    awk '{print "part "$4" bond "$2" "$3" "$5" "$6}' \
        < gen_dihedrals.template.minimal.tmp  \
        > gen_dihedrals.template.tmp
    # (See this section from the espresso manual "5.6. Dihedral interactions")


    # ---- cleanup: ----
    # ---- Re-build the "${data_dihedrals}.template" file ----
    # Instert these lines into the "${data_dihedrals}.template" file which includes
    # the newly generated interactions. (Note: these are in .template format)

    cp gen_dihedrals.template.tmp new_dihedrals.template.tmp
    if [ -s "${data_dihedrals}.template" ]; then
        # Then append existing "Dihedrals" to the end of the generated interactions
        # (Hopefully this way they will override those interactions.)
        cat "${data_dihedrals}.template" >> new_dihedrals.template.tmp 
    fi
    mv -f new_dihedrals.template.tmp "${data_dihedrals}.template"

    ###  THE FOLLOWING STEPS ARE NOT NEEDED  ###
    # (Espresso does not ask us to supply unique ID numbers for each
    #  bonded interaction, so we don't generate counter-variables for
    #  them, and we don't need to update the ttree_assignments.txt file.)
    ###  COMMENTING OUT OLD LAMMPS-SPECIFIC CODE ###
    #echo "(Repairing ttree_assignments.txt file after dihedrals added.)" >&2
    #
    ## ---- Repair the ttree_assignments.txt file ----
    ## The next 2 lines extract the variable names from data_new.template.tmp
    ## and instert them into the appropriate place in ttree_assignments.txt 
    ## (renumbering the relevant variable-assignments to avoid clashes).
    #if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/nbody_fix_ttree_assignments.py" \
    #      '/dihedral' gen_dihedrals.template.tmp \
    #      < ttree_assignments.txt \
    #      > ttree_assignments.tmp; then
    #    exit 5
    #fi

    echo "(Rendering \"$data_dihedrals\" section after dihedrals added.)" >&2
    
    # ---- Re-build (render) the "$data_dihedrals" file ----
    # Now substitute these variable values (assignments) into the variable 
    # names present in the .template file.  (We want to convert the file from 
    # a .template format into an ordinary (numeric) LAMMPS data-section format)
    
    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/ttree_render.py" \
           ttree_assignments.txt \
           < "$data_dihedrals.template" \
           > "$data_dihedrals"; then
        exit 6
    fi
    echo "" >&2
    
    rm -f gen_dihedrals.template*.tmp new_dihedrals.template*.tmp 
done









for FILE in "$data_impropers_by_type"*.template; do
    if [ ! -s "$FILE" ] || [ ! -s "$data_bonds" ]; then
        break;  # This handles with the special cases that occur when 
                # 1) There are no bonds in your system
                # 2) "$data_impropers_by_type"*.template matches nothing
    fi

    echo "Generating 4-body improper interactions by atom/bond type" >&2

    # Extract the text between parenthesis (if present, empty-str otherwise)
    # Example: FILE="Data Impropers By Type (gaff_dih.py)"
    SUBGRAPH_SCRIPT=`echo "$FILE" | awk '/\(.*\)/ {print $0}' | cut -d'(' -f2-| cut -d')' -f 1`
    # Example: (continued) SUBGRAPH_SCRIPT should equal "gaff_dih.py"

    if [ -z "$SUBGRAPH_SCRIPT" ]; then
        SUBGRAPH_SCRIPT="nbody_Impropers.py"
    else
        echo "(using the rules in \"$SUBGRAPH_SCRIPT\")" >&2
        #if [ ! -s "${MOLTEMPLATE_SCRIPT_DIR}/nbody_alt_symmetry/$SUBGRAPH_SCRIPT" ]; then
        #    echo "Error: File \"$SUBGRAPH_SCRIPT\" not found.\n" >&2
	#    echo "       It should be located in this directory:\n" >&2
        #    echo "       ${MOLTEMPLATE_SCRIPT_DIR}/nbody_alt_symmetry/\n" >&2
        #    exit 4
        #fi
    fi

    #-- Generate a file containing the list of interactions on separate lines --

    # The first step is to strip out the espresso-specific junk from each
    # section so we end up with a simple multi-column file containing only 
    # the symbols we care about (which identify atom ids, atom and bond types)
    if ! $PYTHON_COMMAND "${SCRIPT_DIR}/extract_espresso_atom_types.py" \
        < "${data_atoms}.template" \
        > "${data_atoms}.template.minimal"; then
	exit 4
    fi
    # Note: The 3 lines above are usually equivalent to:
    #awk '{print $2" "$8}' \
    #    < "${data_atoms}.template" \
    #    > "${data_atoms}.template.minimal"
    awk '{print NR" "$4" "$2" "$5}' \
        < "${data_bonds}.template" \
        > "${data_bonds}.template.minimal"

    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/nbody_by_type.py" \
            -subgraph "${SUBGRAPH_SCRIPT}" \
            -section "Impropers" \
            -sectionbytype "Impropers By Type" \
            -atom-style "id type" \
            -atoms "${data_atoms}.template.minimal" \
            -bonds "${data_bonds}.template.minimal" \
            -nbodybytype "${FILE}" \
            -prefix '$/bond:i_bytype' > gen_impropers.template.minimal.tmp; then
        exit 4

    #WARNING: DO NOT REPLACE THIS WITH
    #if ! $NBODY_COMMAND ...<-this sometimes causes a shell quotes-related error
    fi


    # Then put the espresso-specific syntax back in:
    awk '{print "part "$4" bond "$2" "$3" "$5" "$6}' \
        < gen_impropers.template.minimal.tmp  \
        > gen_impropers.template.tmp
    # (See this section from the espresso manual "5.6. Improper interactions")


    # ---- cleanup: ----
    # ---- Re-build the "${data_impropers}.template" file ----
    # Instert these lines into the "${data_impropers}.template" file which includes
    # the newly generated interactions. (Note: these are in .template format)

    cp gen_impropers.template.tmp new_impropers.template.tmp
    if [ -s "${data_impropers}.template" ]; then
        # Then append existing "Impropers" to the end of the generated interactions
        # (Hopefully this way they will override those interactions.)
        cat "${data_impropers}.template" >> new_impropers.template.tmp 
    fi
    mv -f new_impropers.template.tmp "${data_impropers}.template"


    ###  THE FOLLOWING STEPS ARE NOT NEEDED  ###
    # (Espresso does not ask us to supply unique ID numbers for each
    #  bonded interaction, so we don't generate counter-variables for
    #  them, and we don't need to update the ttree_assignments.txt file.)
    ###  COMMENTING OUT OLD LAMMPS-SPECIFIC CODE ###
    #echo "(Repairing ttree_assignments.txt file after impropers added.)" >&2
    #
    ## ---- Repair the ttree_assignments.txt file ----
    ## The next 2 lines extract the variable names from data_new.template.tmp
    ## and instert them into the appropriate place in ttree_assignments.txt 
    ## (renumbering the relevant variable-assignments to avoid clashes).
    #if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/nbody_fix_ttree_assignments.py" \
    #      '/improper' gen_impropers.template.tmp \
    #      < ttree_assignments.txt \
    #      > ttree_assignments.tmp; then
    #    exit 5
    #fi
    
    echo "(Rendering \"$data_impropers\" section after impropers added.)" >&2

    # ---- Re-build (render) the "$data_impropers" file ----
    # Now substitute these variable values (assignments) into the variable 
    # names present in the .template file.  (We want to convert the file from 
    # a .template format into an ordinary (numeric) LAMMPS data-section format)
    
    if ! $PYTHON_COMMAND "${MOLTEMPLATE_SCRIPT_DIR}/ttree_render.py" \
           ttree_assignments.txt \
           < "$data_impropers.template" \
           > "$data_impropers"; then
        exit 6
    fi
    echo "" >&2
    
    rm -f gen_impropers.template*.tmp new_impropers.template*.tmp 
done











#NATOMTYPES=`awk '/^@\/atom:/{n++}END{print n}' < ttree_assignments.txt`
#NBONDTYPES=`awk '/^@\/bond:/{n++}END{print n}' < ttree_assignments.txt`
#NANGLETYPES=`awk '/^@\/angle:/{n++}END{print n}' < ttree_assignments.txt`
#NDIHEDRALTYPES=`awk '/^@\/dihedral:/{n++}END{print n}' < ttree_assignments.txt`
#NIMPROPERTYPES=`awk '/^@\/improper:/{n++}END{print n}' < ttree_assignments.txt`
#NBONDTYPES=`awk '/^@\/bond:/{n++}END{print n}' < ttree_assignments.txt`
#NANGLETYPES=`awk '/^@\/bond:/{n++}END{print n}' < ttree_assignments.txt`
#NDIHEDRALTYPES=`awk '/^@\/bond:/{n++}END{print n}' < ttree_assignments.txt`
#NIMPROPERTYPES=`awk '/^@\/bond:/{n++}END{print n}' < ttree_assignments.txt`

#echo "  (debug msg: NATOMTYPES=$NATOMTYPES)"  >&2
#echo "  (debug msg: NBONDTYPES=$NBONDTYPES)"  >&2
#echo "  (debug msg: NANGLETYPES=$NANGLETYPES)"  >&2
#echo "  (debug msg: NDIHEDRALTYPES=$NDIHEDRALTYPES)"  >&2
#echo "  (debug msg: NIMPROPERTYPES=$NIMPROPERTYPES)"  >&2

#NATOMS=`awk '/^\$\/atom:/{n++}END{print n}' < ttree_assignments.txt`
#NBONDS=`awk '/^\$\/bond:/{n++}END{print n}' < ttree_assignments.txt`
#NANGLES=`awk '/^\$\/angle:/{n++}END{print n}' < ttree_assignments.txt`
#NDIHEDRALS=`awk '/^\$\/dihedral:/{n++}END{print n}' < ttree_assignments.txt`
#NIMPROPERS=`awk '/^\$\/improper:/{n++}END{print n}' < ttree_assignments.txt`
#NBONDS=`awk '/^\$\/bond:/{n++}END{print n}' < ttree_assignments.txt`
#NANGLES=`awk '/^\$\/bond:a_/{n++}END{print n}' < ttree_assignments.txt`
#NDIHEDRALS=`awk '/^\$\/bond:d_/{n++}END{print n}' < ttree_assignments.txt`
#NIMPROPERS=`awk '/^\$\/bond:i_/{n++}END{print n}' < ttree_assignments.txt`

#echo "  (debug msg: NATOMS=$NATOMS)"  >&2
#echo "  (debug msg: NBONDS=$NBONDS)"  >&2
#echo "  (debug msg: NANGLES=$NANGLES)"  >&2
#echo "  (debug msg: NDIHEDRALS=$NDIHEDRALS)"  >&2
#echo "  (debug msg: NIMPROPERS=$NIMPROPERS)"  >&2



if [ -s "$in_init" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# initial settings:" >> "$OUT_FILE_TCL"
    cat "$in_init" >> "$OUT_FILE_TCL"
fi




# --- PERIODIC BOUNDARY CONDITIONS ---

# Note: If there is a "$data_boundary" file present, it overrides any settings
#       which may have been stored in a pdb file or other external file.

if [ -s "$data_boundary" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# periodic boundary conditions:" >> "$OUT_FILE_TCL"
    cat "$data_boundary" >> "$OUT_FILE_TCL"

elif [ -z "$BOXSIZE_MINX" ] || [ -z "$BOXSIZE_MAXX" ] || [ -z "$BOXSIZE_MINY" ] || [ -z "$BOXSIZE_MAXY" ] || [ -z "$BOXSIZE_MINZ" ] || [ -z "$BOXSIZE_MAXZ" ]; then

    #echo "Periodic boundary conditions unspecified. Attempting to generate automatically." >&2

    # By default, disable triclinic
    BOXSIZE_XY=""
    BOXSIZE_XZ=""
    BOXSIZE_YZ=""
    TRICLINIC=""

    if [ -s "$tmp_atom_coords" ]; then
        # Estimate the minimimum, maximum x,y,z values
        # from the coordinate data.

	MINMAX_BOUNDS=`awk 'BEGIN{first=1}{if (NF>=3){x=$1; y=$2; z=$3; if (first) {first=0; xmin=x; xmax=x; ymin=y; ymax=y; zmin=z; zmax=z;} else {if (x<xmin) xmin=x; if (x>xmax) xmax=x; if (y<ymin) ymin=y; if (y>ymax) ymax=y; if (z<zmin) zmin=z; if (z>zmax) zmax=z;}}} END{print xmin" "xmax" "ymin" "ymax" "zmin" "zmax;}' < "$tmp_atom_coords"`

        # ...and add a narrow margin (10%) around the boundaries:
	BOXSIZE_MINX=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$2-$1; print $1-0.0*margin*width}"`
	BOXSIZE_MAXX=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$2-$1; print $2+1.0*margin*width}"`
	BOXSIZE_MINY=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$4-$3; print $3-0.0*margin*width}"`
	BOXSIZE_MAXY=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$4-$3; print $4+1.0*margin*width}"`
	BOXSIZE_MINZ=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$6-$5; print $5-0.0*margin*width}"`
	BOXSIZE_MAXZ=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$6-$5; print $6+1.0*margin*width}"`
    else
        # By default, choose some reasonably large box:
	BOXSIZE_MINX="0.0"
	BOXSIZE_MAXX="100.0"
	BOXSIZE_MINY="0.0"
	BOXSIZE_MAXY="100.0"
	BOXSIZE_MINZ="0.0"
	BOXSIZE_MAXZ="100.0"
	# ...and print message scolding the user for being lazy
	#echo "----------------------------------------------------------------------" >&2
        #echo "---- Warning: Unable to determine periodic boundary conditions.   ----" >&2
	#echo "----          This is probably okay.                              ----" >&2
	#echo "----------------------------------------------------------------------" >&2
    fi

elif [ -n $TRICLINIC ]; then
    echo "setmd box $BOXSIZE_MAXX $BOXSIZE_MAXY $BOXSIZE_MAXZ" >> "$OUT_FILE_TCL"
    echo "setmd periodic 1 1 1" >> "$OUT_FILE_TCL"
else
    # Otherwise, this is a triclinic (non orthoganal) crystal basis.
    echo "Error: Triclinic boundary conditions are not yet supported." >&2
    echo "       (If you are reading a PDB file with periodic-boundary" >&2
    echo "        information, such as a CRYST1 record, then either" >&2
    echo "        delete that line from the PDB file, or change the" >&2
    echo "        three angles to 90.000 degress.)" >&2
    exit 7
fi
echo "" >> "$OUT_FILE_TCL"


if [ -s "$data_pair_coeffs" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# non-bonded force-field parameters:" >> "$OUT_FILE_TCL"
    cat "$data_pair_coeffs" >> "$OUT_FILE_TCL"
fi


if [ -s "$data_bond_coeffs" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# 2-body bonded force-field parameters:" >> "$OUT_FILE_TCL"
    cat "$data_bond_coeffs" >> "$OUT_FILE_TCL"
#else
#    if [ -n "$NBONDTYPES" ] && ( [ ! -s "$in_settings" ] || (! grep -q bond_coeff "$in_settings") ); then
#	echo "WARNING: no bond coeff have been set!" >&2
#    fi
fi


if [ -s "$data_angle_coeffs" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# 3-body angle force-field parameters:" >> "$OUT_FILE_TCL"
    cat "$data_angle_coeffs" >> "$OUT_FILE_TCL"
#else
#    if [ -n "$NANGLETYPES" ] && ( [ ! -s "$in_settings" ] || (! grep -q angle_coeff "$in_settings") ); then
#	echo "WARNING: no angle coeff have been set!" >&2
#    fi
fi


if [ -s "$data_dihedral_coeffs" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# 4-body dihedral force-field parameters:" >> "$OUT_FILE_TCL"
    cat "$data_dihedral_coeffs" >> "$OUT_FILE_TCL"
#else
#    if [ -n "$NDIHEDRALTYPES" ] && ( [ ! -s "$in_settings" ] || (! grep -q dihedral_coeff "$in_settings") ); then
#	echo "WARNING: no dihedral coeffs have been set!" >&2
#    fi
fi


if [ -s "$data_improper_coeffs" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# 4-body improper force-field parameters:" >> "$OUT_FILE_TCL"
    cat "$data_improper_coeffs" >> "$OUT_FILE_TCL"
#else
#    if [ -n "$NIMPROPERTYPES" ] && ( [ ! -s "$in_settings" ] || (! grep -q improper_coeff "$in_settings") ); then
#	echo "WARNING: no improper coeffs have been set!" >&2
#    fi
fi


if [ -s "$in_settings" ]; then
    echo "# force field parameters / run settings:" >> "$OUT_FILE_TCL"
    cat "$in_settings" >> "$OUT_FILE_TCL"
fi


if [ -s "$data_atoms" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# atom list:" >> "$OUT_FILE_TCL"
    cat "$data_atoms" >> "$OUT_FILE_TCL"
fi


if [ -s "$tmp_atom_coords" ]; then
    rm -f "$OUT_FILE_COORDS"
    awk 'BEGIN{natom=0} {if (NF>=3) {print "part " natom " pos " $1 " " $2 " " $3; natom++}}' < "$tmp_atom_coords" >> "$OUT_FILE_TCL"
    NATOMS=`awk '/^\\\$\/atom:/{n++}END{print n}' < ttree_assignments.txt`
    NATOMCRDS=`awk '{if (NF>=3) natom+=1} END{print(natom)}' < "$tmp_atom_coords"`
    if [ $NATOMS -ne $NATOMCRDS ]; then 
        echo "Error: Number of atoms in coordinate file provided by user ($NATOMCRDS)" >&2
	echo "does not match the number of atoms generated in ttree file ($NATOMS)" >&2
        exit 6
    fi
fi

if [ -s "$data_bonds" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# bonds:" >> "$OUT_FILE_TCL"
    cat "$data_bonds" >> "$OUT_FILE_TCL"
fi

if [ -s "$data_angles" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# 3-body angle interactions:" >> "$OUT_FILE_TCL"
    cat "$data_angles" >> "$OUT_FILE_TCL"
fi

if [ -s "$data_dihedrals" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# 4-body dihedral interactions:" >> "$OUT_FILE_TCL"
    cat "$data_dihedrals" >> "$OUT_FILE_TCL"
fi

if [ -s "$data_impropers" ]; then
    echo "" >> "$OUT_FILE_TCL"
    echo "# 4-body improper interactions:" >> "$OUT_FILE_TCL"
    cat "$data_impropers" >> "$OUT_FILE_TCL"
fi


# ############## CLEAN UP ################

# A lot of files have been created along the way. 
# However only a few of them are actually useful. 
#
# Optional: clean up some non-essential temporary 
#           files created by running ttree
# We move the non-essential files into a different directory
# (but we don't delete them).

if [ ! -d output_ttree ]; then
    mkdir output_ttree
fi

rm -f "${data_atoms}.template.minimal" "${data_bonds}.template.minimal"

# Move temporary files into the "output_ttree/" directory:
OIFS=$IFS
#IFS=$'\n'
IFS="
"
for file in $MOLTEMPLATE_TEMP_FILES; do
    #echo "file=\"$file\""
    rm -f "output_ttree/$file" >/dev/null 2>&1 || true
    mv "$file" output_ttree/ >/dev/null 2>&1 || true
done
IFS=$OIFS
