#!/bin/sh

# Author: Andrew Jewett (jewett.aij at g mail)
#         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="moltemplate.sh"
G_VERSION="1.01"
G_DATE="2012-12-15"

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


# First, determine the directory in which this shell script is located.
# (The python script files should also be located here as well.)
SCRIPT_DIR=$(dirname $0)


# Check for python:
# I prefer python over python3 because python3 requires 
# more memory.  Just use regular python 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


IMOLPATH=""
if [ -n "${MOLTEMPLATE_PATH}" ]; then
  IMOLPATH="-importpath ${MOLTEMPLATE_PATH}"
fi

# command that invokes lttree.py
LTTREE_COMMAND="$PYTHON_COMMAND ${SCRIPT_DIR}/lttree.py ${IMOLPATH}"

# command that invokes lttree_check.py
LTTREE_CHECK_COMMAND="$PYTHON_COMMAND ${SCRIPT_DIR}/lttree_check.py ${IMOLPATH}"

# command that invokes lttree_postprocess.py
LTTREE_POSTPROCESS_COMMAND="$PYTHON_COMMAND ${SCRIPT_DIR}/lttree_postprocess.py ${IMOLPATH}"

# command that invokes nbody_by_type.py
NBODY_COMMAND="$PYTHON_COMMAND ${SCRIPT_DIR}/nbody_by_type.py"

# command that invokes nbody_fix_ttree_assignments.py
NBODY_FIX_COMMAND="$PYTHON_COMMAND ${SCRIPT_DIR}/nbody_fix_ttree_assignments.py"

# command that invokes ttree_render.py
TTREE_RENDER="$PYTHON_COMMAND ${SCRIPT_DIR}/ttree_render.py"


# What is the name of the .LT 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 .lt or .LT
# If so, then set the base name of the output files
# to equal the base name of the .LT file being read.
# (Being careful here.
#  Sometimes the last argument is not the .lt or .LT 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/%.lt/}" -neq "$LAST_ARG" ]; then
#     OUT_FILE_BASE="${LAST_ARG/%.lt/}"
# But in the original bourn shell (sh), this does not work. 
# Instead we use a hack involving basename and dirname:
LTFILE="$LAST_ARG"
LTFILE_DIR=`dirname "$LTFILE"`
LTFILE_BASE=`basename "$LTFILE" .lt`
LTFILE_NO_EXT="${LTFILE_DIR}/${LTFILE_BASE}"
OUT_FILE_BASE="system"
if [ "$LTFILE_NO_EXT" != "$LTFILE" ]; then
    OUT_FILE_BASE="$LTFILE_BASE"
else
    LTFILE_BASE=`basename "$LAST_ARG" .LT`
    LTFILE_NO_EXT="${LTFILE_DIR}/${LTFILE_BASE}"
    if [ "$LTFILE_NO_EXT" != "$LTFILE" ]; then
	OUT_FILE_BASE="$LTFILE_BASE"
    fi
fi
OUT_FILE_INPUT_SCRIPT="${OUT_FILE_BASE}.in"
OUT_FILE_INIT="${OUT_FILE_BASE}.in.init"
OUT_FILE_SETTINGS="${OUT_FILE_BASE}.in.settings"
OUT_FILE_DATA="${OUT_FILE_BASE}.data"
OUT_FILE_COORDS="${OUT_FILE_BASE}.in.coords"

rm -f "$OUT_FILE_INPUT_SCRIPT" "$OUT_FILE_INIT" "$OUT_FILE_SETTINGS" "$OUT_FILE_DATA" "$OUT_FILE_COORDS"


# -----------------------------------------------------------
# If everything worked, then running ttree usually 
# generates the following files:
#
# Users of lttree typically generate the following files:
# The variable below refer to file names generated by 
# write() and write_once() commands in a lttree-file.
# (I keep changing my mind what I want these names to be.)
data_prefix="Data "
data_prefix_no_space="Data"
data_header="Data Header"
data_atoms="Data Atoms"
data_masses="Data Masses"
data_velocities="Data Velocities"
data_bonds="Data Bonds"
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_angles_by_type="Data Angles By Type"
data_dihedrals_by_type="Data Dihedrals By Type"
data_impropers_by_type="Data Impropers By Type"

# class2 data sections
data_bondbond_coeffs="Data BondBond Coeffs"
data_bondangle_coeffs="Data BondAngle Coeffs"
data_middlebondtorsion_coeffs="Data MiddleBondTorsion Coeffs"
data_endbondtorsion_coeffs="Data EndBondTorsion Coeffs"
data_angletorsion_coeffs="Data AngleTorsion Coeffs"
data_angleangletorsion_coeffs="Data AngleAngleTorsion Coeffs"
data_bondbond13_coeffs="Data BondBond13 Coeffs"
data_angleangle_coeffs="Data AngleAngle Coeffs"

# sections for non-point-like particles:
data_ellipsoids="Data Ellipsoids"
data_lines="Data Lines"
data_triangles="Data Triangles"

# periodic boundary conditions
data_boundary="Data Boundary"
# (for backward compatibility), an older version of this file was named:
data_pbc="Data PBC"

# ---------------------------------------------------------------
# Note: The files above are fragments of a LAMMPS data file.
# In addition, moltemplate 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_masses
$data_pair_coeffs
$data_bond_coeffs
$data_angle_coeffs
$data_dihedral_coeffs
$data_improper_coeffs
$data_atoms
$data_velocities
$data_bonds
$data_angles
$data_dihedrals
$data_impropers
$data_bondbond_coeffs
$data_bondangle_coeffs
$data_middlebondtorsion_coeffs
$data_endbondtorsion_coeffs
$data_angletorsion_coeffs
$data_angleangletorsion_coeffs
$data_bondbond13_coeffs
$data_angleangle_coeffs
$data_ellipsoids
$data_lines
$data_triangles
$data_boundary
$data_angles_by_type
$data_dihedrals_by_type
$data_impropers_by_type
$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:

moltemplate.sh [-atomstyle style] \
               [-pdb/-xyz coord_file] \
               [-a assignments.txt] file.lt

Optional arguments:

-atomstyle style  By default, moltemplate.sh assumes you are using the "full"
                atom style in LAMMPS.  You can change the atom style to "dipole"
                using -atomstyle dipole.  If you are using a hybrid style, 
                you must enclose the list of styles in quotes.  For example:
                -atomstyle "hybrid full dipole"
                For custom atom styles, you can also specify the
                list of column names manually (enclosed in quotes):
                -atomstyle "molid x y z atomid atomtype mux muy muz"

-xyz xyz_file   An optional xyz_file argument can be supplied as an argument
                following "-xyz".
                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 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 moltemplat.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 moltemplate.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.
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 LTTREE_CHECK_COMMAND
	unset LTTREE_CHECK_COMMAND
	unset LTTREE_POSTPROCESS_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-dihdedrals" ]; 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" = "-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 "lttree.py"
    else
        if [ -z "$TTREE_ARGS" ]; then
	    TTREE_ARGS="\"$A\""
        else
            TTREE_ARGS="${TTREE_ARGS} \"$A\""
        fi
    fi
done








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





# If checking is not disabled, then first check for common spelling errors.

if [ -n "$LTTREE_CHECK_COMMAND" ]; then
    if ! eval $LTTREE_CHECK_COMMAND $TTREE_ARGS; then
        exit 1
    fi
fi


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

if ! eval $LTTREE_COMMAND $TTREE_ARGS; then
    exit 1
fi

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

echo "" >&2


if [ -s "${data_atoms}" ]; then
    remove_duplicate_atoms.py < "${data_atoms}" > "${data_atoms}.tmp"
    mv -f "${data_atoms}.tmp" "${data_atoms}"
    remove_duplicate_atoms.py < "${data_atoms}".template > "${data_atoms}.tmp"
    mv -f "${data_atoms}.tmp" "${data_atoms}".template
    renumber_DATA_first_column.py < ${data_atoms} > "${data_atoms}.tmp"
    mv -f "${data_atoms}.tmp" "${data_atoms}"
else
    echo "Error: There are no atoms in your system." >&2
    echo "" >&2
    echo "        Make sure that the object(s) you created are indeed molecules." >&2
    echo "        (Molecule objects must contain at least one" >&2
    echo "         write(\"${data_atoms}\") command.)" >&2
    echo "" >&2
    echo "       (This error often occurs if you instantiated an object" >&2
    echo "        which you thought was a molecule, but it is actually" >&2
    echo "        only a namespace, a force-field name or category" >&2
    echo "        containing the definitions of other molecules.)" >&2
    echo "" >&2
    exit 1
fi




# ---------------- Interactions By Type -----------------
# At the time of writing, bonded-interactions-by-atom-type were not
# understood by LAMMPS.  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_angles_by_type" ]; then
    echo "\nGenerating 3-body angle interactions by atom/bond type" >&2
    #-- Generate a file containing the list of interactions on separate lines --
    if ! $NBODY_COMMAND Angles \
        -atoms "${data_atoms}.template" \
        -bonds "${data_bonds}.template" \
        -nbodybytype "${data_angles_by_type}.template" \
	-prefix '$/angle:bytype' > gen_Angles.template.tmp; then
	exit 1
    fi

    # ---- 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"

    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 ! $NBODY_FIX_COMMAND '/angle' gen_Angles.template.tmp \
          < ttree_assignments.txt \
          > ttree_assignments.tmp; then
        exit 1
    fi

    echo "(Rendering ttree_assignments.tmp file 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 ! $TTREE_RENDER  ttree_assignments.tmp \
           < "${data_angles}.template" \
           > "$data_angles"; then
        exit 1
    fi

    mv -f ttree_assignments.tmp ttree_assignments.txt
    rm -f gen_Angles.template.tmp new_Angles.template.tmp 
fi



if [ -s "$data_dihedrals_by_type" ]; then
    echo "\nGenerating 4-body dihedral interactions by atom/bond type" >&2 
    #-- Generate a file containing the list of interactions on separate lines --
    if ! $NBODY_COMMAND Dihedrals \
        -atoms "${data_atoms}.template" \
        -bonds "${data_bonds}.template" \
        -nbodybytype "${data_dihedrals_by_type}.template" \
	-prefix '$/dihedral:bytype' > gen_Dihedrals.template.tmp; then
	exit 1
    fi
    # ---- 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 -f 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"

    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 ! $NBODY_FIX_COMMAND '/dihedral' gen_Dihedrals.template.tmp \
          < ttree_assignments.txt \
          > ttree_assignments.tmp; then
	exit 1
    fi

    echo "(Rendering ttree_assignments.tmp file after dihedral 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 ! $TTREE_RENDER  ttree_assignments.tmp \
           < "${data_dihedrals}.template" \
           > "$data_dihedrals"; then
	exit 1
    fi

    mv -f ttree_assignments.tmp ttree_assignments.txt
    rm -f gen_Dihedrals.template.tmp new_Dihedrals.template.tmp 
fi



if [ -s "$data_impropers_by_type" ]; then
    echo "Generating 4-body impropers interactions by atom/bond type" >&2
    #-- Generate a file containing the list of interactions on separate lines --
    if ! $NBODY_COMMAND Impropers \
        -atoms "${data_atoms}.template" \
        -bonds "${data_bonds}.template" \
        -nbodybytype "${data_impropers_by_type}.template" \
	-prefix '$/improper:bytype' > gen_Impropers.template.tmp; then
	exit 1
    fi
    # ---- 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"

    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 ! $NBODY_FIX_COMMAND '/improper' gen_Impropers.template.tmp \
          < ttree_assignments.txt \
          > ttree_assignments.tmp; then
	exit 1
    fi

    echo "(Rendering ttree_assignments.tmp file 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 ! $TTREE_RENDER  ttree_assignments.tmp \
           < "${data_impropers}.template" \
           > "$data_impropers"; then
	exit 1
    fi

    mv -f ttree_assignments.tmp ttree_assignments.txt
    rm -f gen_Impropers.template.tmp new_Impropers.template.tmp 
fi



if [ -n "$LTTREE_POSTPROCESS_COMMAND" ]; then
    echo "" >&2
    if ! eval $LTTREE_POSTPROCESS_COMMAND $TTREE_ARGS; then
        exit 1
    fi
    echo "" >&2
fi


# -------------------------------------------------------
# If present, then remove duplicate bonds, angles, dihedrals, and impropers
# (unless overridden by the user).
# -------------------------------------------------------


if [ -s "${data_masses}" ]; then
    remove_duplicate_atoms.py < "${data_masses}" > "${data_masses}.tmp"
    mv -f "${data_masses}.tmp" "${data_masses}" 
fi



if [ -s "${data_bonds}" ]; then
    if [ ! -z $REMOVE_DUPLICATE_BONDS ]; then
        remove_duplicates_nbody.py 2 < "${data_bonds}" > "${data_bonds}.tmp"
        mv "${data_bonds}.tmp" "${data_bonds}"
        remove_duplicates_nbody.py 2 < "${data_bonds}".template > "${data_bonds}.tmp"
        mv "${data_bonds}.tmp" "${data_bonds}".template
    fi
    renumber_DATA_first_column.py < ${data_bonds} > "${data_bonds}.tmp"
    mv -f "${data_bonds}.tmp" "${data_bonds}"
fi


if [ -s "${data_angles}" ]; then
    if [ ! -z $REMOVE_DUPLICATE_ANGLES ]; then
        remove_duplicates_nbody.py 3 < "${data_angles}" > "${data_angles}.tmp"
        mv "${data_angles}.tmp" "${data_angles}"
        remove_duplicates_nbody.py 3 < "${data_angles}".template > "${data_angles}.tmp"
        mv "${data_angles}.tmp" "${data_angles}".template
    fi
    renumber_DATA_first_column.py < ${data_angles} > "${data_angles}.tmp"
    mv -f "${data_angles}.tmp" "${data_angles}"
fi


if [ -s "${data_dihedrals}" ]; then
    if [ ! -z $REMOVE_DUPLICATE_DIHEDRALS ]; then
        remove_duplicates_nbody.py 4 < "${data_dihedrals}" > "${data_dihedrals}.tmp"
        mv "${data_dihedrals}.tmp" "${data_dihedrals}"
        remove_duplicates_nbody.py 4 < "${data_dihedrals}".template > "${data_dihedrals}.tmp"
        mv "${data_dihedrals}.tmp" "${data_dihedrals}".template
    fi
    renumber_DATA_first_column.py < ${data_dihedrals} > "${data_dihedrals}.tmp"
    mv -f "${data_dihedrals}.tmp" "${data_dihedrals}"
fi


if [ -s "${data_impropers}" ]; then
    if [ ! -z $REMOVE_DUPLICATE_IMPROPERS ]; then
        remove_duplicates_nbody.py 4 < "${data_impropers}" > "${data_impropers}.tmp"
        mv "${data_impropers}.tmp" "${data_impropers}"
        remove_duplicates_nbody.py 4 < "${data_impropers}".template > "${data_impropers}.tmp"
        mv "${data_impropers}.tmp" "${data_impropers}".template
    fi
    renumber_DATA_first_column.py < ${data_impropers} > "${data_impropers}.tmp"
    mv -f "${data_impropers}.tmp" "${data_impropers}"
fi

# -------------------------------------------------------


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`

#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`

NATOMS="0"
NBONDS="0"
NANGLES="0"
NDIHEDRALS="0"
NIMPROPERS="0"

if [ -s "${data_atoms}" ]; then 
  NATOMS=`awk 'END{print NR}' < ${data_atoms}`
fi
if [ -s "${data_bonds}" ]; then 
  NBONDS=`awk 'END{print NR}' < ${data_bonds}`
fi
if [ -s "${data_angles}" ]; then 
  NANGLES=`awk 'END{print NR}' < ${data_angles}`
fi
if [ -s "${data_dihedrals}" ]; then 
  NDIHEDRALS=`awk 'END{print NR}' < ${data_dihedrals}`
fi
if [ -s "${data_impropers}" ]; then 
  NIMPROPERS=`awk 'END{print NR}' < ${data_impropers}`
fi


rm -f "$OUT_FILE_DATA"


echo "LAMMPS Description" > "$OUT_FILE_DATA"
echo "" >> "$OUT_FILE_DATA"
echo "     $NATOMS  atoms" >> "$OUT_FILE_DATA"
if [ -n "$NBONDS" ]; then
    echo "     $NBONDS  bonds" >> "$OUT_FILE_DATA"
fi
if [ -n "$NANGLES" ]; then
    echo "     $NANGLES  angles" >> "$OUT_FILE_DATA"
fi
if [ -n "$NDIHEDRALS" ]; then
    echo "     $NDIHEDRALS  dihedrals" >> "$OUT_FILE_DATA"
fi
if [ -n "$NIMPROPERS" ]; then
    echo "     $NIMPROPERS  impropers" >> "$OUT_FILE_DATA"
fi

echo "" >> "$OUT_FILE_DATA"
echo "     $NATOMTYPES  atom types" >> "$OUT_FILE_DATA"

if [ -n "$NBONDTYPES" ]; then
    echo "     $NBONDTYPES  bond types" >> "$OUT_FILE_DATA"
fi
if [ -n "$NANGLETYPES" ]; then
    echo "     $NANGLETYPES  angle types" >> "$OUT_FILE_DATA"
fi
if [ -n "$NDIHEDRALTYPES" ]; then
    echo "     $NDIHEDRALTYPES  dihedral types" >> "$OUT_FILE_DATA"
fi
if [ -n "$NIMPROPERTYPES" ]; then
    echo "     $NIMPROPERTYPES  improper types" >> "$OUT_FILE_DATA"
fi
echo "" >> "$OUT_FILE_DATA"


# --- 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_pbc" ] && [ ! -s "$data_boundary" ]; then
    mv -f "$data_pbc" "$data_boundary"
    echo "WARNING: write_once(\"$data_pbc\") is depreciated" >&2
    echo "     Use write_once(\"$data_boundary\") instead" >&2
fi

if [ -s "$data_boundary" ]; then
    # Copy the boundary conditions from the "$data_boundary" file.
    # Don't assume there is only one line containing "xlo xhi", for example.
    # It's possible the user wrote the boundary conditions multiple times.
    # As always, the most recent setting overrides the earlier settings.
    BOXSIZE_MINX=`awk '{if ($3=="xlo") {xlo=$1}} END{print xlo}' < "$data_boundary"`
    BOXSIZE_MAXX=`awk '{if ($4=="xhi") {xhi=$2}} END{print xhi}' < "$data_boundary"`

    BOXSIZE_MINY=`awk '{if ($3=="ylo") {ylo=$1}} END{print ylo}' < "$data_boundary"`
    BOXSIZE_MAXY=`awk '{if ($4=="yhi") {yhi=$2}} END{print yhi}' < "$data_boundary"`

    BOXSIZE_MINZ=`awk '{if ($3=="zlo") {zlo=$1}} END{print zlo}' < "$data_boundary"`
    BOXSIZE_MAXZ=`awk '{if ($4=="zhi") {zhi=$2}} END{print zhi}' < "$data_boundary"`

    if [ -z "$BOXSIZE_MINX" ] || [ -z "$BOXSIZE_MAXX" ]; then
	echo "Error: Problem with box boundary format (\"xlo xhi\") in \"$data_boundary\"" >&2
	exit 7
    fi
    if [ -z "$BOXSIZE_MINY" ] || [ -z "$BOXSIZE_MAXY" ]; then
	echo "Error: Problem with box boundary format (\"ylo yhi\") in \"$data_boundary\"" >&2
	exit 8
    fi
    if [ -z "$BOXSIZE_MINZ" ] || [ -z "$BOXSIZE_MAXZ" ]; then
	echo "Error: Problem with box boundary format (\"zlo zhi\") in \"$data_boundary\"" >&2
	exit 9
    fi

    BOXSIZE_XY=`awk '{if ($4=="xy") {xy=$1}} END{print xy}' < "$data_boundary"`
    BOXSIZE_XZ=`awk '{if ($5=="xz") {xz=$2}} END{print xz}' < "$data_boundary"`
    BOXSIZE_YZ=`awk '{if ($6=="yz") {yz=$3}} END{print yz}' < "$data_boundary"`

    if [ -n "$BOXSIZE_XY" ] || [ -n "$BOXSIZE_XZ" ] || [ -n "$BOXSIZE_YZ" ]; then
        if [ -n "$BOXSIZE_XY" ] && [ -n "$BOXSIZE_XZ" ] && [ -n "$BOXSIZE_YZ" ]; then
            #echo "triclinic_parameters: XY XZ YZ = $BOXSIZE_XY $BOXSIZE_XZ $BOXSIZE_YZ" >&2
            TRICLINIC="True"
        else
            echo "Error: Problem with triclinic format (\"xy xz yz\") in \"$data_boundary\"" >&2
            exit 10
        fi
    fi
fi




if [ -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.5*margin*width}"`
	BOXSIZE_MAXX=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$2-$1; print $2+0.5*margin*width}"`
	BOXSIZE_MINY=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$4-$3; print $3-0.5*margin*width}"`
	BOXSIZE_MAXY=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$4-$3; print $4+0.5*margin*width}"`
	BOXSIZE_MINZ=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$6-$5; print $5-0.5*margin*width}"`
	BOXSIZE_MAXZ=`echo $MINMAX_BOUNDS | awk "{margin=0.1; width=$6-$5; print $6+0.5*margin*width}"`
    else
        # By default, choose some reasonably large box:
	BOXSIZE_MINX="-100.0"
	BOXSIZE_MAXX="100.0"
	BOXSIZE_MINY="-100.0"
	BOXSIZE_MAXY="100.0"
	BOXSIZE_MINZ="-100.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 "----           (A default cube of volume=(200.0)^3 was used.      ----" >&2
	echo "----               This is probably not what you want!)           ----" >&2
	echo "---- It is recommended that you specify your periodic boundary    ----" >&2
	echo "---- by adding a write_once(\"Boundary\") command to your .lt file. ----" >&2
	echo "---- For example:                                                 ----" >&2
	#echo "----------------------------------------------------------------------" >&2
	echo "----                                                              ----" >&2
	echo "----   write_once(\"Boundary\") {                                   ----" >&2
	echo "----     2.51  46.79 xlo xhi                                      ----" >&2
	echo "----     -4.38 35.824 ylo yhi                                     ----" >&2
	echo "----     0.3601 42.95 zlo zhi                                     ----" >&2
	echo "----   }                                                          ----" >&2
	echo "----------------------------------------------------------------------" >&2
    fi
fi




if [ -z "$TRICLINIC" ]; then
    echo "  $BOXSIZE_MINX $BOXSIZE_MAXX xlo xhi" >> "$OUT_FILE_DATA"
    echo "  $BOXSIZE_MINY $BOXSIZE_MAXY ylo yhi" >> "$OUT_FILE_DATA"
    echo "  $BOXSIZE_MINZ $BOXSIZE_MAXZ zlo zhi" >> "$OUT_FILE_DATA"
else
    echo "triclinic parameters: XY XZ YZ = $BOXSIZE_XY $BOXSIZE_XZ $BOXSIZE_YZ" >&2
    echo "" >&2
    # Otherwise, this is a triclinic (non orthoganal) crystal basis.
    # LAMMPS represents triclinic symmetry using a different set of parameters
    # (lx,ly,lz,xy,xz,yz) than the PDB file format (alpha,beta,gamma).
    echo "  $BOXSIZE_MINX $BOXSIZE_MAXX xlo xhi" >> "$OUT_FILE_DATA"
    echo "  $BOXSIZE_MINY $BOXSIZE_MAXY ylo yhi" >> "$OUT_FILE_DATA"
    echo "  $BOXSIZE_MINZ $BOXSIZE_MAXZ zlo zhi" >> "$OUT_FILE_DATA"
    #echo "  0.000000 $BOXSIZE_X xlo xhi" >> "$OUT_FILE_DATA"
    #echo "  0.000000 $BOXSIZE_Y ylo yhi" >> "$OUT_FILE_DATA"
    #echo "  0.000000 $BOXSIZE_Z zlo zhi" >> "$OUT_FILE_DATA"
    echo "  $BOXSIZE_XY $BOXSIZE_XZ $BOXSIZE_YZ xy xz yz" >> "$OUT_FILE_DATA"
    #echo "a,b,c,alpha,beta,gamma = $BOXSIZE_A,$BOXSIZE_B,$BOXSIZE_C,$ALPHA,$BETA,$GAMMA"
fi
echo "" >> "$OUT_FILE_DATA"




if [ -s "$data_header" ]; then
  cat "$data_header" >> "$OUT_FILE_DATA"
  echo "" >> "$OUT_FILE_DATA"
fi


if [ -s "$data_masses" ]; then
    echo "Masses" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_masses" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
else
    echo "WARNING: missing file \"$data_masses\"" >&2
fi


if [ -s "$data_pair_coeffs" ]; then
    echo "Pair Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_pair_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
else
    if [ ! -s "$in_settings" ] || (! grep -q pair_coeff "$in_settings"); then
	echo "WARNING: no pair coeffs have been set!" >&2
    fi
fi


if [ -s "$data_bond_coeffs" ]; then
    echo "Bond Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_bond_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
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 "Angle Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_angle_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
else
    if [ -n "$NANGLETYPES" ] && ( [ ! -s "$in_settings" ] || (! grep -q angle_coeff "$in_settings") ); then
	echo "WARNING: no angle coeffs have been set!" >&2
    fi
fi

if [ -s "$data_dihedral_coeffs" ]; then
    echo "Dihedral Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_dihedral_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
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 "Improper Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_improper_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
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


# data file sections specific to class2 force-fields:

if [ -s "$data_bondbond_coeffs" ]; then
    echo "BondBond Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_bondbond_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_bondangle_coeffs" ]; then
    echo "BondAngle Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_bondangle_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_middlebondtorsion_coeffs" ]; then
    echo "MiddleBondTorsion Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_middlebondtorsion_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_endbondtorsion_coeffs" ]; then
    echo "EndBondTorsion Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_endbondtorsion_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_angletorsion_coeffs" ]; then
    echo "AngleTorsion Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_angletorsion_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_angleangletorsion_coeffs" ]; then
    echo "AngleAngleTorsion Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_angleangletorsion_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_bondbond13_coeffs" ]; then
    echo "BondBond13 Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_bondbond13_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_angleangle_coeffs" ]; then
    echo "AngleAngle Coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_angleangle_coeffs" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi



if [ -s "$data_atoms" ]; then
    echo "Atoms" >> "$OUT_FILE_DATA"
    if [ -s "$tmp_atom_coords" ]; then
        echo "# (Note: x,y,z coordinates may overlap and can be modified later.)" >> "$OUT_FILE_DATA"
    else
        echo "" >> "$OUT_FILE_DATA"
    fi
    cat "$data_atoms" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
else
    echo "WARNING: missing file \"$data_atoms\"" >&2
fi

if [ -s "$data_ellipsoids" ]; then
    echo "Ellipsoids" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_ellipsoids" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_triangles" ]; then
    echo "Triangles" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_triangles" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_lines" ]; then
    echo "Lines" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_lines" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_velocities" ]; then
    echo "Velocities" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_velocities" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
#else
#    echo "Velocities" >> "$OUT_FILE_DATA"
#    echo "" >> "$OUT_FILE_DATA"
#    awk '{print $1 " 0.0 0.0 0.0"}' < "$data_atoms" >> "$OUT_FILE_DATA"
#    echo "" >> "$OUT_FILE_DATA"
fi

if [ -s "$data_bonds" ]; then
    echo "Bonds" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_bonds" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
#else
#    echo "WARNING: missing file \"$data_bonds\"" >&2
fi



if [ -s "$data_angles" ]; then
    echo "Angles" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_angles" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
#else
#    echo "WARNING: missing file \"$data_angles\"" >&2
fi

if [ -s "$data_dihedrals" ]; then
    echo "Dihedrals" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_dihedrals" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
#else
#    echo "WARNING: missing file \"$data_dihedrals\"" >&2
fi

if [ -s "$data_impropers" ]; then
    echo "Impropers" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_impropers" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
#else
#    echo "WARNING: missing file \"$data_impropers\"" >&2
fi






rm -f $OUT_FILE_INPUT_SCRIPT

if [ -s "$in_init" ]; then
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    cp -f "$in_init" $OUT_FILE_INIT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    echo "# ----------------- Init Section -----------------" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    echo "include \"$OUT_FILE_INIT\"" >> $OUT_FILE_INPUT_SCRIPT
    #echo "# \"$in_init\" typically contains various styles, dimensions, and units:" >> $OUT_FILE_INPUT_SCRIPT
    #echo "include \"$in_init\"" >> $OUT_FILE_INPUT_SCRIPT
    #cat "$in_init" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
fi


echo "" >> $OUT_FILE_INPUT_SCRIPT
echo "# ----------------- Atom Definition Section -----------------" >> $OUT_FILE_INPUT_SCRIPT
echo "" >> $OUT_FILE_INPUT_SCRIPT
echo "read_data \"$OUT_FILE_DATA\"" >> $OUT_FILE_INPUT_SCRIPT
echo "" >> $OUT_FILE_INPUT_SCRIPT
echo "# ----------------- Settings Section -----------------" >> $OUT_FILE_INPUT_SCRIPT
echo "" >> $OUT_FILE_INPUT_SCRIPT


if [ -s "$in_settings" ]; then
    #echo "# \"$in_settings\" typically contains coeffs, fixes, groups & modify commands:" >> $OUT_FILE_INPUT_SCRIPT
    #echo "include \"$in_settings\"" >> $OUT_FILE_INPUT_SCRIPT
    #cat "$in_settings" >> $OUT_FILE_INPUT_SCRIPT
    cp -f "$in_settings" $OUT_FILE_SETTINGS
    echo "include \"$OUT_FILE_SETTINGS\"" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
fi


if [ -s "$tmp_atom_coords" ]; then
    rm -f "$OUT_FILE_COORDS"
    awk '{if (NF>=3) {natom++; print "set atom "natom"  x "$1"  y "$2"  z "$3"  image 0 0 0"}}' < "$tmp_atom_coords" >> "$OUT_FILE_COORDS"
    echo "# Load the atom coordinates:" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    echo "include \"$OUT_FILE_COORDS\"" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    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
else
    rm -f "$OUT_FILE_COORDS"
#    echo "Warning: (moltemplate.sh)" >&2
#    echo "         Atomic coordinates were not supplied externally" >&2
#    echo "         (for example using the \"-pdb\" or \"-xyz\" arguments)." >&2
#    echo "         Hopefully you used rot(), trans() lttree commands to move" >&2
#    echo "         molecules to non-overlapping positions." >&2
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




# 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





# ############## DEAL WITH CUSTOM NON-STANDARD SECTIONS ################


N_data_prefix=`expr length "$data_prefix"`
ls "${data_prefix}"* 2> /dev/null | while read file_name; do
    #If using bash:
    #section_name="${file_name:$N_data_prefix}"
    #If using sh:
    section_name=`expr substr "$file_name" $(($N_data_prefix+1)) 1000000`
    # Create a new section in the data file 
    # matching the portion of the name of 
    # the file after the data_prefix.
    echo "" >> "$OUT_FILE_DATA"
    echo "$section_name" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    cat "$file_name" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    mv -f "$file_name" output_ttree/
done

if [ -e "$data_prefix_no_space" ]; then
    echo "" >> "$OUT_FILE_DATA"
    cat "$data_prefix_no_space" >> "$OUT_FILE_DATA"
    echo "" >> "$OUT_FILE_DATA"
    mv -f "$data_prefix_no_space" output_ttree/
fi



N_in_prefix=`expr length "$in_prefix"`
ls "${in_prefix}"* 2> /dev/null | while read file_name; do
    #If using bash:
    #section_name="${file_name:$N_in_prefix}"
    #If using sh:
    section_name=`expr substr "$file_name" $(($N_in_prefix+1)) 1000000`
    # Create a new section in the lammps input script
    # matching the portion of the name of 
    # the file after the in_prefix.
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    echo "# ----------------- $section_name Section -----------------" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    cat "$file_name" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    mv -f "$file_name" output_ttree/
done

if [ -e "$in_prefix_no_space" ]; then
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    cat "$in_prefix_no_space" >> $OUT_FILE_INPUT_SCRIPT
    echo "" >> $OUT_FILE_INPUT_SCRIPT
    mv -f "$in_prefix_no_space" output_ttree/
fi


# Swap the order of atom types I, J in all "pair_coeff I J ..." commands 
# whenever I > J.  Do this for every input script file generated by moltemplate.
# (Perhaps later I'll check to make sure the user did not specify contradictory
#  "pair_coeff I J ..." and "pair_coeff J I ..." commands, but I won't do it
#  here, because at this point we've thrown away the original atom type names,
#  so there's no easy way to explain the problem to the user if there is one.)

echo "" > input_scripts_so_far.tmp

for file_name in "$OUT_FILE_INIT" "$OUT_FILE_INPUT_SCRIPT" "$OUT_FILE_SETTINGS"; do
    if [ -s "$file_name" ]; then
        echo "postprocessing file \"$file_name\"" >&2
	postprocess_input_script.py input_scripts_so_far.tmp < "$file_name" > "$file_name".tmp
	echo "" >&2
	mv "$file_name".tmp "$file_name"
	cat "$file_name" >> input_scripts_so_far.tmp
    fi
done


ls "${in_prefix}"* 2> /dev/null | while read file_name; do
    echo "postprocessing file \"$file_name\"" >&2
    postprocess_input_script.py input_scripts_so_far.tmp < "$file_name" > "$file_name".tmp
    echo "" >&2
    mv "$file_name".tmp "$file_name"
    cat "$file_name" >> input_scripts_so_far.tmp
done

rm -f input_scripts_so_far.tmp


# ############ Optional: Add a fake run section as an example ############


echo "" >> $OUT_FILE_INPUT_SCRIPT
echo "# ----------------- Run Section -----------------" >> $OUT_FILE_INPUT_SCRIPT
echo "" >> $OUT_FILE_INPUT_SCRIPT
echo "# The lines above define the system you want to simulate." >> $OUT_FILE_INPUT_SCRIPT
echo "# What you do next is up to you." >> $OUT_FILE_INPUT_SCRIPT
echo "# Typically a user would minimize and equilibrate" >> $OUT_FILE_INPUT_SCRIPT
echo "# the system using commands similar to the following:" >> $OUT_FILE_INPUT_SCRIPT
echo "#  ----   examples   ----" >> $OUT_FILE_INPUT_SCRIPT
echo "#" >> $OUT_FILE_INPUT_SCRIPT
echo "#  -- minimize --" >> $OUT_FILE_INPUT_SCRIPT
echo "# minimize 1.0e-5 1.0e-7 1000 10000" >> $OUT_FILE_INPUT_SCRIPT
echo "# (Note: Some fixes, for example \"shake\", interfere with the minimize command," >> $OUT_FILE_INPUT_SCRIPT
echo "#        You can use the \"unfix\" command to disable them before minimization.)" >> $OUT_FILE_INPUT_SCRIPT
echo "#  -- declare time step for normal MD --" >> $OUT_FILE_INPUT_SCRIPT
echo "# timestep 1.0" >> $OUT_FILE_INPUT_SCRIPT
echo "#  -- run at constant pressure (Nose-Hoover)--" >> $OUT_FILE_INPUT_SCRIPT
#echo "# timestep 1.0" >> $OUT_FILE_INPUT_SCRIPT
echo "# fix   fxnpt all npt temp 300.0 300.0 100.0 iso 1.0 1.0 1000.0 drag 1.0">>$OUT_FILE_INPUT_SCRIPT
echo "#  -- ALTERNATELY, run at constant volume (Nose-Hoover) --" >> $OUT_FILE_INPUT_SCRIPT
echo "# fix   fxnvt all nvt temp 300.0 300.0 500.0 tchain 1" >> $OUT_FILE_INPUT_SCRIPT
echo "#  -- ALTERNATELY, run at constant volume using Langevin dynamics. --" >> $OUT_FILE_INPUT_SCRIPT
echo "#  -- (This is good for sparse CG polymers in implicit solvent.)   --" >> $OUT_FILE_INPUT_SCRIPT
echo "fix fxlan all langevin 300.0 300.0 5000 48279" >> $OUT_FILE_INPUT_SCRIPT
echo "#  -- Now, finally run the simulation --" >> $OUT_FILE_INPUT_SCRIPT
echo "# run   50000" >> $OUT_FILE_INPUT_SCRIPT
#echo "# write_restart system_after_nvt.rst" >> $OUT_FILE_INPUT_SCRIPT
#echo "# run   50000" >> $OUT_FILE_INPUT_SCRIPT
#echo "# write_restart system_after_npt.rst" >> $OUT_FILE_INPUT_SCRIPT
echo "#  ---- (end of examples) ----">> $OUT_FILE_INPUT_SCRIPT
#echo "# It is the responsibility of the user to learn LAMMPS and specify these">>$OUT_FILE_INPUT_SCRIPT
#echo "# these commands." >> $OUT_FILE_INPUT_SCRIPT
echo "" >> $OUT_FILE_INPUT_SCRIPT

