# 
#  Copyright (C) 2011-2012,2014-2016,2019,2021  Smithsonian Astrophysical Observatory
#
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#



""" 
test pypixlib modules
"""

from __future__ import print_function

from pydoc import help   #for run-time help
import unittest
import sys,os,math
import numpy as np 
from pixlib import *

def show_whoami():
    print('\n---', sys._getframe(1).f_code.co_name)

def usage():
    """Show the usage with example for Caldb python module."""
    
    print("""\nUsage:\n\
           % python test_pixlib.py [opt] [-v]
           opt:
              -aim:   test aimpoint
              -det:   test detector
              -def:   test default
              -gra:   test grating
              -cor:   test coordinates transfer
              -gen:   test general funtions
              -ext:   test extened chip transfers
              -fai:   test expected failures
                -u:   this message
                -v:   debug option\n""")



DEBUG=0
class TestPixlib(unittest.TestCase):
    def setUp(self):
        global DEBUG
        if "-v" in  sys.argv:
            DEBUG=1
            #sys.argv.remove("-v")
            
    def tearDown(self):
        """ un-import caldb4 ?"""
        nm=['pix', '']
        while True:
            if nm[0] in sys.modules:
                del (sys.modules[nm[0]])
                del (nm[0])
            else:
                break
        return
   

#=======================================
# aimpoint - test aimpoint
#
# AI1    : (   -0.782     0.000  -237.500 )
# HI1    : (   -1.040     0.000   126.985 )
# HS1    : (   -1.430     0.000   250.456 )
# HSI1   : (   -1.430     0.000   250.456 )
# A2C0   : (   -1.430     0.000   250.456 )
# AS1    : (   -0.684     0.000  -190.133 )
# AI2    : (   -0.782     0.000  -233.592 )
# HS2    : (   -1.533     0.000   250.456 )

#========================================
    def test_aimpoint(self):
        p = Pixlib("chandra")
        print("\nTest pixlib Aimpoints ","-"*10)


        print("-- Default aimpoint: ")
        print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord) )

        print("\n-- Set aimpoint in alias:\n")
        p.aimpoint="AI2"
        print(repr(str(p.aimpoint))," = ",pixlib.set_decim_pts(p.aimcoord) )
    
        p.aimpoint="hi1"
        print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord) )

        p.aimpoint="hs1"
        print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord) )

        p.aimpoint="as1"
        print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord) )
  
        p.aimpoint="hs2"
        print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord) )

        print("\n-- Set aimpoint by value:")
        p.aimpoint = -0.78234819833843305,0.0,-233.5924630914318
        aimname=p.aimpoint
        if p.isokay == 1:
            print(repr(str(aimname)), " = ",pixlib.set_decim_pts(p.aimcoord), "\n")
        else:
            print(p)
     

        print("\n-- Expected error returned from setting 'hsi1, a2c0, mypnt' -> ")
        p.aimpoint="HSI1"
        if p.isokay == 1:
            print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord))
        else:
            print("\t"+p.errmsg)

        p.aimpoint="A2C0"
        if p.isokay == 1:
            print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord))
        else:
            print("\t"+p.errmsg)

        p.aimpoint="mypnt"
        if p.isokay == 1:
            print(repr(str(p.aimpoint)), " = ",pixlib.set_decim_pts(p.aimcoord) )
        else:
            print("\t"+p.errmsg+"\n")

        p.close
 
 #Note:
 # there may be 'Segmentation fault' at the exit of the routine
 # it is probably due to some of compiling options
 #

 
    def test_detector(self):
        p = Pixlib("chandra")
        print("\nTest pixlib Detectors ","-"*10)
        detid=p.detector
        print("-- Default detector: ")
        print(repr(str(detid)), " -> expected: acis")

        print("\n-- Set detector in string:")
        p.detector="acis-i"
        detid=p.detector
        print(repr(str(detid)), "    -> expected: acis")

        p.detector="acis-s1"
        detid=p.detector
        print(repr(str(detid)), "    -> expected: acis")

        p.detector="hrc-i"
        detid=p.detector
        print(repr(str(detid)), "   -> expected: hrc-i")

        p.detector="hrc-s"
        detid=p.detector
        print(repr(str(detid)), "   -> expected: hrc-s")

        p.detector="hsi-i"
        detid=p.detector
        print(repr(str(detid)), "     -> expected: hsi")

        p.detector="acis-2c"
        detid=p.detector
        print(repr(str(detid))," -> expected: acis-2c")

        p.close
  
    def test_default(self):
        p = Pixlib()
        print("\nTest pixlib defaults ","-"*10)

        print("detector: ", repr(str(p.detector)), "             -> expected: 'acis'")
        print("aimpoint: ", repr(str(p.aimpoint)), "              -> expected: 'ai1'")
        print(" tdetsys: ", repr(str(p.tdetsys)), "         -> expected: 'ACIS-2.2'")
        print("   fpsys: ", repr(str(p.fpsys)), "           -> expected: 'FP-1.1'")
        print("  gdpsys: ", repr(str(p.gdpsys)), "      -> expected: 'ASC-GDP-1.1'")
        print(" grating: ", repr(str(p.grating)), "              -> expected: 'HEG'")
  
        p.close
    
    def test_grating(self):
        p = Pixlib()
        print("\n-- Test pixlib Grating ","-"*10)

        print("\n-- See what grating defaults are ...")
        print("Grating  = ", p.grating)
        if p.grt_zo[0]==None:
            print("grt_ZO   = ", p.grt_zo) 
        else:
            print("grt_ZO   = ", pixlib.set_decim_pts(p.grt_zo) )
        print("grt_prop = ", pixlib.set_decim_pts(p.grt_prop, 4))
   
        print("\n-- Set gratings arm ...")
        p.grating='leg'
        print("Grating = ", p.grating)
        print("grt_prop = ", pixlib.set_decim_pts(p.grt_prop, 4))

        print("\n-- Set gratings arm and order ...")
        p.grating=['meg',2]
        print("Grating   = ", p.grating)
        print("grt_order = ", p.grt_order)
        print("grt_prop  = ", pixlib.set_decim_pts(p.grt_prop, 4))
 
        print("\n-- GDP sys ...")
        print("default GDP sys = ", p.gdpsys)
        p.gdpsys = "gdp-1.2"
        print("GDP sys = ", p.gdpsys)
        p.gdpsys = "gdp-1.3"
        print("GDP sys = ", p.gdpsys)
        p.gdpsys = "gdp-1.4"
        print("\n-- Expected error from setting gdp-1.4 ->")
    #ERROR: Unsupported grating diffraction plane system name, at 'gdp-1.4'.

        if p.isokay != 1:
            print(p)
        else:
            print("GDP sys = ", p.gdpsys)
    
        print("-- Expected error from getting energy without argument ->")
        grt_energy = p.grt_energy()
        if p.isokay != 1:
            print(p)
        else:
            print("grt-energy = ", pixlib.set_decim_pts(grt_energy))
       
        grt_energy = p.grt_energy((0.3,0.5))
        print("grt-energy = ",  pixlib.set_decim_pts(grt_energy) )
        grt_wavelen =p.grt_wavelen()
        if p.isokay != 1:
            print(p)
        else:
            print("grt-wavelen = ",  pixlib.set_decim_pts(grt_wavelen))

        print("grt-energy = ",  pixlib.set_decim_pts(p.grt_energy()))
        print("\nAll curr inputs/updates:", p.curstat())
    
        p.close
  
    def test_general(self):
        p = Pixlib("chandra")
        print("\n-- Test pixlib general functions ","-"*10)

        print("\nfoc length: ",pixlib.set_decim_pts(p.flength,1), \
            "\t -> expected: 10070.0")
        stg=1.1,2.2,3.3
        ang=23.0
        p.mirror=(stg,ang)
        print("\nstg pos&angle: (",pixlib.set_decim_pts(stg,1),",", pixlib.set_decim_pts(ang,1),")" \
            "\t -> expected: ( (1.1, 2.2, 3.3) , 23.0 )")

        p.grt_zo=3.0,2.0                          # set grt_zo with fc_zo input for 'FC <-> GZO' transformation matrices
        print("\nzero-order in error: ",p.grt_zo) # get grt_zo via fc2gzo_transf matrix
        print(p)
        
        p.grt_zo=3.0,2.0,1.0
        print("grt_zo: ",pixlib.set_decim_pts(p.grt_zo,4), " corr to fc_zo: (3.0,2.0,1.0)" )


        p.grt_order='5'
        print("grt-order in error: ",p.grt_order)
        print(p)
        p.grt_order=5
        print("grt-order: ",p.grt_order, \
            "\t -> expected:  5")
    
        p.grating='leg',4
        print("grating and order: ",p.grating, p.grt_order,\
            "\t -> expected:  leg 4")

        print("\nfp-scale: ", pixlib.set_decim_pts(p.fp_scale,3),\
            "\t -> expected:  0.492\n")
    
        p.close

    
    
    def test_transfer(self):
        p = Pixlib("chandra")
        print("\nTest pixlib coords conversion ","-"*10)


    #ACIS-2.2  ACIS-I3 ID  3  CHIP: (783.8,894.0) TDET: (  5132.00,   3844.80)
    #ACIS-2.2        ACIS-S2 ID  6    DET_coords: (  3658.80,   1702.00)

        id=2 
        chip=140.47,58.37 
        p.aimpoint="AI2"
        print("set aimpoint at ",p.aimpoint)
        lsi=p.chip2lsi([id, chip])
    #lsi= (1.2287446656894812, -25.155139506394796, -5.3452310290900176)
        print("chip2lsi:\n\tid,chip=", id,pixlib.set_decim_pts(chip),"\n\tlsi=",pixlib.set_decim_pts(lsi))

        p.fpsys="FP-1.0"
        print("set fpsys at", p.fpsys)
        fpc=p.chip2fpc((id, chip))
    #fpc=  3096.602,  4194.244
        print("chip2fpc:\n\tid,chip=", id,pixlib.set_decim_pts(chip),"\n\tfpc=",pixlib.set_decim_pts(fpc))
        msc=p.fpc2msc(fpc)
    #msc= (-10068.899462934856, 0.13953637467448429, 174.41686952444726)
        print("fpc2msc:\n\tfpc=", pixlib.set_decim_pts(fpc),"\n\tmsc=",pixlib.set_decim_pts(msc))
    
    
        p.aimpoint="AI1"
        print("set aimpoint at ",p.aimpoint)
        print("set tdet-sys at", p.tdetsys)
        id=3
        chip=783.8,894.0
        tdet=p.chip2tdet((id, chip))
        print("chip2tdet:\n\tid,chip=", id,pixlib.set_decim_pts(chip),"\n\ttdet=",pixlib.set_decim_pts(tdet))
        if p.isokay != 1:
            print(p)


        # tdet= 1.0, 7168.0
        #
        # Here below had been indentated since version @@/main/7, 2012
        #      so never got tested since, but re-instored on March,2021
        # 
        (id,chip)=p.tdet2chip(tdet)
        print("tdet2chip:\n\ttdet=",pixlib.set_decim_pts(tdet),"\n\tid,chip=", id,pixlib.set_decim_pts(chip))
        if p.isokay != 1:
            print(p)

 
        id,chip_e=3,(783.8)
        fpc=p.chip2fpc((id,chip_e))
        print("chip2fpc:\n\tid,chip=", id,chip_e,"\n\tfpc=",fpc)
        print(" -> expected error")
        if p.isokay != 1:
            print(p.errmsg+"\n")
        
        id_n_chip_e=3,(783.8,)
        fpc=p.chip2fpc(id_n_chip_e)
        print("chip2fpc:\n\tid,chip=", id_n_chip_e,"\n\tfpc=",fpc)     
        print(" -> expected error")
        if p.isokay != 1:
            print(p)


        fpc=p.chip2fpc((id,chip))
        print("chip2fpc:\n\tid,chip=", id,pixlib.set_decim_pts(chip),"\n\tfpc=",pixlib.set_decim_pts(fpc))     

        fpc_e=-35.7,981.5
        id_e_n_chip_e=p.fpc2chip(fpc_e)
        print("fpc2chip:\n\tfpc=", fpc_e,"\n\tid,chip=",id_e_n_chip_e)
        if p.isokay != 1:
            print(p)
        else:
            print(" -> expected an extended-chip (negative values).\n" )
            # expected: 
            #   Warning: out of fpc bounds, 
            #   ERROR: Can't find intersection on detector, Fail to do lsi ray to cpc transf.
            # but not thrown. 
            #
            # It is due to fpc2chip, modified later, went fpc2ExtendedChip with resulting
            # extended chips (negative pixels as displayed in the printout above)
            #

        id_e_n_chip_e=p.fpc2chip(fpc)
        print("fpc2chip:\n\tfpc=", pixlib.set_decim_pts(fpc),"\n\tid,chip=", id_e_n_chip_e)
        if p.isokay != 1:
            print(p)
        
        gdp=p.chip2gdp((id,chip))
        print("chip2gdp:\n\tid,chip=", id,pixlib.set_decim_pts(chip),"\n\tgdp=",pixlib.set_decim_pts(gdp))
        if p.isokay != 1:
            print(p.errmsg+"\n")

        gdp=p.fpc2gdp(fpc)
        print("fpc2gdp:\n\tfpc=", pixlib.set_decim_pts(fpc),"\n\tgdp=",pixlib.set_decim_pts(gdp))
        if p.isokay != 1:
            print(p.errmsg+"\n")

        msc=p.fpc2msc(fpc)
        print("fpc2msc:\n\tfpc=", pixlib.set_decim_pts(fpc),"\n\tmsc=",pixlib.set_decim_pts(msc))
        fpc=p.msc2fpc(msc)
        print("msc2fpc:\n\tmsc=", pixlib.set_decim_pts(msc),"\n\tfpc=",pixlib.set_decim_pts(fpc))
        if p.isokay != 1:
            print(p.errmsg+"\n")


        aspoffs = 0.25,0.35
        sky=p.app_aspect(fpc, aspoffs)
        print("app_aspect:\n\tfpc=", fpc,"\n\tsky=",sky)
        print("\taspoffs=", aspoffs)
        print(" -> expected error")
        if p.isokay != 1:
            print(p.errmsg+"\n")

        aspoffs = 0.25,0.35,0.0
        sky=p.app_aspect(fpc, aspoffs)
        print("app_aspect:\n\tfpc=", pixlib.set_decim_pts(fpc),"\n\tsky=",pixlib.set_decim_pts(sky))
        print("\taspoffs=", pixlib.set_decim_pts(aspoffs))
        if p.isokay != 1:
            print(p.errmsg+"\n")

        fpc=p.deapp_aspect(sky)
        print("deapp_aspect:\n\tsky=", pixlib.set_decim_pts(sky),"\n\tfpc=",pixlib.set_decim_pts(fpc))
        if p.isokay != 1:
            print(p.errmsg+"\n")


        p.close

    def test_extdchip(self):    
        pix = Pixlib("chandra", "geom.par")
        print("\n-- Test pixlib extended chip conversions ","-"*10)

        pix.detector = "ACIS"
        SIM_X   = -7.8090834371673E-01 
        SIM_Y   =  0.0000000000000E+00 
        SIM_Z   = -2.3358743446083E+02 
        DY_AVG  =  4.5452498327000E-02 
        DZ_AVG  =  2.1333081580000E-01 
        DTH_AVG = -2.1552640335000E-03 
 
        RA_NOM  =  2.4682474880853E+02 
        DEC_NOM = -2.4573378630717E+01 
            
        D_SIM = [ 0.0, -1*DY_AVG, -1*DZ_AVG ]
            
        pix.aimpoint = [ SIM_X, SIM_Y, SIM_Z ]
        pix.mirror = (  D_SIM, DTH_AVG )
        pix.fpsys  = "FP-1.1"
      
        """  
        expecting 
         ( 0, 1034.2003, 462.2634)
        """
        dxy = (3484.9970385478168, 4034.4782009383603)
        (id, chip) = pix.fpc2chip( dxy )
        print("\n1> fpc -> extended (id,chip) = (%2d," % id, ", ".join(["%.4f" % f for f in chip]), ')')

        fpc = pix.chip2fpc((id,chip))      
        if fpc[0] == None or  fpc[1] == None:
            print("1> extended (id,chip) -> fpc = (", ", ".join(["%10s" % f for f in fpc]), ')')
        else:
            print("1> extended (id,chip) -> fpc = (", ", ".join(["%10.4f" % f for f in fpc]), ')')


        """
        expecting
         ( 3, 1026.4890, 467.5626) 
        """
        dxy = (4624.37853503, 4045.39427581)     
        (id, chip) = pix.fpc2chip( dxy )
        print("\n2> fpc -> extended (id,chip) = (%2d," % id, ", ".join(["%.4f" % f for f in chip]), ')')
        fpc = pix.chip2fpc((id,chip))      
        if fpc[0] == None or  fpc[1] == None:
            print("2> extended (id,chip) -> fpc = (", ", ".join(["%10s" % f for f in fpc]), ')')
        else:
            print("2> extended (id,chip) -> fpc = (", ", ".join(["%10.4f" % f for f in fpc]), ')')


        pix.close
# ---------------
        pix = Pixlib("chandra", "geom.par")
        pix.detector = "ACIS"
        pix.fpsys  = "FP-3.1"
 

        """
        expecting
        fpc <- ext-chip (id= 2): (5153.070, 4046.554)
        """
        chip=(2, (-10.0,1.0) )
        fpc = pix.chip2fpc(chip)      
        if fpc[0] == None or  fpc[1] == None:
            print("\n3> extended (id,chip) -> fpc = (", ", ".join(["%10s" % f for f in fpc]), ')')
        else:
            print("\n3> extended (id,chip) -> fpc = (", ", ".join(["%10.4f" % f for f in fpc]), ')')
            (id, chip) = pix.fpc2chip(fpc)
            print("3> fpc -> extended (id,chip) = (%2d," % id, ", ".join(["%.4f" % f for f in chip]), ')')
  
        """
        expecting
        fpc <- ext-chip (id= 7): (3277.479, 5352.961)
        """
        chip=(7, (1054.5,1064.5) )
        fpc = pix.chip2fpc(chip)
        if fpc[0] == None or  fpc[1] == None:
            print("\n4> extended (id,chip) -> fpc = (", ", ".join(["%10s" % f for f in fpc]), ')')
        else:
            print("\n4> extended (id,chip) -> fpc = (", ", ".join(["%10.4f" % f for f in fpc]), ')')
        (id, chip) = pix.fpc2chipCoords( (7, fpc) )
        print("4> fpc (id=7)-> extended (chip) = (%2d," % id, ", ".join(["%.4f" % f for f in chip]), ')')
  


        """
        expecting
        fpc <-  chip (id= 4): (7388.901, 6400.933)
        """
        chip=(4, (0.5,0.5) )
        fpc = pix.chip2fpc(chip)
        print("\n5>  regular (id,chip) -> fpc = (", ", ".join(["%10.4f" % f for f in fpc]), ')')
        (id, chip) = pix.fpc2chip(fpc)
        print("5> fpc ->  regular (id,chip) = (%2d," % id, ", ".join(["%.4f" % f for f in chip]), ')')
  

 
        """
        expecting
        fpc -> chip (id= 2,    9.616,    1.111)
        """
        fpc=(5152.914, 4065.807)
        (id, chip) = pix.fpc2chip(fpc)
        print("\n6> fpc -> (id,chip) = (%2d," % id, ", ".join(["%.4f" % f for f in chip]), ')')
        fpc = pix.chip2fpc( (id,chip) )
        print("6>  regular (id,chip) -> fpc = (", ", ".join(["%10.4f" % f for f in fpc]), ')')

        pix.close

    def test_strings(self):    
         print("\n-- Test pixlib input string-types  ","-"*10)

    # expected okay
         pix = Pixlib("chandra", b"geom.par")  
         pix.close
         pix = Pixlib(u"chandra", b"geom.par")  
         pix.aimpoint=(-0.782,     0.000,  -237.500)
         print(pix.aimpoint) 
         if len(pix.errmsg):        # expected 'None'
             print(pix.errmsg)      # expected '', no error

         pix.aimpoint=b"ai1"
         if len(pix.errmsg):
             print(pix.errmsg)      # expected '', no error

    # expected errors
         pix.aimpoint="(-0.782,     0.000,  -237.500)" 
         print(pix.errmsg)      # expected error-message

         pix.aimpoint=u"anyaim"
         print(pix.errmsg)      # expected error-message

         pix.detector="anydet"
         print(pix.errmsg)      # expected error-message

         pix.close

    def test_failures(self):    
         print("\n-- Test pixlib expected failures  ","-"*10)
         allexp = 0
         count  = 0

    # expected okay
         pix = Pixlib(u"chandra", b"geom.par")  
 
      
         # test datatype, numeric types
         #  test SM55 bug report 
         pix.mirror=((10.0, -2.0, 1.0), np.float32(32)) 
         count += 1
         exp = "type np.float32 on stage-angle"
         if pix.isokay == 0:  # expect okay, should not get it here
             allexp += (exp == pix.errmsg)    # expected if strings equal
             print("%2i) '%s'\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
         else:
             exp = '((10.0, -2.0, 1.0), 32.0)'
             val = str(pix.mirror)
             print("%2i) '%s'\texpected: %s" % ( count, val, exp == val  ) )
             allexp += (exp == val)

         #  test np.int64()
         pix.mirror = ((10.0,-1.0,1.0), np.int64(20)) 
         count += 1
         exp = "type int64 on stage-angle"
         if pix.isokay == 0:  # expect okay, should not get it here
             allexp += (exp == pix.errmsg)    # expected if strings equal
             print("%2i) '%s'\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
         else:
             exp = '((10.0, -1.0, 1.0), 20.0)'
             val = str(pix.mirror)
             print("%2i) '%s'\texpected: %s" % ( count, val, exp == val  ) )
             allexp += (exp == val)

         #  test bool, np.int32(), int
         pix.mirror = ((bool(90), np.float32(-2), int(10) ), 20 ) 
         count += 1
         if pix.isokay == 0:  # expect okay, should not get it here
             allexp += (exp == pix.errmsg)    # expected if strings equal
             print("%2i) '%s'\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
         else:
             exp ='((1.0, -2.0, 10.0), 20.0)'
             val = str(pix.mirror)
             print("%2i) '%s'\texpected: %s" % ( count, val, exp == val  ) )
             allexp += (exp == val)
                
 
         #  test bool, np.int64(), bool
         pix.mirror = ((bool(0), np.int64(-2), bool(-10) ), 20 ) 
         count += 1
         if pix.isokay == 0:  # expect okay, should not get it here
             allexp += (exp == pix.errmsg)    # expected if strings equal
             print("%2i) '%s'\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
         else:
             exp ='((0.0, -2.0, 1.0), 20.0)'
             val = str(pix.mirror)
             print("%2i) '%s'\texpected: %s" % ( count, val, exp == val  ) )
             allexp += (exp == val)

         #  test bool
         pix.mirror = ((10.0,-1.0,1.0), bool(20)) 
         count += 1
         exp = "type bool on satge-angle"
         if pix.isokay == 0:  # expect okay, should not get it here
             allexp += (exp == pix.errmsg)    # expected if strings equal
             print("%2i) '%s'\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
         else:
             val = str(pix.mirror)
             exp = '((10.0, -1.0, 1.0), 1.0)'
             print("%2i) '%s'\texpected: %s" % ( count, val, exp == val  ) )
             allexp += (exp == val)


         # test datatype, string types
         #  test digit in string
         pix.mirror = ((0.0,-1.0,'1.0'),10.0)
         count += 1
         if pix.isokay == 0:  # not okay
            exp = "Error: invalid data type of 'stage-pos', '1.0', in (0.0, -1.0, '1.0')."
            allexp += (exp == pix.errmsg)    # expected if strings equal
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
 
         #  test string in string
         pix.mirror = ((0.0,-1.0,1.0), 'ImStrin')
         count += 1
         if pix.isokay == 0:
            exp = "Error: need non-string type for stage-angle in '((0.0, -1.0, 1.0), 'ImStrin')'."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )

     
        #  test numerical input on expected string
         pix.detector = 5
         count += 1
         exp = "Error: not strings  at '5'."
         if pix.isokay == 0:
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
                
         #  test numerical input on expected string
         pix.fpsys = 5.5
         count += 1
         if pix.isokay == 0:
            exp = "Error: not strings  at '5.5'."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
     
 
         # test dimension, expected 3-D 
         pix.mirror = ((0.0,-1.0, ), 10.0)
         count += 1
         if pix.isokay == 0:
            exp = "Error: need 3-D for 'stage-pos' but 2-D input."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
                                 
         # test input format, missing stg-angle
         pix.mirror = ((0.0,-1.0, 1.0), )
         count += 1
         if pix.isokay == 0:
            exp = "Error: expected input syntax: '((pos1,pos2,pos3), ang)' ."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
  
 
         fpc=pix.chip2fpc((2, ))
         count += 1
         if pix.isokay == 0:
            exp = "Error: expected input syntax: '(id, (chipx,chipy))' ."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )


         tdet=pix.chip2tdet((2,  None))
         count += 1
         if pix.isokay == 0:
            exp = "Error: need 'list' or 'tuple' type for 'chip' not the type of '<class 'NoneType'>'."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )

 
         pix.aimpoint=(-0.782,  0.000)
         count += 1
         if pix.isokay == 0:        # expected 'None'
            exp="Error: need 3-D for 'aimcoord' but 2-D input., at (-0.782, 0.0)'."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
      
                                  
            
         # test wrong format, expected list/tupe 
         pix.mirror = (0.0, 10.0)
         count += 1
         if pix.isokay == 0:
            exp="Error: need 'list' or 'tuple' type for 'stage-pos' not the type of '<class 'float'>'."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
 
         # test wrong input
         pix.grating="anyval"
         count += 1
         if pix.isokay == 0:        # expected 'None'
            exp="ERROR: Unsupported grating arm name, at 'anyval'."
            allexp += (exp == pix.errmsg) 
            print("%2i) '%s'\n\texpected: %s" % ( count, pix.errmsg, exp == pix.errmsg ) )
         
         pix.close
 
         if allexp==count:
             return 0     # return 0 if all expected TRUE  
         else:
             sys.exit(1)  # otherwise exit(1) 


    def test_gtransfer(self):    
         print("\n-- Test pixlib grating coords transfers","-"*10)
  
         p = Pixlib("chandra")
         
         print("\n----- Pixlib Default SetUp -----")
         print(p.curstat())
         print("\t grt-order:  ", p.grt_order)
         print("\t    grt-zo: ", p.grt_zo )
         print("\n")
 

         """ #1 """
         print("\n=== #1 RFEs:  fpc <-> fc, fc <-> gzo, gzo <-> gac\n")

         try:
             fpc = ( 4110.657608,   3698.628392 )
             fc = p.fpc2fc(fpc)
             print("fpc2fc:\n\tfpc=", pixlib.set_decim_pts(fpc,4),"\n\t fc=", pixlib.set_decim_pts(fc,4))
             fpc=p.fc2fpc(fc)
             print("fc2fpc:\n\t fc=",pixlib.set_decim_pts(fc,4),"\n\tfpc=", pixlib.set_decim_pts(fpc,4)  )
        
             gzo=p.fc2gzo(fc)
             print("fc2gzo:\n\t fc=",  pixlib.set_decim_pts(fc,4), "\n\tgzo=", pixlib.set_decim_pts(gzo,4) )
             fc=p.gzo2fc(gzo)
             print("gzo2fc:\n\tgzo=", pixlib.set_decim_pts(gzo,4),"\n\t fc=", pixlib.set_decim_pts(fc,4) )

             # retain the first element value of gzo in mm
             gzo_res=gzo[0]  
 
             #
             gac=p.gzo2gac(gzo)
             print("gzo2gac:\n\tgzo=",  pixlib.set_decim_pts(gzo,4),"\n\tgac=",pixlib.set_decim_pts(gac,4) )
             gzo=p.gac2gzo(gac)
             print("gac2gzo:\n\tgac=",  pixlib.set_decim_pts(gac,4),"\n\tgzo=", pixlib.set_decim_pts(gzo,4),"       (direction/unit vector)")

             # retrieve  grating-zero-order vector for normalization
             gzo_norm=math.fabs(gzo_res)

             gzo = (gzo[0]*gzo_norm, gzo[1]*gzo_norm,gzo[2]*gzo_norm)
             print("\tgZO=", pixlib.set_decim_pts(gzo,4)," (physical vector in mm)")
             print("   \t ( gZO=gzo*grt_zo0,  grt_zo0 =",  pixlib.set_decim_pts(gzo_norm,4) ,")")

         except Exception as err:
             print("Error: failed to run at {}.".format(str(err)) )   

         p.close


         """ #2 """
         print("\n\n=== #2 conversions:  chip->fpc->fc->gzo->gac->gzo->fc->fpc->chip, on chip edges")
         chipids = [     0,         3,        7,       1,          5,         6 ]
         chipxs  = [ 103.0,     760.0,     32.5,     0.5,     1024.6,    1023.9 ]  # extended chip if chipx>1024.0, chipx<0.5 
         chipys  = [  10.0,     960.5,     12.5,     0.6,     1024.6,       0.5 ]  # extended chip if chipy>1024.0, chipy<0.5 
         desc    = ["'Regular'",  "'Regular'", "'Regular'" , "'Edged'", "'Edged'", "'Edged'"]

 
         #
         # launch pixlib with detector and fpsys setups
         #
         p = Pixlib("chandra")


         for ii in range(0, len(chipids)):
             print("\n--",ii+1,"-- do transfers starting from",desc[ii],"chip")
            

             try:
                id,chip= (chipids[ii], (chipxs[ii], chipys[ii]))
                fpc=p.chip2fpc( (id,chip) )
                id_n_chip = id,pixlib.set_decim_pts(chip,4)
                print("  t1 chip2fpc:\n\t(id, chip)=",id_n_chip, "\n\tfpc=", pixlib.set_decim_pts(fpc,4) )
                id,chip=p.fpc2chip(fpc)
                id_n_chip=id,pixlib.set_decim_pts(chip,4)
                print("     fpc2chip:\n\tfpc=",pixlib.set_decim_pts(fpc,4),"\n\t(id,chip)=", id_n_chip,  " --> match t1's") 
                id,chip=p.fpc2chipCoords((chipids[ii],fpc))
                id_n_fpc=chipids[ii],pixlib.set_decim_pts(fpc,4)
                if p.isokay==1:
                    chip=pixlib.set_decim_pts(chip,4)
                    print("     fpc2chipCoords:\n\t(id,fpc)=",id_n_fpc,"\n\t   chip=", chip,  " --> match t1's\n") 
                else:
                    print("     fpc2chipCoords:\n\t(id,fpc)=",id_n_fpc,"\n\t   chip=", chip,  " --> FAILed\n") 
                  


                fpc0=fpc 
                fpc=pixlib.set_decim_pts(fpc0,4)
                fc0=p.fpc2fc(fpc0)
                fc=pixlib.set_decim_pts(fc0,4)
                print("  t2 fpc2fc:\n\tfpc=", fpc,"\n\t fc=", fc)
             
                gzo=p.fc2gzo(fc0)
                print("  t3 fc2gzo:\n\t fc=", fc, "\n\tgzo=", pixlib.set_decim_pts(gzo,4) )

              
                gac0=p.gzo2gac(gzo)
                gac=pixlib.set_decim_pts(gac0,4)
                print("  t4 gzo2gac:\n\tgzo=",  pixlib.set_decim_pts(gzo,4),"\n\tgac=", gac)


                # reserve the value of gzo in mm
                gzo_res=gzo  
  

                print("\n----- reverse the transfers")
                gzo=p.gac2gzo(gac0)
                print(" rt4 gac2gzo:\n\tgac=", gac,"\n\tgzo=", pixlib.set_decim_pts(gzo,4), " --> gzo in direction")

 
                fc0=p.gzo2fc( pixlib.set_decim_pts(gzo,6) ) 
                fc=pixlib.set_decim_pts(fc0,4)
                print(" rt3 gzo2fc: --> gzo in direction vector \n\tgzo=", pixlib.set_decim_pts(gzo,4), "\n\t fc=", fc, " --> divergent from t3")

               
                fpc0=p.fc2fpc(fc0)
                fpc=pixlib.set_decim_pts(fpc0,4)
                print(" rt2 fc2fpc:\n\t fc=",fc,"\n\tfpc=", fpc," --> divergent from t2"  )

                id,chip=p.fpc2chip(fpc)
                id_n_chip=id,pixlib.set_decim_pts(chip,4)
                print(" rt1 fpc2chip:\n\tfpc=",fpc,"\n\t(id,chip)=", id_n_chip,  " --> divergent from t1") 

                print("\n----- reverse the transfers in physical gzo")
                gzo =gzo_res
                
                fc0=p.gzo2fc(gzo) 
                fc=pixlib.set_decim_pts(fc0,4)
                print("prt3 gzo2fc: --> gzo in physical vector \n\tgzo=", pixlib.set_decim_pts(gzo,4), "\n\t fc=", fc, " --> close to t3")

                fpc0=p.fc2fpc(fc0)
                fpc=pixlib.set_decim_pts(fpc0,4)
                print("prt2 fc2fpc:\n\t fc=",fc,"\n\tfpc=", fpc, " --> close to t2")

                id,chip=p.fpc2chip(fpc0)
                fpc=pixlib.set_decim_pts(fpc0,4)
                if p.isokay==1:
                    id_n_chip=id,pixlib.set_decim_pts(chip,4)
                    print("prt1 fpc2chip:\n\tfpc=",fpc,"\n\t(id,chip)=", id_n_chip, " --> close to t1") 
                else:
                    print("prt1 fpc2chip:\n\tfpc=",fpc,"\n\t(id,chip)=", id_n_chip, " --> FAILed")
 
 
             except Exception as err:
                print("Error: failed to run at {}.".format(str(err)) )
            
         # end of for-loop
         p.close
         print("\n")


         """ #4 """
         print("\n=== #3 catch exception")
         p = Pixlib("chandra")

         try:
             gzo=  ( 3.0, 'a')
             fc=p.gzo2fc(gzo)
             if p.isokay != 1: raise Exception(p) 
             print("gzo2fc:\n\tgzo=", gzo,"\n\t fc=", fc)
         except Exception as err:
             print("\n  fc=p.gzo2fc( (3.0,'a') )")
             print("  Caught {}".format(str(err)) )

         try:
             gzo= (3.0, 4.0, 'a')
             fc=p.gzo2fc(gzo)
             if p.isokay != 1: raise Exception(p)
             print("gzo2fc:\n\tgzo=", gzo,"\n\t fc=", fc)
         except Exception as err:
             print("\n  fc=p.gzo2fc( (3.0,4.0,'a') )")
             print("  Caught {}".format(str(err)) )

         try:
             fc= (0.0, 0.3401, 9.5568, 'a')
             gzo=p.fc2gzo(fc)
             if p.isokay != 1: raise Exception(p) 
             print("\nfc2gzo:\n\t fc=", fc,"\n\tgzo=", gzo)
         except Exception as err:
             print("\n  gzo=p.fc2gzo( (0.0,0.3401,9.5568, 'a') )")
             print("  Caught {}".format(str(err)) )
             

         try:
             fpc=  ( 3.0, 'a')
             fc=p.fpc2fc(fpc)
             if p.isokay != 1: raise Exception(p) 
             print("fpc2fc:\n\tfpc=", fpc,"\n\t fc=", fc)
         except Exception as err:
             print("\n  fc=p.fpc2fc( (3.0, 'a') )")
             print("  Caught {}".format(str(err)) )

         try:
             fc=  ( 3.0 , 4.0)
             fpc=p.fc2fpc(fc)
             if p.isokay != 1: raise Exception(p) 
             print("fc2fpc:\n\tfpc=", fpc,"\n\t fc=", fpc)
         except Exception as err:
             print("\n  fpc=p.fc2fpc( (3.0, 4.0) )")
             print("  Caught {}".format(str(err)) )

         
         p.close
         print("\n")


    #
    # JIra ticket: SL-250 and test_ZeroOrder 
    #

    """ Chandra CALDB as 4/20/2021

    INSTRUMENT GRATING GRATING_ARM      PERIOD               ALPHA                   ROWLAND             
 
       ACIS   HETG   HEG               2000.810              -5.2050               8632.480
      HRC-S   HETG   HEG               2000.810              -5.2050               8632.480
      HRC-I   HETG   HEG               2000.810              -5.2050               8632.480
 
      ACIS    HETG   MEG               4001.950               4.7550               8632.480
      HRC-S   HETG   MEG               4001.950               4.7550               8632.480
      HRC-I   HETG   MEG               4001.950               4.7750               8632.480

      ACIS    LETG   LEG               9912.160             -0.01670               8637.0
      HRC-S   LETG   LEG               9912.160                0.070               8637.0
      HRC-I   LETG   LEG               9912.160                0.070               8637.0
    """
    def test_ZeroOrder(self):    
        """ 
        Grating Zero-Order position is determined by Rowland Circle 
        while the fc-gzo transfers are also by Grating Angle.
        """



        gratings = ( ("ACIS" , "HEG", "GDP-1.1", "FP-1.1") ,  # <--- 1 
                     ("HRC-S", "HEG") ,                       # <--- 1
                     ("HRC-I", "HEG") ,                       # <--- 1
                     ("ACIS" , "MEG") ,                       # <--- 2
                     ("HRC-S", "MEG", "GDP-1.2", "FP-1.1") ,  # <--- 2
                     ("HRC-I", "MEG") ,                       # <--- 2 not
                     ("ACIS" , "LEG") ,                       # <--- 3 not
                     ("HRC-S", "LEG") ,                       # <--- 3
                     ("HRC-I", "LEG", "GDP-1.2", "FP-1.1") )  # <--- 3
                  

             
        # test grt_zo set and get functions
        """            
        Reference: src/pixlib/pixlib/tests/t_mirror_grating.c, case-3, case-4, case-5
        setups:
         Focal Length (mm) = 10070.000
         Detector = ACIS
         Focal Plane Sys. = FP-1.1
         Aim Point(AI2) (mm) = (-0.782348 0 -233.592)
         Grating Arm = HEG
         Grating Order =  1
         Dispersion Plane Sys. = ASC-GDP-1.1
         Rowland Circle (mm) = 8632.48
 
        TESTSAV/pixlib/mirgrt_3.txt, mirgrt_4.txt, mirgrt_5.txt
        case-3:
        Pitch-Yaw (arc-mins) = (2.0, 0.0 )
        find FC2_zo    =  (    -0.096644      0.000000      5.858545 )

        
        case=4:
        Pitch-Yaw (arc-mins) = (2.0, 3.0  )
        find FC2_zo    =  (    -0.103173     -8.787642      5.858376 )

        case-5:
        Pitch-Yaw (arc-mins) = (2.0, 3.0  )
        find FC2_zo    =  (    -0.083996     -8.787637      5.858700 )


        """

        #
        # 1st test
        # set up fc<->gzo transformation matrices at fc_zo
        FC_ZOs = ( (    -0.096644 ,    0.000000 ,    5.858545 ) ,
                   (    -0.103173 ,   -8.787642,     5.858376 ) ,
                   (    -0.083996 ,   -8.787637,     5.858700 ) )

        print("\n-- Test Set FC-ZO and Get GRT-ZO Positions ","-"*10)
        print("\tVarify GRT-ZO a Rowland Circle distance along X-axis")
        try:
            for ii in range(0, len(gratings) ) :
                grt = gratings[ii]

                p = Pixlib("chandra", "geom")

                # overwrite the default detector
                p.detector = grt[0]    
                p.grating  = grt[1]
                print("\n Detector:",p.detector, "\tGrating Arm:",p.grating)

                for jj in range(0, len(FC_ZOs) ) :
                    FC_ZO    = FC_ZOs[jj]

                    p.grt_zo = FC_ZO
                    GRT_ZO = p.grt_zo
                    print("\tSet transfs at  FC_ZO: ", pixlib.set_decim_pts( FC_ZO,6))
                    print("\tGet GRT_ZO fm transfs: ", pixlib.set_decim_pts(GRT_ZO,6))
                    print("\n")
                p.close
        except Exception as err:
            print("Error: failed to run at {}.".format(str(err)) )   


        #
        # 2nd test
        #
        print("\n-- Test Grating Zero Order Functions","-"*10)
        print("\tVary detector & grating-arm while firming GRT-Order and GRT-ZO")

        FC_ZO = FC_ZOs[0]                   

        try:
            for ii in range(0, len(gratings) ) :
                grt = gratings[ii]

                p = Pixlib("chandra", "geom")

                if grt[0] == "ACIS" :
                    p.grating  = grt[1]    
                    print("\n\n", p.curstat(), "\n")
                else:
                    p.detector = grt[0]
                    p.grating  = grt[1]    # must be after p.detector to overwirte the detector's defauls           
                    print("\n\t%s"     % ("***** The current updates *****".rjust(10) ))
                    print("\t%s: '%s'" % ("Detector".rjust(10), p.detector ))
                    print("\t%s: '%s'" % ("Grating".rjust(10), p.grating   ))
                    print("\n")


                # set up fc<->gzo transformation matrices at fc_zo
                # TEST grt_zo for SL-250 ticket
                p.grt_zo=FC_ZO
                print("\n  Set transfs at FC-ZO: ", pixlib.set_decim_pts(FC_ZO,6))
                print("  Get GRT-ZO fm transf: ", pixlib.set_decim_pts(p.grt_zo,4))

                if p.grating == 'HEG':
                    if p.detector == "ACIS" :
                        print("\tNote: grt_zo value is contributed from Rowland Circle.")
                    else:
                        print("\tExpect grt_zo matching to ACIS HEG\'s.")
                elif p.grating == "MEG":
                    print("\tExpect grt_zo matching to ACIS HEG\'s.")
                elif p.grating == "LEG" :
                    if p.detector == "ACIS" :
                        print("\tNote: grt_zo is contributed from Rowalnd Circle.")
                    else:
                        print("\tExpect grt_zo matching to ACIS LEG\'s.")
                print("\n")

                # get grt_ZO via fc2gzo_transf matrix
                grt_zo=p.grt_zo
                fc_zo=p.gzo2fc(grt_zo)
                print("  convert GRT_ZO:", pixlib.set_decim_pts(grt_zo,4), " to  FC_ZO:", pixlib.set_decim_pts(fc_zo,4)) 
                gzo=p.fc2gzo(fc_zo) 
                print("  convert  FC_ZO:", pixlib.set_decim_pts(fc_zo,4),  "  to GRT_ZO:", pixlib.set_decim_pts(gzo,4))
                print("\n")

                # set aribtary fc value and do fc2gzo transfer and ther reverse under the current zero-order grating
                fc =  (1.1348, 22.4357, 10.7258) 
                print("  Pick up values for FC: ", pixlib.set_decim_pts(fc,4))

                gzo =p.fc2gzo(fc)
                print("    fc2gzo: ", pixlib.set_decim_pts(fc,4),  " --> ", pixlib.set_decim_pts(gzo,4))
                fc1 =p.gzo2fc(gzo)
                print("    gzo2fc: ", pixlib.set_decim_pts(gzo,4),  " --> ", pixlib.set_decim_pts(fc1,4))

                if p.grating == 'HEG':
                    if p.detector != "ACIS" :
                        print("\tExpect gzo matching to ACIS HEG\'s.")
                elif p.grating == "MEG":
                    if p.detector == "ACIS":
                        print("\tNote: fc-gzo transfers depend on Rowland & grt-Angle")
                    elif p.detector == "HRC-S" :
                        print("\tExpect gzo matching to ACIS MEG\'s.")
                    else:
                        print("\tExpect not matching to ACIS MEG\'s gzo, due to grt-Angle delta")
                elif p.grating == "LEG" :
                    if p.detector == "ACIS" :
                        print("\tNote: fc-gzo transfers depend on Rowland & grt-Angle.")
                    elif p.detector == "HRC-S" :
                        print("\tExpect not matching to ACIS LEG\'s, due to grt-Angle delta.")
                    elif p.detector == "HRC-I" :
                        print("\tExpect matching to HRC-S LEG\'s.")
                print("\n")

                p.close

        except Exception as err:
            print("Error: failed to run at {}.".format(str(err)) )   

        #
        # 3rd test
        #
        # In c-pixlib, the grt-zo is set at (0,0,0)FC as default: 
        #   ./pixlib/pixlib/pixlib_hinde.c:L85,L088,L178
        #   L085 --- config_system():
        #   L088 ---- double mpy[] = {0.0, 0.0, 0.0};
        #   L178 ---- pix_set_gzo(mpy);
        # 
        # Without explicitly invoking set-grt-zo, do the transfers under the c-library defaults.
        # Here is outlnes the expected outcomes.
        #
        # With the c-pixlib default grt-zo, there is no effective grating, or  
        #   grt_zo is placed at Rowland Circle distance along x-axis
        #   the corresponding gac coordianates is at (0,0), so are a zero wavelength and unavailable grating energy
        #   the corresponding gdp is placed at the center of GDPSys plane
        #   the associated fc is at (0,0,0) and so the fpc is at the center of FPSys plane
        #
        # In py-pixlib level, in order to show the c-pixlib default grating is to 
        #  
        # 1> call fc2gzo, fpc2gdp both requires the support of FC-GZO transormation matix
        #  for simplicity, the test runs below start with 0-vector fc, or
        # 2> call grt_zo getter to get default GRT_ZO. Becsause the py-pixlib dictinary feature, it needs to
        #    to call grt_zo setter for registering 'FC_ZO' in 0-vector into the dictionary. The getter returns
        #    the same value as from fc2gzo.
        #
        
        print("\n-- Test Default GRT-ZO via 0 FC_ZO ","-"*10)
        
        #
        # do fc2gzo/gzo2fc transfers at default GRT-ZO
        #
        try:
            p = Pixlib("chandra", "geom")
            print(p.curstat())

            print("  Do transfers at defaults, including FC-GZO transf. matrixes. ")
            gzo=p.fc2gzo((0.0,0.0,0.0)) 
            print("   fc2gzo:  (0.0, 0.0, 0.0) ", " --> ", pixlib.set_decim_pts(gzo,4))
            fc=p.gzo2fc(gzo)
            print("   gzo2fc:", pixlib.set_decim_pts(gzo,4), " --> ", pixlib.set_decim_pts(fc,4))
            print("\n")


            #
            # do a sequence of transfers at default GRT-ZO, starting from 000fc, fc->fpc->gdp->gac, against gzo->gac
            #
            print("\n  Grating Coords conversion at default GRT-ZO: ")
            
            fc=(0.0,0.0,0.0)
            fpc=p.fc2fpc(fc)
            print("\tfc2fpc: ", pixlib.set_decim_pts(fc,4),  " --> ", pixlib.set_decim_pts(fpc,4))

            gdp=p.fpc2gdp(fpc)
            print("\tfpc2gdp: ", pixlib.set_decim_pts(fpc,4),  " --> ", pixlib.set_decim_pts(gdp,4))

            gac=p.gdp2gac(gdp)
            print("\tgdp2gac: ", pixlib.set_decim_pts(gdp,4),  " --> ", pixlib.set_decim_pts(gac,4))

            gzo=p.fc2gzo(fc)
            gac=p.gzo2gac(gzo)
            print("\tgzo2gac:", pixlib.set_decim_pts(gzo,4), " --> ", pixlib.set_decim_pts(gac,4))

            print("\n")

            p.close
        except Exception as err:
            print("Error: failed to run at {}.".format(str(err)) )   



        #
        # get GRT_ZO at default via zero-vector FC_ZO
        #
        grt_arms = ( "HEG", "MEG", "LEG")
        print("\n  Set/Get GRT-ZO at defaults:")
        try:
            p = Pixlib("chandra", "geom")
            print(p.curstat())
 
            for ii in range(0, len(grt_arms) ) :
                if ii== 0:
                    print("  set/get GRT-ZO at defaults, grating:", p.grating)

                else:
                    p.grating = grt_arms[ii]              
                    p.grt_zo=(0.0,0.0,0.0)
                    print("  set/get GRT-ZO at defaults but grating:", p.grating)

                if ii== 0:
                    print("   get GRT-ZO: ", p.grt_zo, ", expected at python-pixlib")
                    p.grt_zo=(0.0,0.0,0.0)
                    print("   GRT-ZO default value at fc_zo=(0,0,0): ")
                    print("               ", p.grt_zo, ", Rowland Circle distance along x-axis")
                else:
                    print("   get GRT-ZO: ", p.grt_zo, ", Rowland Circle distance along x-axis")
 
                print("\n")
 
            p.close
        except Exception as err:
            print("Error: failed to run at {}.".format(str(err)) )   



    #
    # JIra ticket: SL-250 and test_mnc2gdp
    #
    def test_mnc2gdp(self):    
        """ 
        Do fc-mnc and gdp-gac transfers after Grating Zero-Order transformation setup.
        """


        """            
        Reference: src/pixlib/pixlib/tests/t_mirror_grating.c, case-3
        setups:
         Focal Length (mm) = 10070.000
         Detector = ACIS
         Focal Plane Sys. = FP-1.1
         Aim Point(AI2) (mm) = (-0.782348 0 -233.592)
         Grating Arm = HEG
         Grating Order =  1
         Dispersion Plane Sys. = ASC-GDP-1.1
         Rowland Circle (mm) = 8632.48
 
        case-3:
        Start at source with HPY=(2.0, 0.0), do transfers and 
        get FC_zo = (    -0.096644      0.000000      5.858545 )
        
        Given chip-id,(cpcx,cpcy) = ACIS_I1, (3.357460,      1.388128  )
        do conversions to MNC: 
         MNC <- CPC(ACIS-I1) =  (-10068.865201     22.433143     10.724608 )
         FC<- MNC   =  (     1.134799     22.433143     10.724608 )
         FPC<- FC   =  (  5030.548950   3649.959406 )
        """

        
        # pick up the test suite , the first set is for case-3
        mydets = ( ("ACIS" , "HEG", "GDP-1.1", "FP-1.1") ,  # <--- 1
                   ("HRC-S", "MEG", "GDP-1.2", "FP-1.1") ,  # <--- 2
                   ("HRC-I", "LEG", "GDP-1.2", "FP-1.1") )  # <--- 3
                  
        # set up fc<->gzo transformation matrices at fc_zo
        FC_ZO = (    -0.096644 ,    0.000000 ,    5.858545 )
        # start at MNC at 
        MNC_0 = (-10068.865201,   22.433143,    10.724608)

        print("\n-- Test pixlib fc-mnc and gdp-gac transfers","-"*10)
        print("\tVary detector & grating-arm while firming GRT-Order, GRT-ZO,GDPSYS & FPSYS")


        print("\n  Set transfs at FC_ZO:   ", pixlib.set_decim_pts(FC_ZO,6))
        print("  Pick mnc coordinates:   ", pixlib.set_decim_pts(MNC_0,6),"\n")
  
        try:
            # loop the detector's property for transfer calculation
            for ii in range(0, len(mydets) ) :
                det = mydets[ii]

                p = Pixlib("chandra", "geom")
                p.grt_order=1

                if det[0] == "ACIS":
                    p.gdpsys   = det[2]
                    print("\n\n", p.curstat(), "\n")
                else:
                    p.detector = det[0]
                    p.grating  = det[1]
                    p.gdpsys   = det[2]  # must be after p.grating to overwirte the grating defauls            
                    p.fpsys    = det[3]  

                    print("\n\t%s"     % ("***** The current updates *****".rjust(10) ))
                    print("\t%s: '%s'" % ("Detector".rjust(10), p.detector ))
                    print("\t%s: '%s'" % ("Aimpoint".rjust(10), p.aimpoint ))
                    print("\t%s: '%s'" % ("fpsys".rjust(10),    p.fpsys    ))
                    print("\t%s: '%s'" % ("gdpsys".rjust(10),   p.gdpsys   ))
                    print("\t%s: '%s'" % ("Grating".rjust(10),  p.grating  ))
                    print("\n")



                # set up fc<->gzo transformation matrices at fc_zo
                p.grt_zo= FC_ZO
                mnc     = MNC_0


                # do transfers
                # TEST mnc2fpc for SL-250
                fpc=p.mnc2fpc(mnc) 
                print("   mnc2fpc: ", pixlib.set_decim_pts(mnc,4),  " --> ", pixlib.set_decim_pts(fpc,4))
                mnc=p.fpc2mnc(fpc)
                print("   fpc2mnc: ", pixlib.set_decim_pts(fpc,4),  " --> ", pixlib.set_decim_pts(mnc,4))
                if p.detector == "ACIS" :
                    print("\tEXPECT\t fpc=(5030.548950,   3649.959406 )")
                else:
                    print("\tEXPECTed\n\t\t  fpc depends on Focal Plan system:", p.fpsys)
                print("\n")


                fc=p.fpc2fc(fpc) 
                print("        fpc2fc: ", pixlib.set_decim_pts(fpc,4),  " --> ", pixlib.set_decim_pts(fc,4))

                gdp=p.fpc2gdp(fpc) 
                print("       fpc2gdp: ", pixlib.set_decim_pts(fpc,4),  " --> ", pixlib.set_decim_pts(gdp,4))

                # TEST gdp2gac for SL-250 ticket
                gac_dp=p.gdp2gac(gdp)
                GZO_dir=p.gac2gzo(gac_dp) 
                print("       gdp2gac: ", pixlib.set_decim_pts(gdp,4),  " --> ", pixlib.set_decim_pts(gac_dp,4))
                print("   gdp2gzo_dir: ", pixlib.set_decim_pts(gdp,4),  " --> ", pixlib.set_decim_pts(GZO_dir,6))
                if p.detector == "ACIS" :
                    print("\tEXPECT\n \t\t     fc=( 1.134799,     22.433143,     10.724608 )")
                    print("\t\t    gdp=( 19782.725334    980.583650     )")
                    print("\t\tgzo_dir=(-0.999996     0.002537    0.000797)") 
                else:
                    print("\tEXPECTed\n \t\t gzo & gdp depend on detector & grating arm:", p.detector,p.grating)


                print("\n")

                # TEST grt_zo with fc2gzo and gzo2fc transfers for SL-250 ticket
                gzo =p.fc2gzo(fc)
                print("    fc2gzo: ", pixlib.set_decim_pts(fc,4),  " --> ", pixlib.set_decim_pts(gzo,4))
                fc1 =p.gzo2fc(gzo)
                print("    gzo2fc: ", pixlib.set_decim_pts(gzo,4),  " --> ", pixlib.set_decim_pts(fc1,4))
                print("\n")

                gac=p.gzo2gac(GZO_dir) 
                print("   gzo_dir2gac: ", pixlib.set_decim_pts(GZO_dir,4),  " --> ", pixlib.set_decim_pts(gac,4))
                gac=p.gzo2gac(gzo) 
                print("       gzo2gac: ", pixlib.set_decim_pts(gzo,4),  " --> ", pixlib.set_decim_pts(gac,4))
                if p.detector == "ACIS" :
                    print("\tEXPECT\tgac=(     8.722114/60.0      0.045683 )")
                print("\n")

                eng=p.grt_energy(gac) # EXPECT eng= 0.002442 KeV
                print("   gac2energy:  ", pixlib.set_decim_pts(gac,4),  " --> ", pixlib.set_decim_pts(eng, 4),"KeV")
                if p.detector == "ACIS" :
                    print("\tEXPECT\tenergy=  2.442 KeV")
                else:
                    print("\tEXPECTed\n \t\t energy depends on grating property (Peri,Ang) & order:", p.grt_prop,p.grt_order)

                print("\n")

                p.close

        except Exception as err:
            print("Error: failed to run at {}.".format(str(err)) )   



 


if __name__ == "__main__":

    if "-u" in sys.argv[1:]:
        print(usage())        
    elif len(sys.argv)==1 or (len(sys.argv)==2 and ("-v" in sys.argv or "-q" in sys.argv ) ):
        unittest.main(defaultTest="TestPixlib")
    else:
        suite = unittest.TestSuite()
        for arg in sys.argv[1:]:
            if arg == "-aim":
                suite.addTest(TestPixlib("test_aimpoint")) 
                sys.argv.remove("-aim")
            elif arg == "-det":
                suite.addTest(TestPixlib("test_detector"))
                sys.argv.remove("-det")
            elif arg == "-def":
                suite.addTest(TestPixlib("test_default"))
                sys.argv.remove("-def")
            elif arg == "-gra":
                suite.addTest(TestPixlib("test_grating"))
                sys.argv.remove("-gra")
            elif arg == "-cor":
                suite.addTest(TestPixlib("test_transfer"))
                sys.argv.remove("-cor")
            elif arg == "-gen":
                suite.addTest(TestPixlib("test_general"))
                sys.argv.remove("-gen")
            elif arg == "-ext":
                suite.addTest(TestPixlib("test_extdchip"))
                sys.argv.remove("-ext")
            elif arg == "-str":
                suite.addTest(TestPixlib("test_strings"))
                sys.argv.remove("-str")
            elif arg == "-fai":
                suite.addTest(TestPixlib("test_failures"))
                sys.argv.remove("-fai")
            elif arg == "-gtr":
                suite.addTest(TestPixlib("test_gtransfer"))
                sys.argv.remove("-gtr")
            elif arg == "-gzo":
                suite.addTest(TestPixlib("test_ZeroOrder"))
                sys.argv.remove("-gzo")
            elif arg == "-m2g":
                suite.addTest(TestPixlib("test_mnc2gdp"))
                sys.argv.remove("-m2g")
            else:
                pass
      
        result = unittest.TextTestRunner(verbosity=2).run(suite)
  
        if result.wasSuccessful() :
            sys.exit(0)
        else:
            sys.exit(1)

