Gaussian

Gaussian 16 software

Gaussian 16 (G16) is the world’s most widely used quantum chemistry software. It calculates the electronic structure of molecules using methods ranging from Hartree-Fock to coupled cluster, DFT, and multireference methods. On duhpc (High Performance Computing Cluster commissioned in HPCC Lab, Department of Chemistry, University of Delhi), Gaussian 16 is installed on the compute nodes and is accessed through the SLURM batch system.

Template for Gaussian Job Script:

#!/bin/bash
#==============================================================
# Gaussian16 Job Script — duhpc Cluster
# Version: 3.0  |  May 2026
# Department of Chemistry, University of Delhi
#
# FEATURES:
#   ✓ Auto-restart from checkpoint after power failure
#   ✓ Walltime warning — saves checkpoint 5 min before kill
#   ✓ Auto-injects %Chk if user forgets
#   ✓ NProcShared mismatch detection and fix
#   ✓ Smart failure diagnosis with recovery hints
#   ✓ Scratch preserved on failure for debugging
#
# USAGE:
#   1. Copy this file to your job directory
#   2. Edit JobFile= line with your input filename
#   3. Adjust --cpus-per-task and --mem to match your .com file
#   4. sbatch gaussian_job.sh
#
# PARTITION GUIDE:
#   compute → Gaussian, single-node, up to 5 days, max 16 CPUs ← USE THIS
#   mpi     → GROMACS, NAMD, Amber MPI — multi-node jobs ONLY
#   short   → Test jobs, max 4 hours, max 8 CPUs
#   gpu     → Amber CUDA, GROMACS GPU — GPU jobs only
#==============================================================

#SBATCH --job-name=Gaussian
#SBATCH --partition=compute         # Always use compute for Gaussian
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8           # Recommended: 4-16 (see guide below)
#SBATCH --mem=32G                   # Match %Mem in .com file + 4G buffer
#SBATCH --time=5-00:00:00           # Max 5 days on compute partition
#SBATCH --output=%x_%j.out          # Stdout (%x=jobname, %j=jobid)
#SBATCH --error=%x_%j.err           # Stderr
#SBATCH --mail-type=BEGIN,END,FAIL  # Email notifications
#SBATCH --mail-user=your@email.com  # ← Change to your email address
#SBATCH --signal=B:USR1@300         # Save checkpoint 5 min before walltime

# ══════════════════════════════════════════════════════════
# USER SETTINGS — Edit only this section
# ══════════════════════════════════════════════════════════
JobFile=molecule           # Input filename WITHOUT .com extension
# ══════════════════════════════════════════════════════════

# CPU SELECTION GUIDE:
#   Geometry optimisation:  4-8  CPUs  --mem=20-32G
#   Single point (DFT):     8-12 CPUs  --mem=32-48G
#   Frequency calculation:  8-12 CPUs  --mem=32-48G
#   TD-DFT / NMR:           4-8  CPUs  --mem=32-48G
#   MP2 / CCSD(T):          8-16 CPUs  --mem=48-60G
#   Large molecule >100 at: 12-16 CPUs --mem=48-60G
#
# IMPORTANT: %NProcShared in .com file MUST match --cpus-per-task
# IMPORTANT: %Mem in .com file must be ~4G LESS than --mem here

#==============================================================
# SETUP — do not edit below unless you know what you are doing
#==============================================================

SUBMIT_DIR=$SLURM_SUBMIT_DIR
CHK_PATH="$SUBMIT_DIR/${JobFile}.chk"
LOG_PATH="$SUBMIT_DIR/${JobFile}.log"
export GAUSS_SCRDIR=/scratch/gaussian/$USER/$SLURM_JOBID

#──────────────────────────────────────────────────────────
# WALLTIME TRAP — fires 5 minutes before SLURM kills job
# Saves checkpoint so job can be restarted
#──────────────────────────────────────────────────────────
walltime_handler() {
    echo ""
    echo "╔══════════════════════════════════════════════════════╗"
    echo "║  ⚠  WALLTIME LIMIT APPROACHING — 5 minutes left!   ║"
    echo "╚══════════════════════════════════════════════════════╝"

    # Save checkpoint from scratch to job directory
    SAVED=0
    for chk in "$GAUSS_SCRDIR"/*.chk; do
        [ -f "$chk" ] && cp "$chk" "$SUBMIT_DIR/" && \
            echo "✓ Checkpoint saved: $SUBMIT_DIR/$(basename $chk)" && \
            SAVED=1
    done
    [ -f "$CHK_PATH" ] && \
        echo "✓ Checkpoint in submit dir: $CHK_PATH" && SAVED=1
    [ $SAVED -eq 0 ] && \
        echo "✗ No checkpoint found — add %Chk=${JobFile}.chk to .com file"

    echo ""
    echo "TO RESTART THIS JOB:"
    echo "  1. Increase --time in this script (e.g. 5-00:00:00)"
    echo "  2. Resubmit: sbatch gaussian_job.sh"
    echo "     (script auto-detects checkpoint and restarts)"
    echo ""
    echo "OR ask admin for walltime extension:"
    echo "  Contact: ighani@ducc.du.ac.in with Job ID $SLURM_JOB_ID"
}
trap 'walltime_handler' USR1

#──────────────────────────────────────────────────────────
# PRINT JOB HEADER
#──────────────────────────────────────────────────────────
echo "╔══════════════════════════════════════════════╗"
echo "║       Gaussian16 Job — duhpc Cluster        ║"
echo "╚══════════════════════════════════════════════╝"
echo "Job ID     : $SLURM_JOB_ID"
echo "Job Name   : $SLURM_JOB_NAME"
echo "User       : $USER"
echo "Node       : $SLURMD_NODENAME"
echo "CPUs       : $SLURM_CPUS_PER_TASK"
echo "Memory     : $SLURM_MEM_PER_NODE MB"
echo "Submit Dir : $SUBMIT_DIR"
echo "Input file : ${JobFile}.com"
echo "Log file   : ${JobFile}.log"
echo "Checkpoint : $CHK_PATH"
echo "Scratch    : $GAUSS_SCRDIR"
echo "Started    : $(date)"
echo "══════════════════════════════════════════════"

#──────────────────────────────────────────────────────────
# LOAD GAUSSIAN
#──────────────────────────────────────────────────────────
export g16root=/scratch/apps/gaussian
export PATH=$g16root/g16:$PATH
export LD_LIBRARY_PATH=$g16root/g16:$LD_LIBRARY_PATH
source $g16root/g16/bsd/g16.profile
ulimit -s unlimited

#──────────────────────────────────────────────────────────
# SETUP SCRATCH DIRECTORY
#──────────────────────────────────────────────────────────
mkdir -p $GAUSS_SCRDIR

#──────────────────────────────────────────────────────────
# VALIDATE INPUT FILE
#──────────────────────────────────────────────────────────
cd $SUBMIT_DIR

if [ ! -f "${JobFile}.com" ]; then
    echo "ERROR: Input file '${JobFile}.com' not found in:"
    echo "       $SUBMIT_DIR"
    echo ""
    echo "Available .com files:"
    ls *.com 2>/dev/null || echo "  (none found)"
    exit 1
fi

# Fix Windows line endings silently
sed -i 's/\r//g' ${JobFile}.com

# Show key settings from input file
echo ""
echo "--- Input file settings ---"
grep -i "^%NProcShared\|^%Mem\|^%Chk\|^%nproc\|^%mem\|^%chk" ${JobFile}.com

#──────────────────────────────────────────────────────────
# CHECK AND FIX NPROC MISMATCH
#──────────────────────────────────────────────────────────
NPROC=$(grep -i "^%NProcShared\|^%nproc" ${JobFile}.com | \
    grep -o '[0-9]*' | head -1)
if [ -n "$NPROC" ] && [ "$NPROC" != "$SLURM_CPUS_PER_TASK" ]; then
    echo ""
    echo "⚠  WARNING: %NProcShared=$NPROC in .com file"
    echo "   but --cpus-per-task=$SLURM_CPUS_PER_TASK in job script"
    echo "   Fixing .com file to match SLURM allocation..."
    sed -i "s/NProcShared=$NPROC/NProcShared=$SLURM_CPUS_PER_TASK/Ig" \
        ${JobFile}.com
    sed -i "s/%nproc=$NPROC/%nproc=$SLURM_CPUS_PER_TASK/Ig" \
        ${JobFile}.com
    echo "   ✓ %NProcShared updated to $SLURM_CPUS_PER_TASK"
fi

#──────────────────────────────────────────────────────────
# AUTO-INJECT %Chk IF MISSING
#──────────────────────────────────────────────────────────
if ! grep -qi "^%chk" ${JobFile}.com; then
    echo ""
    echo "⚠  No %Chk found — auto-adding checkpoint line"
    TMPFILE=$(mktemp)
    echo "%Chk=${CHK_PATH}" > $TMPFILE
    cat ${JobFile}.com >> $TMPFILE
    cp $TMPFILE ${JobFile}.com
    rm -f $TMPFILE
    echo "   ✓ Added: %Chk=${CHK_PATH}"
fi

#──────────────────────────────────────────────────────────
# AUTO-DETECT RESTART FROM CHECKPOINT
#──────────────────────────────────────────────────────────
RESTART_MODE=0
ACTUAL_INPUT="${JobFile}.com"

if [ -f "$CHK_PATH" ]; then
    CHK_SIZE=$(ls -lh "$CHK_PATH" | awk '{print $5}')
    CHK_DATE=$(ls -l  "$CHK_PATH" | awk '{print $6,$7,$8}')
    echo ""
    echo "╔══════════════════════════════════════════════╗"
    echo "║  ✓ RESTART MODE: Checkpoint found!          ║"
    echo "╚══════════════════════════════════════════════╝"
    echo "Checkpoint : $CHK_PATH"
    echo "Size       : $CHK_SIZE  |  Modified: $CHK_DATE"

    # Build restart input file
    ROUTE=$(grep -i "^#" "${JobFile}.com" | head -1)
    MEM_LINE=$(grep -i "^%mem"  "${JobFile}.com" | head -1)
    NPROC_LINE=$(grep -i "^%nproc\|^%cpu" "${JobFile}.com" | head -1)
    CHK_LINE=$(grep -i "^%chk"  "${JobFile}.com" | head -1)

    # Add Restart keyword to route
    if echo "$ROUTE" | grep -qi "Opt=("; then
        NEW_ROUTE=$(echo "$ROUTE" | sed 's/Opt=(\([^)]*\))/Opt=(Restart,\1/I')
    elif echo "$ROUTE" | grep -qi "\bOpt\b"; then
        NEW_ROUTE=$(echo "$ROUTE" | sed 's/\bOpt\b/Opt=Restart/I')
    elif echo "$ROUTE" | grep -qi "IRC"; then
        NEW_ROUTE=$(echo "$ROUTE" | sed 's/IRC/IRC=Restart/I')
    else
        NEW_ROUTE="$ROUTE Restart"
    fi

    RESTART_INPUT="${JobFile}_restart_${SLURM_JOB_ID}.com"

    # Extract charge and multiplicity from original input
    # Format: "0 1" on the line after the first blank line after route
    CHARGE_MULT=$(awk '
        /^#/{found_route=1; next}
        found_route && /^$/{blank++; next}
        found_route && blank==1 && /^$/{blank++; next}
        found_route && blank>=1 && NF>0 && !/^$/{
            if (blank>=2) {print; exit}
        }
    ' "${JobFile}.com" | head -1)

    # If not found try simpler approach
    [ -z "$CHARGE_MULT" ] && \
        CHARGE_MULT=$(grep -A99 "^$" "${JobFile}.com" | \
        grep -E "^[0-9-]+ [0-9]+$" | head -1)

    # Default to "0 1" if still not found
    [ -z "$CHARGE_MULT" ] && CHARGE_MULT="0 1"

    {
        # Link0 section
        echo "$CHK_LINE"
        [ -n "$MEM_LINE"   ] && echo "$MEM_LINE"
        [ -n "$NPROC_LINE" ] && echo "$NPROC_LINE"
        # Route card
        echo "$NEW_ROUTE"
        # Blank line
        echo ""
        # Title line
        echo "Restart from checkpoint — Job $SLURM_JOB_ID — $(date)"
        # Blank line
        echo ""
        # Charge and multiplicity
        echo "$CHARGE_MULT"
        # Two final blank lines — Gaussian requires this
        echo ""
        echo ""
    } > "$RESTART_INPUT"

    # Verify restart file looks correct
    echo "--- Restart input file ---"
    cat "$RESTART_INPUT"
    echo "--- End restart input ---"
    echo ""

    ACTUAL_INPUT="$RESTART_INPUT"
    RESTART_MODE=1
    echo "Restart input : $RESTART_INPUT"
    echo "Route         : $NEW_ROUTE"
else
    echo ""
    echo "--- Fresh start — no checkpoint found ---"
fi

echo ""

#──────────────────────────────────────────────────────────
# RUN GAUSSIAN
#──────────────────────────────────────────────────────────
echo "--- Starting Gaussian16 ---"
echo "Mode    : $([ $RESTART_MODE -eq 1 ] && \
    echo 'RESTART from checkpoint' || echo 'FRESH START')"
echo ""
START=$(date +%s)

# Run Gaussian directly (not background) for reliable output capture
# The USR1 trap will still fire correctly
g16 < "$ACTUAL_INPUT" > "$LOG_PATH" 2>&1
EXIT=$?

END=$(date +%s)
ELAPSED=$((END-START))
HOURS=$((ELAPSED/3600))
MINS=$(( (ELAPSED%3600)/60 ))
SECS=$((ELAPSED%60))

#──────────────────────────────────────────────────────────
# SAVE CHECKPOINT BEFORE CLEANUP
#──────────────────────────────────────────────────────────
echo ""
echo "--- Saving checkpoint ---"
CHK_SAVED=0
for chk in "$GAUSS_SCRDIR"/*.chk; do
    [ -f "$chk" ] && \
        cp "$chk" "$SUBMIT_DIR/" && \
        echo "✓ Saved: $SUBMIT_DIR/$(basename $chk)" && \
        CHK_SAVED=1
done
[ -f "$CHK_PATH" ] && \
    echo "✓ Checkpoint: $CHK_PATH ($(ls -lh $CHK_PATH | awk '{print $5}'))" && \
    CHK_SAVED=1
[ $CHK_SAVED -eq 0 ] && \
    echo "✗ No checkpoint found"

#──────────────────────────────────────────────────────────
# JOB RESULT SUMMARY
#──────────────────────────────────────────────────────────
echo ""
echo "╔══════════════════════════════════════════════╗"
echo "║                JOB SUMMARY                  ║"
echo "╚══════════════════════════════════════════════╝"
echo "Job ID    : $SLURM_JOB_ID"
echo "Node      : $SLURMD_NODENAME"
echo "Wall time : ${HOURS}h ${MINS}m ${SECS}s"
echo "Exit code : $EXIT"

# Check if log file is empty — Gaussian never started
if [ ! -s "$LOG_PATH" ]; then
    echo "Status    : ✗ FAILED — Gaussian did not start"
    echo ""
    echo "Log file is empty — possible causes:"
    echo "  1. Input file format error"
    echo "  2. Gaussian binary not found"
    echo "  3. Memory or scratch issue"
    echo ""
    echo "Check input file:"
    echo "  cat $ACTUAL_INPUT"
    echo "Scratch preserved: $GAUSS_SCRDIR"
    echo ""
    echo "Finished  : $(date)"
    echo "══════════════════════════════════════════════"
    exit 1
fi

if [ $EXIT -eq 0 ] && \
   [ -s "$LOG_PATH" ] && \
   grep -q "Normal termination" "$LOG_PATH" 2>/dev/null; then
    echo "Status    : ✓ COMPLETED SUCCESSFULLY"
    echo ""
    echo "--- Key results ---"
    grep -E "SCF Done|CCSD\(T\)|MP2|Zero-point|Thermal correction|\
Dipole moment|Frequencies|Stationary point|Optimized Parameters|\
Normal termination|Job cpu time" \
        "$LOG_PATH" 2>/dev/null | \
        grep -v "^$" | tail -10
    # Clean scratch on success
    rm -rf $GAUSS_SCRDIR
    echo ""
    echo "Scratch   : Cleaned"

elif grep -q "Erroneous write\|galloc\|Out of memory\|sbrk" \
     "$LOG_PATH" 2>/dev/null; then
    echo "Status    : ✗ FAILED — Memory error"
    echo ""
    MEM_GB=$((SLURM_MEM_PER_NODE/1024))
    NEW_MEM=$((MEM_GB+16))
    echo "SOLUTION: Increase memory in job script:"
    echo "  Change: #SBATCH --mem=${MEM_GB}G"
    echo "  To:     #SBATCH --mem=${NEW_MEM}G"
    echo "  And in .com file: %Mem=$((NEW_MEM-4))GB"
    echo ""
    echo "Scratch preserved: $GAUSS_SCRDIR"

elif grep -q "Convergence failure\|SCF has not converged" \
     "$LOG_PATH" 2>/dev/null; then
    echo "Status    : ✗ FAILED — SCF convergence failure"
    echo ""
    echo "SOLUTION: Add to route card:"
    echo "  SCF=(MaxCycles=512,XQC)"
    echo ""
    echo "Scratch preserved: $GAUSS_SCRDIR"

elif grep -q "Optimization stopped\|Berny optimization" \
     "$LOG_PATH" 2>/dev/null && \
     ! grep -q "Stationary point found" "$LOG_PATH" 2>/dev/null; then
    echo "Status    : ✗ INCOMPLETE — Geometry optimisation not converged"
    echo ""
    if [ $CHK_SAVED -eq 1 ]; then
        echo "SOLUTION: Checkpoint saved — resubmit to continue:"
        echo "  sbatch gaussian_job.sh"
        echo "  (script auto-detects checkpoint and restarts)"
    fi
    echo ""
    echo "Scratch preserved: $GAUSS_SCRDIR"

else
    echo "Status    : ✗ FAILED"
    echo ""
    echo "Last 15 lines of log:"
    tail -15 "$LOG_PATH" 2>/dev/null
    echo ""
    [ $CHK_SAVED -eq 1 ] && \
        echo "Checkpoint saved — resubmit with: sbatch gaussian_job.sh"
    echo "Scratch preserved: $GAUSS_SCRDIR"
fi

echo ""
echo "Finished  : $(date)"
echo "══════════════════════════════════════════════"
echo ""
echo "--- Gaussian log: $LOG_PATH ---"
echo "--- For help: ighani@ducc.du.ac.in ---"

Useful SLURM Commands for Gaussian Jobs

TaskCommand
Submit jobsbatch gaussian_job.sh
Check job statussqueue -u $USER
Cancel jobscancel JOBID
Live outputtail -f molecule.log

back to chemistry.du.ac.in/hpcc