#!/usr/bin/env python
# Name:		lytle_convert
# Purpose:	Convert Farrel Lytle data files from steps to energy
#           and output in SFF format.  This program supports
#			conversion of two different file types.  Those which 
#			have a header beginning with NPTS and containing DSPACE and 
#			the older files with begin with CUEDGE and do not contain
#			d-spacing information. 
# Author:	Carlo U. Segre <segre@iit.edu>
#
# Copyright 2009 Illinois Institute of Technology
#
# Version:
#	1.0		2009/02/03	Carlo Segre
#			* Initial release
#	1.1		2009/02/11	Carlo Segre
#			* Replace Numeric with numpy
#			* Open output file after checking for supported input 
#			  file format
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
# Except as contained in this notice, the name of Illinois Institute
# of Technology shall not be used in advertising or otherwise to promote
# the sale, use or other dealings in this Software without prior written
# authorization from Illinois Institute of Technology.
#

__version__ = '1.1'
__rcsid__ = '$Id$'
__source__ = '$Source$'

import os
import sys
import getopt
from string import *
from struct import *
import commands
import time
import numpy

def usage(error=1):
	usage = """\
	
Usage: %s [OPTION]... INFILE0 [INFILE1 ... INFILEn]
Converts Farrel Lytle data files from steps to energy.

Options:
   -h, --help    Print this message
   
""" % os.path.basename(sys.argv[0])

	if error:
		sys.stderr.write(usage)
		sys.exit(1)
	else:
		sys.stdout.write(usage)
		sys.exit()


def main(rawFile, convFile):

    inFile = open(rawFile, "r")

    lines = inFile.readlines()

    vars = lines[0].split()
    if vars[0] == "NPTS" :
        fileType = "new"
        vals = lines[1].split()
    elif vars[0] == "CUEDGE" :
        fileType = "old"
        vals = vars[5:]
        vars = vars[:5]
    else :
        sys.stderr.write("Unknown file format!\n")
        sys.exit(1)
    
    ouFile = open(convFile, "w")
    pi = numpy.arccos(-1.)
    hc = 12398.5
    energyCu = 8980.3
    edgeCu = float(vals[vars.index('CUEDGE')])
    if fileType == "new" :
        stepDegree = float(vals[vars.index('STPDEG')])
        d = float(vals[vars.index('DSPACE')])
        numPts = int(vals[vars.index('NPTS')])
        numScalers = int(vals[vars.index('NS')])
        scale = float(vals[vars.index('SCALE')])
    else:
#		For the "old" file type, the following assumptions are made:
#				dSpacing = 1.92017
#				stepDegree = 2000 * int(edgeCu / 42000)
#		make sure to change these if converted files do not have the
#		correct energy.
        stepDegree = int((edgeCu / 42000) + 0.5) * 2000
        d = 1.92017
        numPts = (len(lines) - 5) * 4
        numScalers = 1
    start = float(vals[vars.index('START')])
    stop = float(vals[vars.index('STOP')])
    thetaCu=numpy.arcsin(hc/(2*d*energyCu))

    steps = numpy.zeros((numPts), dtype=float)
    scalers = numpy.zeros((numPts, numScalers), dtype=float)
    if fileType == "new" :
        i = 0
        while i < numPts :
            try :
                tmp = lines[i + 7].split()
            except IndexError :
                numPts = i
                break
            try :
                steps[i] = float(tmp[0])
            except IndexError :
                numPts = i
                break
            j = 0
            while j < numScalers :
                scalers[i,j] = float(tmp[j + 1])
                j = j + 1
            i = i + 1
    else :
        i = 0
        while i < numPts :
            try :
                tmp = lines[(i / 4) + 5].split()
            except IndexError :
                numPts = i
                break
            k = 0
            while k < 4 :
                try :
                    steps[i] = float(tmp[2 * k])
                    scalers[i,0] = float(tmp[(2 * k)+1])
                except IndexError :
                    numPts = i
                    break
                k = k + 1
                i = i + 1
                    
    theta = ((steps - edgeCu) / stepDegree) * (pi / 180.) + thetaCu
    energy = hc / (2 * d * numpy.sin(theta))

    if fileType == "new" :
        ouFile.write('# SFF main_header 12\n')
    else :
        ouFile.write('# SFF main_header 11\n')
    ouFile.write('# raw_data_file = "' + rawFile +'";\n')
    ouFile.write('# source = "Farrel Lytle Database";\n')
    timestamp = time.strftime('%m-%d-%G %H:%M:%S').split()
    ouFile.write('# conversion_timestamp = ' + str(timestamp) + ';\n')
    ouFile.write('# d_spacing = "' + str(d) + '";\n')
    ouFile.write('# steps_per_degree = "' + str(stepDegree) + '";\n')
    ouFile.write('# step_start = "' + str(vals[vars.index('START')]) + '";\n')
    if fileType == "new" :
        ouFile.write('# step_deltas = "' + 
                lines[2][lines[2].find('DELTA:') + 6:].strip() + '";\n')
        ouFile.write('# region_ends = "' +
                lines[3][lines[3].find('DELEND:') + 7:].strip() + '";\n')
        ouFile.write('# count_times = "' + 
                lines[4][lines[4].find('SEC:') + 4:].strip() + '";\n')
        ouFile.write('# offsets = "' + 
                lines[5][lines[5].find('OFFSET:') + 7:].strip() + '";\n')
        ouFile.write('# sample = "' + lines[6].strip() + '";\n')
        scalerList = ""
        j = 0 
        while j < numScalers :
            scalerList = scalerList + 'scaler' + str(j) + ' '
            j = j + 1
        ouFile.write('# %devices = "energy ' + scalerList + 'steps";\n')
    else :
        ouFile.write('# step_deltas = "' + 
                lines[1][lines[1].find('DELTA:') + 6:].strip() + '";\n')
        ouFile.write('# region_ends = "' +
                lines[2][lines[2].find('DELEND:') + 7:].strip() + '";\n')
        ouFile.write('# count_times = "' + 
                lines[3][lines[3].find('SEC:') + 4:].strip() + '";\n')
        ouFile.write('# full_scale_counts = "' + 
                str(vals[vars.index('FSCTS:')]) + '";\n')
        ouFile.write('# sample = "' + lines[4].strip() + '";\n')
        ouFile.write('# %devices = "energy mu(E) steps";\n')

    i = 0
    while i < numPts :
        if energy[i] < 0 :
            break
        ouFile.write('%8.2f' % energy[i] + '\t')
        if fileType == "new" :
            j = 0 
            while j < numScalers :
                ouFile.write('%10.2f' % scalers[i,j] + '\t')
                j = j + 1
        else :
            ouFile.write('%10.6f' % scalers[i,0] + '\t')
        ouFile.write('%8.0f' % steps[i] + '\n')
        i = i + 1

    inFile.close()
    ouFile.close()

if __name__ == '__main__':

    try:
        opts, args = getopt.getopt(sys.argv[1:], 'h', ['help'])
    except getopt.error:
        sys.stderr.write("%s: %s \nTry `%s --help` for more informatIon\n"
            % (PROGNAME, e, PROGNAME))
        sys.exit(1)

    for o in opts:
        if o in ('-h', '--help'):
            usage(error=0)
	
    if len(args) == 0:
        usage()

    for infile in args:
        oufile = '_'.join(infile.split('.')) + '.sff'
        main(infile, oufile)
