kcas_calib

Parses a calibration flat file and take calibration images

usage: kcas_calib: [-h, --help] [-f, --file] [-n, --night] [-p, --park] [-d, --dry-run]

-h , --help

show this help message and exit

-f

File to load cal script from

-n

Is this a night-time calibration (auto-parks) ?

-p

Park calibration unit at the end

-d

List steps but do not execute calibrations

#! @KPYTHON@

from KCWI import Calibration, Blue
from KCWI.Helper import say
import argparse
import sys, os, time
import ktl
import signal


# Parsing arguments
description = "Parses a calibration flat file and take calibration images"
parser = argparse.ArgumentParser(description=description)
parser.add_argument('-f','--file',dest='filen',nargs="?",default=None, help='File to load cal script from')
parser.add_argument('-n','--night',dest='night',default=False, help='Is this a night-time calibration (auto-parks) ?', action='store_true')
parser.add_argument('-p','--park',dest='park',default=False, help='Park calibration unit at the end', action='store_true')
parser.add_argument('-d','--dry-run',dest='dry',default=False, help='List steps but do not execute calibrations', action='store_true')

thar_lampid=1
fear_lampid=0
cont_lampid=3
dome_lampid=-1
bias_lampid=-2
dark_lampid=-3


def sig_handler(signum, frame, dry):

    say("Stop (CTRL+C) detected.")

    # turns lamps off
    execute(dry, Calibration.lamp,'all','off')    

    # CLOSE shutters
    execute(dry, Calibration.lamp_shutter,'thar','close')
    execute(dry, Calibration.lamp_shutter,'fear','close')

    # abort exposure
    exposeip = ktl.cache('kbds','exposip')
    if exposeip.read() == 1:
        say("Aborting current exposure")
        abortex = ktl.cache('kbs','abortex')
        execute(dry, abortex.write, 1)
        
    # abort movements
    status = ktl.cache('kcas','status')
    status.monitor()

    if status.read() == 'Moving':
        abort = ktl.cache('kcas','abort')
        execute(dry, abort.write, 1)

    ok = ktl.Expression('kcas.status == OK')
    result = ok.wait(timeout = 30)
    execute(dry, Calibration.cal_mirror, 'Sky')

    sys.exit(0)



def printInfo(calibration):
    say("")
    say("Executing the following calibration:")
    say("Lamp: %s, Object: %s, Exptime: %s, Afternoon exposures: %s, Night exposures: %s, Geometry: %s" % \
        (calibration['lamp'],calibration['object'],calibration['exptime'],calibration['afternoon'],calibration['night'],calibration['geometry']))

def setObject(calibration):
    if calibration['geometry']=='1':
        geometryFlag = "/Mode=Geom"
    else:
        geometryFlag = ""
    if calibration['lamp']=='DARK':
        lampFlag = "None"
    else:
        lampFlag = calibration['lamp']

    currentObject = "Lamp=%s/CalObj=%s/Expt=%s sec.%s" % (lampFlag,calibration['object'],calibration['exptime'],geometryFlag)
    say("Setting object to: %s" % (currentObject))
    object = ktl.cache('kbds','object')
    object.write(currentObject)


# this is a wrapper that disables the functions if in dry-run mode

def execute(dry, func, *args, **kwargs):

    if not dry:
        func(*args, **kwargs)
    else:
        string_args = []
        for arg in args:
            string_args.append(str(arg))

        print "DRY RUN: %s(%s)" % (func.__name__, 
                                       ','.join(list(string_args) + ["%s=%s" % (str(k), str(v)) for (k, v) in kwargs.iteritems()])) 


def convertLampNametoID(lampname):
    lampname = lampname.lower()

    if lampname in ['thar','tha','th','t',1]:
        lampid = thar_lampid
    elif lampname in ['fear','fea','fe','f','f',0]:
        lampid = fear_lampid
    elif lampname in ['continuum','cont','led',3]:
        lampid = cont_lampid
    elif lampname in ['dome','dom','d',-1]:
        lampid = dome_lampid
    elif lampname in ['bias','bs',-2]:
        lampid = bias_lampid
    elif lampname in ['dark','dar','dk']:
        lampid = dark_lampid
    else:
        say("Error: Invalid lamp %s" % (lampname))
        sys.exit(1)
    return lampid

def CheckObjectName(object):
    object = object.lower()
    if object in ['dark','0','pin300','1','medbarsa','medbars','2','medbarsb','3','finbars','4', \
                  'diaglin','5','flata','flat','6','flatb','7','lrgbarsa','lrgbars','8','lrgbarsb', \
                  'lrgbars','9','pin500','10','tpat','11','horlin','12','mira','13']:
       return
    else:
       say("Error: Unkown object %s" % (object))
       sys.exit(1)

def convertGeometryFlag(flag):
    flag = flag.lower()
    if flag in ['yes','y','1']:
                   convflag = 1
    elif flag in ['no','n','0']:
                   convflag = 0
    return convflag


def kcas_calib(filen,night,park, dry):

    caltype="day"
    park=0

    dark = False

    if night:
        caltype='night'
        park = 1

    thar_used=0
    fear_used=0
    dome_used=0

    expectedNumberOfColumns = 6

    # record current detector status

    detAmpmodeInit = Blue.ampmodeb()
    detGainMulInit = Blue.gainmulb()
    detCcdModeInit = Blue.ccdmodeb()
    detExptimeInit = Blue.tintb()


    detSleep = 2

    # create an empty array of calibrations to be executed
    # this will be an array of dictionaries

    Calibrations = []
    
    # check if the file exists, and read it

    try:
        say("Opening file %s" % (filen))
        calFile = open(filen,"r")
        lines = calFile.readlines()
        calFile.close()
    except:
        raise RuntimeError("The input flat file does not exist")

    # process the lines

    for line in lines:

        # skip comments

        if '#' in line:
            continue

        # if the line contains an = sign, then it indicates the original state file

        if '=' in line:
            statusFile = line.split('=')[1]
            continue
        
        # for all other cases, ingest the information

        data = line.split()
        if len(data) != expectedNumberOfColumns:
            say("Skipping line: %s" % line)
            continue
        else:
            calibration = {}
            calibration["lamp"]=data[0]
            calibration["object"]=data[1]
            calibration["exptime"]=data[2]
            calibration["afternoon"]=data[3]
            calibration["night"]=data[4]
            calibration["geometry"]=data[5]
            
            # add the current calibration line to the array
            Calibrations.append(calibration)

    # make sure the calibration axes are homed

    kcas = ktl.cache('kcas')
    calxhomed = kcas['calxhomed']
    calyhomed = kcas['calyhomed']
    calmhomed = kcas['calmhomed']

    for axis in [calxhomed,calyhomed,calmhomed]:
        if int(axis['ascii'])==0:
            say("Calibration axis %s is not homed" % axis['NAME'])
            exit(1)
    
    # conversions and checks

    for calibration in Calibrations:
        # lamp
        calibration["lampid"] = convertLampNametoID(calibration["lamp"])
        # object
        CheckObjectName(calibration["object"])
        # geometry
        calibration["geometry"] = convertGeometryFlag(calibration["geometry"])

    # check which lamps are used (continumm is always used)

    thar_used = 0 
    fear_used = 0
    dome_used = 0
    
    for calibration in Calibrations:
        if (caltype == 'day' and int(calibration['afternoon']) > 0) or (caltype == 'night' and int(calibration['night']) > 0):
            if calibration['lampid'] == thar_lampid:
                thar_used = 1
            if calibration['lampid'] == fear_lampid:
                fear_used = 1
    
        if (caltype == 'day' and int(calibration['afternoon']) > 0):

            if calibration['lampid'] == dome_lampid:
                dome_used = 1

    say("Caltype   = %s" % (caltype))
    say("Thar used = %s" % (str(thar_used)))
    say("Fear used = %s" % (str(fear_used)))
    say("Dome used = %s" % (str(dome_used)))

    
    if (thar_used):
        execute(dry,Calibration.lamp,'thar','on')
        execute(dry,Calibration.lamp_shutter,'thar','close')

    if (fear_used):
        execute(dry,Calibration.lamp,'fear','on')
        execute(dry,Calibration.lamp_shutter,'fear','close')

    # Close the hatch
    
    execute(dry,Calibration.hatch,'close')
    
    # Loop through the calibrations (INTERNAL ONLY)

    for calibration in Calibrations:
        
        # skip the dome calibration
        if calibration['lampid'] == dome_lampid:
            continue

        #
        time.sleep(1)


        # print info
        printInfo(calibration)
        # set object
        setObject(calibration)

        if caltype == 'day':
            count = calibration['afternoon']
        elif calitype == 'night':
            count = calibration['night']

        say("Count:   %s" % (count))

        say("Geomtry: %s" % (calibration['geometry']))

        autoshut = ktl.cache('kbds','autoshut')
        if int(count) > 0:
            if calibration['lampid'] == fear_lampid:
                execute(dry, Calibration.lamp_shutter,'fear','open')
                execute(dry, Calibration.lamp_shutter,'thar','close')
                execute(dry, Calibration.lamp,'cont','off')
                dark = False

            if calibration['lampid'] == thar_lampid:
                execute(dry, Calibration.lamp_shutter,'fear','close')
                execute(dry, Calibration.lamp_shutter,'thar','open')
                execute(dry, Calibration.lamp,'cont','off')
                dark = False

            if calibration['lampid'] == cont_lampid:
                execute(dry, Calibration.lamp_shutter,'fear','close')
                execute(dry, Calibration.lamp_shutter,'thar','close')
                execute(dry, Calibration.lamp,'cont','on')
                dark = False

            if calibration['lampid'] == dark_lampid or calibration['lampid'] == bias_lampid:
                execute(dry, Calibration.lamp_shutter,'fear','close')
                execute(dry, Calibration.lamp_shutter,'thar','close')
                execute(dry, Calibration.lamp,'cont','off')
                dark = True



        # move mirror axis

        execute(dry, Calibration.cal_mirror,position="Mirror")

        # move calx and caly objects

        execute(dry, Calibration.cal_object,position=calibration['object'])

        # set exposure time

        execute(dry, Blue.tintb,str(calibration['exptime']))

        # if geometry is set to 1, modify the detector configuration

        if calibration['geometry'] != 0:
            execute(dry, Blue.ampmodeb,0)
            execute(dry, Blue.gainmulb,10)
            execute(dry, Blue.ccdmodeb,1)

        # otherwise restore the initial configuration
        else:
            execute(dry, Blue.ampmodeb,detAmpmodeInit)
            execute(dry, Blue.gainmulb,detGainMulInit)
            execute(dry, Blue.ccdmodeb,detCcdModeInit)

        # exposure time

        execute(dry, Blue.tintb,calibration['exptime'])

        # take exposures

        say("Exposing. Count = %d, Dark = %s." % (int(count),str(dark)))
        execute(dry, Blue.goib,count, dark)

        # turn off continuum
        
        execute(dry, Calibration.lamp,'cont','off')
        
        # close arc shutters
    
        execute(dry, Calibration.lamp_shutter,'thar','close')
        execute(dry, Calibration.lamp_shutter,'fear','close')

        # return detector to initial configuration

        execute(dry, Blue.ampmodeb,detAmpmodeInit)
        execute(dry, Blue.gainmulb,detGainMulInit)
        execute(dry, Blue.ccdmodeb,detCcdModeInit)            
    
    # Loop through the calibrations (DOME ONLY)
    dark = False

    if dome_used:

        for calibration in Calibrations:
        
            # skip the internal calibrations
            if calibration['lampid'] != dome_lampid:
                continue

            # print info
            printInfo(calibration)

            if caltype == 'day':
                count = calibration['afternoon']
            elif calitype == 'night':
                count = calibration['night']

            say("Count:   %s" % (count))

            say("Geomtry: %s" % (calibration['geometry']))           

            # TURN ON DOME LAMPS

            # INSERT A CALL TO THE COMMAND TO TURN ON DOME LAMPS TBD !!!!!!!!

            # open hatch

            execute(dry, Calibration.hatch,'open')

            # move cal mirrot out of the way

            execute(dry, Calibration.cal_mirror,position='Sky')

            # move cal x y in place

            execute(dry, Calibration.cal_object,position=calibration['object'])

            # set exposure time
        
            execute(dry, Blue.tintb,calibration['exptime'])

            # take exposures

            say("Exposing. Count = %d, Dark = %s." % (int(count),str(dark)))
            execute(dry, Blue.goib,count, dark)

        
    # return exposure time to original

    execute(dry, Blue.tintb,detExptimeInit)
   
    # close arc shutters, turns off continuum

    execute(dry, Calibration.lamp_shutter,'thar','close')
    execute(dry, Calibration.lamp_shutter,'fear','close')
    execute(dry, Calibration.lamp,'cont','off')

    if park:
        # turns off lamps
        execute(dry, Calibration.lamp,'all','off')
        execute(dry, Calibration.cal_object,'Dark')
        execute(dry, calibration.cal_mirror,'Sky')


if __name__ == '__main__':

   args = parser.parse_args()


   filen = args.filen
   night = args.night
   park = args.night
   dry = args.dry

   signal.signal(signal.SIGINT,sig_handler)
   signal.signal(signal.SIGILL,sig_handler)
   signal.signal(signal.SIGTERM,sig_handler)


   kcas_calib(filen, night, park, dry)