#!/bin/sh
##
## This script performs exposure correction to images, and
## finally produce the exposure-corrected image.
##
## * make `image' from `evt file'
## * make `spectral weight' using `make_instmap_weights'
## * use `fluximage' to generating `exposure map'
## * make `exposure-corrected' image
## * and extract `surface brighness profile'
##
## NOTES:
## only ACIS-I (chip: 0-3) and ACIS-S (chip: 7) supported
## `merge_all' conflict with Heasoft's `pget' etc. tools
##
## Weitian LI
## 2012/08/16
##
VERSION="v3.0"
UPDATED="2015/06/03"
##
## ChangeLogs:
## v3.1, 2015/06/04, Aaron LI
##   * Added check for 'fluximage' parameter 'xygrid' before to use.
##     'fluximage' of version before '15Oct2012' does not have parameter
##     'xygrid' and dose not support spectral weights with parameter 'bands'.
## v3.0, 2015/06/03, Aaron LI
##   * Changed to use 'fluximage' by default, and fallback to 'merge_all'
##   * Copy needed pfiles to current working directory, and
##     set environment variable $PFILES to use these first.
##   * Replaced 'grep' with '\grep', 'ls' with '\ls'
## v2.1, 2014/10/30, Weitian LI
##   Add 'aspect' parameter for 'skyfov' to fix the 'FoV shift bug'
## v2.0, 2014/07/29, Weitian LI
##   `merge_all' deprecated, use `fluximage' if possible
## v1.2, 2012/08/21, Weitian LI
##   set `ardlib' before process `merge_all'
## v1.1, 2012/08/21, Weitian LI
##   fix a bug with `sed'
##

unalias -a
export LC_COLLATE=C

## error code {{{
ERR_USG=1
ERR_DIR=11
ERR_EVT=12
ERR_BKG=13
ERR_REG=14
ERR_ASOL=21
ERR_BPIX=22
ERR_PBK=23
ERR_MSK=24
ERR_BKGTY=31
ERR_SPEC=32
ERR_DET=41
ERR_ENG=42
ERR_CIAO=100
ERR_TOOL=110
## error code }}}

## usage, help {{{
case "$1" in
    -[hH]*|--[hH]*)
        printf "usage:\n"
        printf "    `basename $0` evt=<evt_file> energy=<e_start:e_end:e_width> basedir=<base_dir> nh=<nH> z=<redshift> temp=<avg_temperature> abund=<avg_abund> [ logfile=<log_file> ]\n"
        printf "\nversion:\n"
        printf "    ${VERSION}, ${UPDATED}\n"
        exit ${ERR_USG}
        ;;
esac
## usage, help }}}

## default parameters {{{
# default `event file' which used to match `blanksky' files
#DFT_EVT="_NOT_EXIST_"
DFT_EVT="`\ls evt2*_clean.fits 2> /dev/null`"
# default dir which contains `asols, asol.lis, ...' files
# DFT_BASEDIR="_NOT_EXIST_"
DFT_BASEDIR=".."
# default `radial region file' to extract surface brightness
DFT_SBP_REG="_NOT_EXIST_"
#DFT_SBP_REG="sbprofile.reg"
# default `energy band' applying to `images' analysis
# format: `E_START:E_END:E_WIDTH'
DFT_ENERGY="700:7000:100"

# default `log file'
DFT_LOGFILE="expcorr_sbp_`date '+%Y%m%d'`.log"

## howto find files in `basedir'
# default `asol.lis pattern'
DFT_ASOLIS_PAT="acis*asol?.lis"
# default `bad pixel filename pattern'
DFT_BPIX_PAT="acis*repro*bpix?.fits"
# default `msk file pattern'
DFT_MSK_PAT="acis*msk?.fits"
## default parameters }}}

## functions {{{
# process commandline arguments
# cmdline arg format: `KEY=VALUE'
getopt_keyval() {
    until [ -z "$1" ]
    do
        key=${1%%=*}                    # extract key
        val=${1#*=}                     # extract value
        keyval="${key}=\"${val}\""
        echo "## getopt: eval '${keyval}'"
        eval ${keyval}
        shift                           # shift, process next one
    done
}
## functions }}}

## check CIAO init {{{
if [ -z "${ASCDS_INSTALL}" ]; then
    printf "ERROR: CIAO NOT initialized\n"
    exit ${ERR_CIAO}
fi

## XXX: heasoft's `pget' etc. tools conflict with some CIAO tools
printf "set \$PATH to avoid conflicts between HEAsoft and CIAO\n"
export PATH="${ASCDS_BIN}:${ASCDS_CONTRIB}:${PATH}"
printf "## PATH: ${PATH}\n"
## check CIAO }}}

## parameters {{{
# process cmdline args using `getopt_keyval'
getopt_keyval "$@"

## check log parameters {{{
if [ ! -z "${log}" ]; then
    LOGFILE="${log}"
else
    LOGFILE=${DFT_LOGFILE}
fi
printf "## use logfile: \`${LOGFILE}'\n"
[ -e "${LOGFILE}" ] && mv -fv ${LOGFILE} ${LOGFILE}_bak
TOLOG="tee -a ${LOGFILE}"
echo "process script: `basename $0`" >> ${LOGFILE}
echo "process date: `date`" >> ${LOGFILE}
## log }}}

# check given parameters
# check evt file
if [ -r "${evt}" ]; then
    EVT=${evt}
elif [ -r "${DFT_EVT}" ]; then
    EVT=${DFT_EVT}
else
    read -p "clean evt2 file: " EVT
    if [ ! -r "${EVT}" ]; then
        printf "ERROR: cannot access given \`${EVT}' evt file\n"
        exit ${ERR_EVT}
    fi
fi
printf "## use evt file: \`${EVT}'\n" | ${TOLOG}
# check given region file(s)
if [ -r "${reg}" ]; then
    SBP_REG="${reg}"
elif [ -r "${DFT_SBP_REG}" ]; then
    SBP_REG=${DFT_SBP_REG}
fi
printf "## use reg file(s): \`${SBP_REG}'\n" | ${TOLOG}
## check given `energy' {{{
if [ ! -z "${energy}" ]; then
    ENERGY="${energy}"
else
    ENERGY="${DFT_ENERGY}"
fi
# split energy variable
ENG_N=`echo ${ENERGY} | awk -F':' '{ print NF }'`
if [ ${ENG_N} -eq 1 ]; then
    E_START=`echo ${DFT_ENERGY} | awk -F':' '{ print $1 }'`
    E_END=`echo ${DFT_ENERGY} | awk -F':' '{ print $2 }'`
    E_WIDTH=${ENERGY}
elif [ ${ENG_N} -eq 2 ]; then
    E_START=`echo ${ENERGY} | awk -F':' '{ print $1 }'`
    E_END=`echo ${ENERGY} | awk -F':' '{ print $2 }'`
    E_WIDTH=`echo ${DFT_ENERGY} | awk -F':' '{ print $3 }'`
elif [ ${ENG_N} -eq 3 ]; then
    E_START=`echo ${ENERGY} | awk -F':' '{ print $1 }'`
    E_END=`echo ${ENERGY} | awk -F':' '{ print $2 }'`
    E_WIDTH=`echo ${ENERGY} | awk -F':' '{ print $3 }'`
else
    printf "ERROR: invalid energy: \`${ENERGY}'\n"
    exit ${ERR_ENG}
fi
ENG_RANGE="${E_START}:${E_END}"
printf "## use energy range: \`${ENG_RANGE}' eV\n" | ${TOLOG}
printf "## use energy width: \`${E_WIDTH}' eV\n" | ${TOLOG}
## parse energy }}}
# parameters (nH, z, avg_temp, avg_abund) used to calculate {{{
# `spectral weights' for `mkinstmap'
# check given nH
if [ -z "${nh}" ]; then
    read -p "> value of nH: " N_H
else
    N_H=${nh}
fi
printf "## use nH: ${N_H}\n" | ${TOLOG}
# check given redshift
if [ -z "${z}" ]; then
    read -p "> value of redshift: " REDSHIFT
else
    REDSHIFT=${z}
fi
printf "## use redshift: ${REDSHIFT}\n" | ${TOLOG}
# check given temperature
if [ -z "${temp}" ]; then
    read -p "> object average temperature: " TEMP
else
    TEMP=${temp}
fi
printf "## use temperature: ${TEMP}\n" | ${TOLOG}
# check given abundance
if [ -z "${abund}" ]; then
    read -p "> object average abundance: " ABUND
else
    ABUND=${abund}
fi
printf "## use abundance: ${ABUND}\n" | ${TOLOG}
# `spectral weights' parameters }}}
# check given dir
if [ -d "${basedir}" ]; then
    BASEDIR=${basedir}
elif [ -d "${DFT_BASEDIR}" ]; then
    BASEDIR=${DFT_BASEDIR}
else
    read -p "> basedir (contains asol files): " BASEDIR
    if [ ! -d "${BASEDIR}" ]; then
        printf "ERROR: given \`${BASEDIR}' NOT a directory\n"
        exit ${ERR_DIR}
    fi
fi
# remove the trailing '/'
BASEDIR=`echo ${BASEDIR} | sed 's/\/*$//'`
printf "## use basedir: \`${BASEDIR}'\n" | ${TOLOG}
## parameters }}}

## prepare parameter files (pfiles) {{{
CIAO_TOOLS="dmkeypar dmcopy dmhedit dmimgcalc ardlib make_instmap_weights skyfov get_sky_limits fluximage merge_all"

# Copy necessary pfiles for localized usage
for tool in ${CIAO_TOOLS}; do
    pfile=`paccess ${tool}`
    [ -n "${pfile}" ] && punlearn ${tool} && cp -Lvf ${pfile} .
done

# Modify environment variable 'PFILES' to use local pfiles first
export PFILES="./:${PFILES}"
## pfiles }}}

## check files in `basedir' {{{
# check asol files
ASOLIS=`\ls -1 ${BASEDIR}/${DFT_ASOLIS_PAT} | head -n 1`
if [ -z "${ASOLIS}" ]; then
    printf "ERROR: cannot find \"${DFT_ASOLIS_PAT}\" in dir \`${BASEDIR}'\n"
    exit ${ERR_ASOL}
fi
printf "## use asolis: \`${ASOLIS}'\n"
# check badpixel file
BPIX=`\ls -1 ${BASEDIR}/${DFT_BPIX_PAT} | head -n 1`
if [ -z "${BPIX}" ]; then
    printf "ERROR: cannot find \"${DFT_BPIX_PAT}\" in dir \`${BASEDIR}'\n"
    exit ${ERR_BPIX}
fi
printf "## use badpixel: \`${BPIX}'\n" | ${TOLOG}
# check msk file
MSK=`\ls -1 ${BASEDIR}/${DFT_MSK_PAT} | head -n 1`
if [ -z "${MSK}" ]; then
    printf "ERROR: cannot find \"${DFT_MSK_PAT}\" in dir \`${BASEDIR}'\n"
    exit ${ERR_MSK}
fi
printf "## use msk file: \`${MSK}'\n" | ${TOLOG}
## check files }}}

## determine ACIS type {{{
# consistent with `ciao_procevt'
punlearn dmkeypar
DETNAM=`dmkeypar ${EVT} DETNAM echo=yes`
if echo ${DETNAM} | \grep -q 'ACIS-0123'; then
    printf "## \`DETNAM' (${DETNAM}) has chips 0123\n"
    printf "## ACIS-I\n"
    ACIS_TYPE="ACIS-I"
    CCD="0:3"
    NEW_DETNAM="ACIS-0123"
    ROOTNAME="c0-3_e${E_START}-${E_END}"
elif echo ${DETNAM} | \grep -q 'ACIS-[0-6]*7'; then
    printf "## \`DETNAM' (${DETNAM}) has chip 7\n"
    printf "## ACIS-S\n"
    ACIS_TYPE="ACIS-S"
    CCD="7"
    NEW_DETNAM="ACIS-7"
    ROOTNAME="c7_e${E_START}-${E_END}"
else
    printf "ERROR: unknown detector type: ${DETNAM}\n"
    exit ${ERR_DET}
fi
## ACIS type }}}

## main process {{{
## set `ardlib' at first
printf "set \`ardlib' first ...\n"
punlearn ardlib
acis_set_ardlib badpixfile="${BPIX}"

## generate `spectral weights' for `instrumental map' {{{
printf "generate \`spectral weights' for making instrumental map ...\n"
SPEC_WGT="instmap_weights.txt"
# convert `eV' to `keV'
EMIN=`echo ${E_START} | awk '{ print $1/1000 }'`
EMAX=`echo ${E_END} | awk '{ print $1/1000 }'`
EWIDTH=`echo ${E_WIDTH} | awk '{ print $1/1000 }'`
punlearn make_instmap_weights
make_instmap_weights outfile="${SPEC_WGT}" \
    model="xswabs.gal*xsapec.ap" \
    paramvals="gal.nh=${N_H};ap.kt=${TEMP};ap.abundanc=${ABUND};ap.redshift=${REDSHIFT}" \
    emin="${EMIN}" emax="${EMAX}" ewidth="${EWIDTH}" \
    abund="grsa" clobber=yes
## spectral weights }}}

## generate `skyfov'
printf "generate skyfov ...\n"
SKYFOV="skyfov.fits"
punlearn skyfov
skyfov infile="${EVT}" outfile="${SKYFOV}" aspect="@${ASOLIS}" clobber=yes

## filter by energy band & make image
printf "filter out events in energy band: \`${ENG_RANGE}' ...\n"
EVT_E="evt2_${ROOTNAME}.fits"
if [ ! -r "${EVT_E}" ]; then
    punlearn dmcopy
    dmcopy infile="${EVT}[energy=${E_START}:${E_END}]" outfile="${EVT_E}" clobber=yes
fi

printf "make image ...\n"
IMG_ORIG="img_${ROOTNAME}.fits"
punlearn dmcopy
dmcopy infile="${EVT_E}[sky=region(${SKYFOV}[ccd_id=${CCD}])][bin sky=1]" \
    outfile="${IMG_ORIG}" clobber=yes

## modify `DETNAM' of image
printf "modify keyword \`DETNAM' of image -> \`${NEW_DETNAM}'\n"
punlearn dmhedit
dmhedit infile="${IMG_ORIG}" filelist=none operation=add \
    key=DETNAM value="${NEW_DETNAM}"

## get `xygrid' for image
punlearn get_sky_limits
get_sky_limits image="${IMG_ORIG}"
XYGRID=`pget get_sky_limits xygrid`
printf "## get \`xygrid': \`${XYGRID}'\n" | ${TOLOG}

EXPMAP="expmap_${ROOTNAME}.fits"
IMG_EXPCORR="img_expcorr_${ROOTNAME}.fits"

# Check whether fluximage is capable to make exposure correction for us
# version after '15Oct2012' supports 'xygrid' and spectral weights file.
if `pget fluximage xygrid >/dev/null 2>&1`; then
    USE_FLUXIMAGE="YES"
else
    # 'fluximage' do not support 'xygrid' parameter and spectral weights.
    # fallback to use 'merge_all'
    USE_FLUXIMAGE="NO"
fi

if [ "${USE_FLUXIMAGE}" = "YES" ]; then
    ## 'fluximage' is available, use it by default
    ## use 'fluximage' to generate `exposure map' and apply exposure correction
    printf "use fluximage to generate expmap and apply correction ...\n"
    punlearn fluximage
    fluximage infile="${EVT_E}" outroot="${ROOTNAME}" \
        binsize=1 bands="${SPEC_WGT}" xygrid="${XYGRID}" \
        asol="@${ASOLIS}" badpixfile="${BPIX}" \
        maskfile="${MSK}" clobber=yes
    ## make symbolic links
    # clipped counts image
    ln -svf ${ROOTNAME}*band*thresh.img ${IMG_ORIG%.fits}_thresh.fits
    # clipped exposure map
    ln -svf ${ROOTNAME}*band*thresh.expmap ${EXPMAP}
    # exposure-corrected image
    ln -svf ${ROOTNAME}*band*flux.img ${IMG_EXPCORR}
else
    # 'merge_all' is available, fallback to this
    printf "fallback to merge_all ...\n"
    ## XXX: `merge_all' needs `asol files' in working directory
    printf "link asol files into currect dir (\`merge_all' needed) ...\n"
    for f in `cat ${ASOLIS}`; do
        asol=`basename ${f}`
        ln -svf ${BASEDIR}/${asol} .
    done

    printf "use \`merge_all' to generate \`exposure map' ONLY ...\n"
    punlearn merge_all
    merge_all evtfile="${EVT_E}" asol="@${ASOLIS}" \
        chip="${CCD}" xygrid="${XYGRID}" \
        energy="${SPEC_WGT}" expmap="${EXPMAP}" \
        dtffile="" refcoord="" merged="" expcorr="" \
        clobber=yes

    ## apply exposure correction
    printf "use \`dmimgcalc' to apply \`exposure correction' ...\n"
    punlearn dmimgcalc
    dmimgcalc infile="${IMG_ORIG}" infile2="${EXPMAP}" \
        outfile="${IMG_EXPCORR}" operation=div clobber=yes
fi

## main }}}

exit 0