#!/usr/bin/python3
# -*- coding: utf-8 -*-

from __future__ import print_function

import time
import os
import glob
import Manyo
import Manyo.Utsusemi as mu
import Manyo.SAS as ms
import math

import utsusemi.ana.Reduction.BaseCommands as BaseCom
import Hist, Corr, QSpace
import utsusemi.SAS.ana.Reduction.QSpaceBaseCommands as QBC
import utsusemi.SAS.ana.Reduction.HistBaseCommands as HBC

# special reserved word for commands history
HISTORY = None

# reserved words for return value in this.
DAT = None
ecs = None
EC = None
ret = None
PyObj = None
Iq = None
Tr = None
ECA = None
DATList=None

#########################################
def GetNeunetHistSAS(runNo="0",HistParam="tof,0,40000,100",DetParam="psd",DetRange="All",TimeRange="All",FrameInfo="None",MaskInfo="NoFile",CaseInfo="None",BGInfo="TimeDep:None",TofShift="None",AnaMode="0",ParamFiles="-,-",SolAngCor=False,Options="-"):
    """
    Convert Event data of NEUNET to Histogram
    GetNeunetHist(runNo="197,198",
                  HistParam="tof,0,40000,100",
                  DetParam="psd",
                  DetRange="All",
                  TimeRange="All",
                  FrameInfo="None",
                  MaskInfo="NoFile"
                  CaseInfo="None",
                  BGInfo="TimeDep:None",
                  TofShift="None",
                  AnaMode="0",
                  ParamFiles="-,-",
                  SolAngCor=False,
                  Options="-"
                  )

    -----------------------
    HistParam format
        TOF
           delta-TOF const :  tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : rtof,<min_tof>,<max_tof>,<racio>

        TOF with time forcusing
           delta-TOF const : tf-tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : tf-rtof,<min_tof>,<max_tof>,<racio>

        Lambda
           delta-lambda const        :  lambda,<min_lambda>,<max_lambda>,<delta_lambda>
           delta-lambda/lambda const : rlambda,<min_lambda>,<max_lambda>,<racio>

        Energy            : energy,<min_energy>,<max_energy>,<delta_energy>

        Momentum Transfer : q,<min_Q>,<max_Q>,<delta_Q>[,<ki_x>,<ki_y>,<ki_z>]

        Energy Transfer   : hw,<Ei>,<min_hw>,<max_hw>,<delta_hw>[,<t0_shift>]

        d-value
            delta-d-value                 : d,<min_d-val>,<max_d-val>,<delta_d-val>
            delta-d-value / d-value const : rd,<min_d-val>,<max_d-val>,<ratio>

    -----------------------
    DetParam format
        "<detType>[[<LLD_min>:<LLD_max>]][,..]" : detType in {"PSD","MON","PSD-PH","MON-PH", "UPSD", "TRIGNET"}
                                                "-PH" means that Pulse Height is calculated at the same time
    -----------------------
    DetRange format
        "All[:<number_of_pixels>]"                     : use all detectors
        "<startDetId>-<endDetId>[:<number_of_pixels>]" : use detectors from <startDetId> to <endDetId>
                                                         "X-Y:Z,A-B:C,D-E:F..." can be used for more settings
    -----------------------
    TofShift format
        "<ptnId>[,<p1>,<p2>,...]"
             ptnId = 0 : no use in this facade( only use if scattered data of tof origin shift vs lambda is given )
             ptnId = 1 : use shift = p1/(exp(-p2*(lambda-p3)) +p4) + p5*lambda
                         default p1=5.0, p2=8.464, p3=2.08765, p4=1.23477, p5=5.32657
    -----------------------

    @param runNo     (string or int) Run Number(s) 123 or "123,124"
    @param HistParam (string) "type,param,param,param,..." type must be in "tof" "rtof" "lambda" "rlambda" "hw" "energy" "q" "d" "rd"
    @param DetParam  (string) "DetType[,LLD,HLD]" DetType must be in "psd","n2mon","psd-ph" or "n2mon-ph"
    @param DetRange  (string) "All[:number_of_pixels]" or "startPsdId-endPsdId[:number_of_pixels]"
    @param TimeRange (string) "All" or "startTime,endTime" in [second] or "YYYY/MM/DD,hh:mm:ss,YYYY/MM/DD,hh:mm:ss"
    @param FrameInfo (string) "None" or "FrameNumber, boudaryTime"
    @param MaskInfo  (string) "<maskfile> [,<TOFmask>-<TOFmask>,..]" : if no use maskfile, set "NoFile"
    @param CaseInfo  (string) CaseInfo file must be in ${UTSUSEMI_USR_DIR}/ana/xml or ${UTSUSEMI_HOME_DIR}/ana/xml
    @param BGInfo    (string) "TimeDep:None" TimeDep:tof1-tof2
    @param TofShift  (string) "None" or "<ptnId> [,<p1>,<p2>,...]"
    @param AnaMode   (string or int) change analysis mode, which means to swich WiringInfo and DetectorInfo to be used for histogram.
    @param ParamFiles(string) "<path/to/WiringInfo>,<path/to/DetectorInfo>"
    @param SolAngCor (bool) True for doing SolidAngle Correction
    @retval DAT (ElementContainerMatrix)
    """
    runNo_strlist=runNo.split(",")
    runNoList = []
    for a_run_st in runNo_strlist:
        runNoList.append( int(a_run_st) )
    num_of_runs = len(runNoList)
    all_data_list = []
    if DetRange.find("RPMT") == 0:
        if Options.upper().find("ISCHECKPULSEID:FALSE") < 0:
            if Options == "-":
                Options = "ISCHECKPULSEID:false"
            else:
                Options += ",ISCHECKPULSEID:false"
        print("##########################[inamura 260106] Check PulseID = Flase ({})".format(Options))
        RPMT_LLDHLD = [0, 0, 0, 0] #[<LLD_X>,<HLD_X>,<LLD_Y>,<HLD_Y>]
        RPMT_COI = 32 #<LmtCoi>

        #detType="PSD"
        mode_no=5
        AnaMode = "5"
        rpmt_params = DetRange.split(",")
        if len(rpmt_params)>1:
            RPMT_LLDHLD[0] = int(rpmt_params[1])
        if len(rpmt_params)>2:
            RPMT_LLDHLD[1] = int(rpmt_params[2])
        if len(rpmt_params)>3:
            RPMT_LLDHLD[2] = int(rpmt_params[3])
        if len(rpmt_params)>4:
            RPMT_LLDHLD[3] = int(rpmt_params[4])
        if len(rpmt_params)>5:
            RPMT_LLDHLD[4] = int(rpmt_params[5])
        if len(rpmt_params)>6:
            RPMT_COI = int(rpmt_params[6])
        for a_runNo in runNoList:
            DaqId = 13 #Default
            ind = DetRange.find(":")
            if ind > 0:
                DaqId = int(DetRange[ind+1:])
            #ConvertFromRPMTK2Psd( int(a_runNo), DaqId, 0, "SAS03")
            dfile_found_path = ""
            HBC.ConvertFromRPMTK2Psd(int(a_runNo), DaqId, 0, "SAS03", mode_no, RPMT_LLDHLD, RPMT_COI, dfile_found_path)

    AnaMode = AnaMode+","+ParamFiles
    det_range_list = DetRange.split(",")
    DetRange = ""
    for a_det in det_range_list:
        a_det = a_det.strip()
        if a_det == "SM":
            DetRange += "SMBL14,SMBL16,"
        else:
            DetRange += (a_det + ",")
    DetRange = DetRange[:-1]
    print("#[inamura 240411] DetRange rewrite to ", DetRange)
    for runNo in runNoList:
        HBC.CheckT0bUpdate(int(runNo))
        a_dat_list = BaseCom.GetNeunetHist(runNo,HistParam,DetParam,DetRange,TimeRange,FrameInfo,MaskInfo,CaseInfo,BGInfo,TofShift,AnaMode,Options)
        if type(a_dat_list)!=list:
            a_dat_list=[a_dat_list]
        all_data_list.append(a_dat_list)
    dat_list = []
    UCC=mu.UtsusemiCalcContainers()

    for i in range(len(all_data_list[0])):
        ret = Manyo.ElementContainerMatrix(all_data_list[0][i])
        kickers=ret.PutHeaderPointer().PutInt4("KICKERCOUNT")
        for j in range(num_of_runs-1):
            a_dat = all_data_list[j+1][i]
            kickers += a_dat.PutHeaderPointer().PutInt4("KICKERCOUNT")
            ret_tmp = Manyo.ElementContainerMatrix(ret.PutHeader())
            if UCC.CalcContainers(ret_tmp,1.0,ret,"+",1.0,a_dat):
                pass
            else:
                raise
            ret = ret_tmp
        ret.InputHeader(all_data_list[0][i].PutHeader())
        ret.PutHeaderPointer().OverWrite("KICKERCOUNT",kickers)
        dat_list.append(ret)
    del UCC

    for dat in dat_list:
        ## Create Lambda Vector for each EC
        tt1 = ms.CreateLambVector( dat )
        tt1.Execute()
        del tt1

        ## Convertion from histogram to per_unit
        tt2 = ms.ConvertToPoint(dat)
        tt2.Execute()
        del tt2

        ## Solid angle correction
        if (SolAngCor):
            for i in range(dat.PutSize()):
                if (dat(i).PutHeaderPointer().PutString("TYPE")=="PSD"):
                    for j in range( dat(i).PutSize() ):
                        ec = dat(i,j)
                        sa = ec.PutHeaderPointer().PutDouble("PixelSolidAngle")
                        if sa==0.0:
                            raise UserWarning("Solid angle = 0 at %d,%d"%(i,j))
                        else:
                            ec.MulMySelf(1.0/sa)

            p_chk = mu.UtsusemiCheckDataProcess()
            p_chk.AddProcess( dat, "SolidAngleCorrection" )
            del p_chk

    return dat_list

def GetNeunetHistSASWitoutCheckPulseId(runNo="197",HistParam="tof,0,40000,100",DetParam="psd",DetRange="All",TimeRange="All",FrameInfo="None",MaskInfo="NoFile",CaseInfo="None",BGInfo="TimeDep:None",TofShift="None",AnaMode="0",ParamFiles="-,-",SolAngCor=False):
    """
    Convert Event data of NEUNET to Histogram
    GetNeunetHist(runNo="197,198",
                  HistParam="tof,0,40000,100",
                  DetParam="psd",
                  DetRange="All",
                  TimeRange="All",
                  FrameInfo="None",
                  MaskInfo="NoFile"
                  CaseInfo="None",
                  BGInfo="TimeDep:None",
                  TofShift="None",
                  AnaMode="0",
                  ParamFiles="-,-",
                  SolAngCor=False
                  )

    -----------------------
    HistParam format
        TOF
           delta-TOF const :  tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : rtof,<min_tof>,<max_tof>,<racio>

        TOF with time forcusing
           delta-TOF const : tf-tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : tf-rtof,<min_tof>,<max_tof>,<racio>

        Lambda
           delta-lambda const        :  lambda,<min_lambda>,<max_lambda>,<delta_lambda>
           delta-lambda/lambda const : rlambda,<min_lambda>,<max_lambda>,<racio>

        Energy            : energy,<min_energy>,<max_energy>,<delta_energy>

        Momentum Transfer : q,<min_Q>,<max_Q>,<delta_Q>[,<ki_x>,<ki_y>,<ki_z>]

        Energy Transfer   : hw,<Ei>,<min_hw>,<max_hw>,<delta_hw>[,<t0_shift>]

        d-value           : d,<min_d-val>,<max_d-val>,<delta_d-val>

    -----------------------
    DetParam format
        "<detType>[[<LLD_min>:<LLD_max>]][,..]" : detType in {"PSD","MON","PSD-PH","MON-PH", "UPSD", "TRIGNET"}
                                                "-PH" means that Pulse Height is calculated at the same time
    -----------------------
    DetRange format
        "All[:<number_of_pixels>]"                     : use all detectors
        "<startDetId>-<endDetId>[:<number_of_pixels>]" : use detectors from <startDetId> to <endDetId>
                                                         "X-Y:Z,A-B:C,D-E:F..." can be used for more settings
    -----------------------
    TofShift format
        "<ptnId>[,<p1>,<p2>,...]"
             ptnId = 0 : no use in this facade( only use if scattered data of tof origin shift vs lambda is given )
             ptnId = 1 : use shift = p1/(exp(-p2*(lambda-p3)) +p4) + p5*lambda
                         default p1=5.0, p2=8.464, p3=2.08765, p4=1.23477, p5=5.32657
    -----------------------

    @param runNo     (string or int) Run Number(s) 123 or "123,124"
    @param HistParam (string) "type,param,param,param,..." type must be in "tof" "rtof" "lambda" "rlambda" "hw"
    @param DetParam  (string) "DetType[,LLD,HLD]" DetType must be in "psd","n2mon","psd-ph" or "n2mon-ph"
    @param DetRange  (string) "All[:number_of_pixels]" or "startPsdId-endPsdId[:number_of_pixels]"
    @param TimeRange (string) "All" or "startTime,endTime" in [second] or "YYYY/MM/DD,hh:mm:ss,YYYY/MM/DD,hh:mm:ss"
    @param FrameInfo (string) "None" or "FrameNumber, boudaryTime"
    @param MaskInfo  (string) "<maskfile> [,<TOFmask>-<TOFmask>,..]" : if no use maskfile, set "NoFile"
    @param CaseInfo  (string) CaseInfo file must be in ${UTSUSEMI_USR_DIR}/ana/xml or ${UTSUSEMI_HOME_DIR}/ana/xml
    @param BGInfo    (string) "TimeDep:None" TimeDep:tof1-tof2
    @param TofShift  (string) "None" or "<ptnId> [,<p1>,<p2>,...]"
    @param AnaMode   (string or int) change analysis mode, which means to swich WiringInfo and DetectorInfo to be used for histogram.
    @param ParamFiles(string) "<path/to/WiringInfo>,<path/to/DetectorInfo>"
    @param SolAngCor (bool) True for doing SolidAngle Correction
    @retval DAT (ElementContainerMatrix)
    """

    HBC.CheckT0bUpdate(int(runNo))
    AnaMode = AnaMode+","+ParamFiles
    dat_list = BaseCom.GetNeunetHist(runNo,HistParam,DetParam,DetRange,TimeRange,FrameInfo,MaskInfo,CaseInfo,BGInfo,TofShift,AnaMode,Options="ISCHECKPULSEID:false")
    if type(dat_list)!=list:
        dat_list=[dat_list]
    for dat in dat_list:
        ## Create Lambda Vector for each EC
        tt1 = ms.CreateLambVector( dat )
        tt1.Execute()
        del tt1

        ## Convertion from histogram to per_unit
        tt2 = ms.ConvertToPoint(dat)
        tt2.Execute()
        del tt2

        ## Solid angle correction
        if (SolAngCor):
            for i in range(dat.PutSize()):
                if (dat(i).PutHeaderPointer().PutString("TYPE")=="PSD"):
                    for j in range( dat(i).PutSize() ):
                        ec = dat(i,j)
                        sa = ec.PutHeaderPointer().PutDouble("PixelSolidAngle")
                        if sa==0.0:
                            raise UserWarning("Solid angle = 0 at %d,%d"%(i,j))
                        else:
                            ec.MulMySelf(1.0/sa)

            p_chk = mu.UtsusemiCheckDataProcess()
            p_chk.AddProcess( dat, "SolidAngleCorrection" )
            del p_chk

    return dat_list

########################################
def DataReductionMulti( dat_list=DAT,Xrange="4.0 7.7 0.1 dL", kickerNorm=True, incVec="0.0 0.0 1.0", maskFile="mask_160316.xml" ):
    """
    Do the data reduction process as below:
      - EC = Hist.GetMonHistSAS(runNo=runno,MonNo=1,AxType=conv_type,Xrange=conv_params,MonIndex=0,TimeSlice="-1 -1",frameBoundary=0.0,CalibEffi=True)
      - Corr.I0LambdaCorrection(dat=DATs,I0Lamb=EC)
      - QSpace.ConvertQSpace(dat=DATs,InVec=incVec)
      - DoMask(dat=DATs,filename=maskFile)
      - DATs.MulMySelf( float(all_kickers)/float(kickers) ) when "kickerNorm" is True

    @param dat_list(list)
    @param Xrange(string)
    @param kickerNorm(bool) True:do kicker normalization
    @retval None
    """
    print("#########################[inamura 251223] DataReductionMulti start")
    if type(dat_list)==list:
        data = dat_list
    else:
        data = [dat_list]
    run_st=data[0].PutHeader().PutString("RUNNUMBER")
    #runno=int(run_st)
    run_st_list=run_st.split(",")

    conv_type =""
    conv_params=""
    p_list=Xrange.split(" ")
    if len(p_list)!=4:
        raise UserWarning("param error")
    AxType=p_list[3].lower()
    if AxType=="dl":
        conv_type = "lambda"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="dl/l":
        conv_type = "lambda2"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="tof":
        conv_type = "tof"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    else:
        raise UserWarning("param error about conv type")

    UCC=mu.UtsusemiCalcContainers()
    all_kickers = 0
    EC_sum=None
    for a_run_st in run_st_list:
        runno=int(a_run_st)
        ECs = Hist.GetMonHistSAS(runNo=runno,MonNo=1,AxType=conv_type,Xrange=conv_params,MonIndex=0,TimeSlice="-1 -1",frameBoundary=0.0,CalibEffi=True)
        all_kickers += ECs.PutHeaderPointer().PutInt4("KICKERCOUNT")
        if EC_sum is None:
            EC_sum = ECs
        else:
            EC_sum += ECs
    EC_sum.PutHeaderPointer().OverWrite("KICKERCOUNT",all_kickers)
    del UCC

    lambda_range = "%g %g"%(float(p_list[0]),float(p_list[1]))

    #all_kickers = ECs.PutHeaderPointer().PutInt4("KICKERCOUNT")
    for DATs in data:
        #Corr.CorrectDetEffi(dat=DATs,filename="detectorEffiTBL.dat")
        Corr.I0LambdaCorrection(dat=DATs,I0Lamb=EC_sum)
        print("#########################[inamura 251223] ConvertQspace start")
        QSpace.ConvertQSpace(dat=DATs,InVec=incVec)
        print("#########################[inamura 251223] ConvertQspace start")
        #DoMask(dat=DATs,filename=maskFile)
        if maskFile.upper()!="NONE" and maskFile!="-" and maskFile.upper()!="NOFILE":
            DoMask(dat=DATs,filename=maskFile)
        if kickerNorm:
            kickers = DATs.PutHeaderPointer().PutInt4("KICKERCOUNT")
            DATs.MulMySelf( float(all_kickers)/float(kickers) )
    if len(data)==1:
        dat_list=data[0]

########################################
def SubtractBackMulti( dat_list=DAT, dat_BG=DAT):
    """

    @param dat_list (list of ElementContainerMatrix)
    @param dat_BG (ElementCntainerMatrix)
    @retval DATs (list of ElementContainerMatrix)
    """
    if type(dat_list)!=list:
        dat_list = [dat_list]

    import Com
    ret = []
    for a_dat in dat_list:
        ret.append( Com.CalcContainers(dat1=a_dat,dat2=dat_BG,coef1=1.0,coef2=1.0,ope="-") )
    return ret

########################################
def QzProjectionMulti(dat_list=DATList,QxRange="-0.06 0.06 0.001",QyRange="-0.06 0.06 0.001",QzRange="-0.5 0.0",LambdaRange="4.0 7.7 0.01"):
    """

    @param dat_list(list)
    @param Xrange(string)
    @retval list of ElementContainerArray
    """
    ret = []
    for dat in dat_list:
        eca = QSpace.QzProjection(dat,QxRange,QyRange,QzRange,LambdaRange)
        ret.append(eca)

    return ret

########################################
def SectorAverageByAnglesMulti( dat_list=DATList, index=0, Banks="SM16-SM14-SD-SU", Qrange="0.01 2.0 0.001 dQ/Q", LamRange="0.7 0.8", AzimAng="0.0 0.0", PolAng="0.0 0.0", QLamFile="None/QLambdaRange" ):
    """
    Convert Data to Q space EventData to produce histogram
    SectorAverageByAngles( dat=DAT, Banks="SM16-SM14-SD-SU", Qrange="0.01 2.0 0.001 dq/Q", LamRange="0.7 0.8", AzimAng="0.0 0.0", PolAng="0.0 0.0" )

    @param  dat_list (list of ElementContainerMatrix)
    @param  index    (int)    index number in dat_list to analyze
    @param  Banks    (string)  "SM16-SD-SU" means these banks are unified in one Iq, "SM SD SU" means separated Iq
    @param  Qrange   (string)  Q range and type of Qbin "Qmin Qmax deltaQ type" type must be dQ/Q or dQ
    @param  LamRange (string)  Lambda range "Lambda_min Lambda_max"
    @param  AzimAng  (string)  "-20.0 20 170 -170"
    @param  PolAng   (string)  "0 90 0 40"
    @param  QLamFile (string)  filename of Q-Lambda range info. If None, no use. (read QLambdaRange_SM.txt for SM bank)
    @retval Iq       (list of ElementContainer)
    """

    return QBC.SectorAverageByAngles( dat_list[index], Banks, Qrange, LamRange, AzimAng, PolAng, QLamFile )

########################################
def GetAzimuthProfile(dat=DAT, Qcenter=0.036, dQ=0.002, azim_bin=1.0, azim_range="0.0 360.0", lambda_range="0 0"):
    """
    Calculates Azimuth Profile from DataReduction

    @param dat          (ElementContainerMatrix)
    @param Qcenter      (float)
    @param dQ           (float)
    @param azim_bin     (float)
    @param azim_range   (string)
    @param lambda_range (string)
    @retval Iap
    """
    ec_list=GetAzimuthProfileMulti([dat], Qcenter, dQ, azim_bin, azim_range, lambda_range)
    return ec_list[0]

########################################
def GetAzimuthProfileMulti(dat_list=DATList, Qcenter=0.036, dQ=0.002, azim_bin=1.0, azim_range="0.0 360.0", lambda_range="0 0"):
    """
    Calculates Azimuth Profile from DataReduction

    @param dat_list     (list)
    @param Qcenter      (float)
    @param dQ           (float)
    @param azim_bin     (float)
    @param azim_range   (string)
    @param lambda_range (string)
    @retval IapList
    """
    return QBC.GetAzimuthProfileMulti(dat_list, Qcenter, dQ, azim_bin, azim_range, lambda_range)

########################################
def Test( dat_list=DAT, Xrange="0.7 7.6 0.1 dL" ):
    """

    @param dat_list(list)
    @param Xrange(string)
    @retval list of ElementContainerArray
    """

    run_st=dat_list[0].PutHeader().PutString("RUNNUMBER")
    runno=int(run_st)

    conv_type =""
    conv_params=""
    p_list=Xrange.split(" ")
    if len(p_list)!=4:
        raise UserWarning("param error")
    AxType=p_list[3].lower()
    if AxType=="dl":
        conv_type = "lambda"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="dl/l":
        conv_type = "lambda2"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="tof":
        conv_type = "tof"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    else:
        raise UserWarning("param error about conv type")

    ECs = Hist.GetMonHistSAS(runNo=runno,MonNo=1,AxType=conv_type,Xrange=conv_params,MonIndex=0,TimeSlice="-1 -1",frameBoundary=0.0,CalibEffi=True)

    lambda_range = "%g %g"%(float(p_list[0]),float(p_list[1]))
    ret = []
    for DATs in dat_list:
        Corr.CorrectDetEffi(dat=DATs,filename="detectorEffiTBL.dat")
        Corr.I0LambdaCorrection(dat=DATs,I0Lamb=ECs)
        QSpace.ConvertQSpace(dat=DATs,InVec="0.0 0.0 1.0")
        DoMask(dat=DATs,filename="mask_160316.xml")
        ECA = QSpace.QzProjection(dat=DATs,QxRange="-0.06 0.06 0.001",QyRange="-0.06 0.06 0.001",QzRange="-0.5 0.0",LambdaRange=lambda_range)
        ret.append( ECA )
    return ret

########################################
def PickDataByCaseId( dat=DAT, caseId=1 ):
    """
    """
    import Manyo
    if isinstance( dat, Manyo.ElementContainerMatrix() ):
        return dat
    for a_dat in dat:
        hh=a_dat.PutHeaderPointer()
        if caseId==hh.PutInt4("CASEID"):
            return a_dat

    raise UserWarning("This caseId is NOT included.")

#########################################
def DoMask(dat=DAT,filename="mask.txt"):
    """
    MASKED flag controled by file.
    @param dat [Def:DAT] (ElementContainerMatrix)
    @param filename (string) filename of mask information
    """

    BaseCom.DoMask(dat,filename)

########################################
def RemoveAllMask( dat=DAT ):
    """
    Does remove mask
    REmoveAllMask( dat, filename )

    @param dat       (ElementContainerMatrix)
    @param filename  (string) mask file must be in UTSUSEMI_USR_DIR/ana/xml
    @retval None
    """

    SMSK = mu.UtsusemiSetMask( dat )
    SMSK.UmaskAll()
    del SMSK

############################################
def LoadDataFromManyoBinary(path="./",filename="Sample.mdb"):
    """
    Load ElementContainerMatrix from manyo binary data file
    which is the binary format for storing ElementContainers usign HDF5
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval  data (ElementContaienr, -Array, -Matrix)
    """
    return BaseCom.LoadDataFromManyoBinary(path,filename)

############################################
def SaveDataToManyoBinary(dat=DAT, path="./",filename="Sample.mdb"):
    """
    Save ElementContainerMatrix to manyo binary data file
    This is the binary format for storing ElementContainers using HDF5
    @param  dat      (ElementContainer, -Array, -Matrix)
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval None
    """
    BaseCom.SaveDataToManyoBinary(dat, path,filename)

#########################################
def LoadDataFromDump(path="./",filename="Sample.dmp"):
    """
    Load ElementContainerMatrix from dump file made by ECMSerialize class
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval DAT        ElementContainer/Array/Matrix
    """

    return BaseCom.LoadDataFromDump(path,filename)

#########################################
def SaveDataToDump(dat=DAT, path="./",filename="Sample.dmp"):
    """
    Serialize ElementContainerMatrix to dump file using ECMSerialize class.
    @param  dat      (ElementContainerMatrix)
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval None
    """

    BaseCom.SaveDataToDump(dat,path,filename)

#########################################
def GetDataFromNeXus(path="./",filename="Sample.nx"):
    """
    Load ElementContainer/Array/Matrix from NeXus file.
    @param  path     (String)   path to data file
    @param  filename (String)  data file name
    @retval DAT      ElementContainer/Array/Matrix
    """
    return BaseCom.GetDataFromNeXus(path,filename)

#########################################
def SaveDataToNeXus(dat=DAT, name="Data",path="./",filename="Sample.nx"):
    """
    Save ElementContainer/Array/Matrix to NeXus file.
    @param  dat       (ElementContainerMatrix)
    @param  name      (String)   Title of saved data
    @param  path      (String)   path to data file
    @param  filename  (String)  data file name
    @retval None
    """
    BaseCom.SaveDataToNeXus(dat, name,path,filename)

##########################################
def getBeamCurrent(start_day="2009/5/30", start_time="10:00:00", end_day="2009/5/30", end_time="11:00:00" ):
    """
    get Beam current from web and calculate summation of the number of shots and protons
    @param start_day  the day of measurement start
    @param start_time the time of measurement start
    @param end_day    the day of measurement end
    @param end_time   the time of measurement end
    @retval ret       the number of protons [TelaProtons]
    """
    return BaseCom.getBeamCurrent(start_day, start_time, end_day, end_time)

##########################################
def NormByBeamCurrent(dat=DAT,factor=1000.0 ):
    """
    Normailze by Beam current from web and calculate summation of the number of shots and protons. Experimental info file, like SIK000XXX.xml file, must be placed in your ~/exp/xml directory.
    @param dat        (ElementContainer,-Array,-Matrix)
    @param factor     (double) normalize factor data*factor/beamCurrent
    """
    BaseCom.NormByBeamCurrent(dat, factor)



#########################################
def PrintObject(target=PyObj):
    """
    Print object for debug.
    @param target print to stdout
    @retval None
    """
    print(type(target))
    try:
        print(target)
    except:
        print("not printable")

#########################################
def MergeDataECM(dat1=DAT, coef1=1.0, dat2=DAT, coef2=0.0, dat3=DAT, coef3=0.0, dat4=DAT, coef4=0.0):
    """
    Merge Data (ElementContainerMatrix only)
    @param dat1  (ElementContainerMatrix)
    @param coef1 (float) coefficient for dat1
    @param dat2  (ElementContainerMatrix)
    @param coef2 (float) coefficient for dat2
    @param dat3  (ElementContainerMatrix)
    @param coef3 (float) coefficient for dat3
    @param dat4  (ElementContainerMatrix)
    @param coef4 (float) coefficient for dat4
    @retval DATmerg  (ElementContainerMatrix)
    """
    if not isinstance( dat1, Manyo.ElementContainerMatrix ):
        raise UserWarning("dat1 is not ElementContainerMatrix")
    if not isinstance( dat2, Manyo.ElementContainerMatrix ):
        raise UserWarning("dat2 is not ElementContainerMatrix")
    if not isinstance( dat3, Manyo.ElementContainerMatrix ):
        raise UserWarning("dat3 is not ElementContainerMatrix")
    if not isinstance( dat4, Manyo.ElementContainerMatrix ):
        raise UserWarning("dat4 is not ElementContainerMatrix")

    ret = dat1.Mul( coef1 )
    hh = ret.PutHeaderPointer()
    if (coef2!=0.0):
        for i in range( dat2.PutSize() ):
            ret.Add( dat2.PutPointer(i).Mul(coef2) )
        hht = dat2.PutHeaderPointer()
        if (hh.CheckKey("BANKIDLIST")==1) and (hht.CheckKey("BANKIDLIST")==1):
            bidvect=hh.PutInt4Vector("BANKIDLIST")
            bszvect=hh.PutInt4Vector("BANKSIZELIST")
            bnmvect=hh.PutStringVector("BANKNAMELIST")
            bidvectt=hht.PutInt4Vector("BANKIDLIST")
            bszvectt=hht.PutInt4Vector("BANKSIZELIST")
            bnmvectt=hht.PutStringVector("BANKNAMELIST")
            for i in range( bidvectt.size() ):
                bidvect.push_back( bidvectt[i] )
                bszvect.push_back( bszvectt[i] )
                bnmvect.push_back( bnmvectt[i] )
            hh.OverWrite("BANKIDLIST",bidvect)
            hh.OverWrite("BANKSIZELIST",bszvect)
            hh.OverWrite("BANKNAMELIST",bnmvect)

    if (coef3!=0.0):
        for i in range( dat3.PutSize() ):
            ret.Add( dat3.PutPointer(i).Mul(coef3) )
        hht = dat3.PutHeaderPointer()
        if (hh.CheckKey("BANKIDLIST")==1) and (hht.CheckKey("BANKIDLIST")==1):
            bidvect=hh.PutInt4Vector("BANKIDLIST")
            bszvect=hh.PutInt4Vector("BANKSIZELIST")
            bnmvect=hh.PutStringVector("BANKNAMELIST")
            bidvectt=hht.PutInt4Vector("BANKIDLIST")
            bszvectt=hht.PutInt4Vector("BANKSIZELIST")
            bnmvectt=hht.PutStringVector("BANKNAMELIST")
            for i in range( bidvectt.size() ):
                bidvect.push_back( bidvectt[i] )
                bszvect.push_back( bszvectt[i] )
                bnmvect.push_back( bnmvectt[i] )
            hh.OverWrite("BANKIDLIST",bidvect)
            hh.OverWrite("BANKSIZELIST",bszvect)
            hh.OverWrite("BANKNAMELIST",bnmvect)


    if (coef4!=0.0):
        for i in range( dat4.PutSize() ):
            ret.Add( dat4.PutPointer(i).Mul(coef4) )
        hht = dat4.PutHeaderPointer()
        if (hh.CheckKey("BANKIDLIST")==1) and (hht.CheckKey("BANKIDLIST")==1):
            bidvect=hh.PutInt4Vector("BANKIDLIST")
            bszvect=hh.PutInt4Vector("BANKSIZELIST")
            bnmvect=hh.PutStringVector("BANKNAMELIST")
            bidvectt=hht.PutInt4Vector("BANKIDLIST")
            bszvectt=hht.PutInt4Vector("BANKSIZELIST")
            bnmvectt=hht.PutStringVector("BANKNAMELIST")
            for i in range( bidvectt.size() ):
                bidvect.push_back( bidvectt[i] )
                bszvect.push_back( bszvectt[i] )
                bnmvect.push_back( bnmvectt[i] )
            hh.OverWrite("BANKIDLIST",bidvect)
            hh.OverWrite("BANKSIZELIST",bszvect)
            hh.OverWrite("BANKNAMELIST",bnmvect)

    return ret

########################################
def CopyData(first_run=10,last_run=-1,flag=0):
    """
    Copy EventData file from DAQ0 or DAQ1 into /data/XXX
    @param runno_from (int) First Run No of a measurement to be copied
    @param runno_to (int) Last Run No of a measurement to be copied
    @param flag  (int)  Flag for Copy(0) or Symbolic link(1) / default is Symbolic link or -1 for testing
    @retval None
    """
    BaseCom.CopyData( first_run, last_run, flag )

#########################################
def GetPH(dat=DAT, binSize=1):
    """
    Get Pulse Height Profile of PSD
    Each PSD pulse heignt profile is stored in header of ElementContaienrArray.
    @param  dat   (ElementContainerMatrix) Loaded ElementContainerMatrix.
    @param  binSize (UInt4)
    @retval ECS    ElementContainer or list of ElementContainers of pulse height profile
    """
    if type(dat)==list:
        import Manyo
        eca = Manyo.ElementContainerArray(dat[0].PutHeader())
        for a_dat in dat:
            eca_tmp = BaseCom.GetPH(a_dat,binSize)
            for i in range( eca_tmp.PutSize() ):
                eca.Add(eca_tmp.Put(i))
        return eca
    else:
        return BaseCom.GetPH(dat,binSize)

#########################################
def DetectorEffi(dat=DAT, dataFile="SUS304-3He-PSD-SAS-6atm.dat"):
    """
    DetectorEfficiency correction by using Manyo default functions
    @param dat [Def:DAT] (ElementContainerMatrix)
    @param dataFile (string)
    @return None
    """
    import Manyo.SAS as ms
    tt = ms.SASDetectorEfficiencyCorrection()
    if tt.LoadDataFile( dataFile ):
        tt.Execute( dat )
    else:
        raise UserWarning("Invalid Parameters")

#########################################
def SetRPMTMask2thetaByGrav(dat=DAT, Angle=0.25, isOutSide=True):
    """
    set masked-status to pixels which 2theta is inside of given angle with the center positions dropping by a gravity
    @param dat [Def:DAT]
    @param Angle   [deg]
    @param isOutSide (bool) set mask outside of given angle or not
    @return None
    """
    PP=ms.RPMTSetMaskBy2theta(dat, Angle, isOutSide)
    if PP.Status():
        PP.Execute()
    return
    """
    modeNo = 5
    runNo_st = dat.PutHeader().PutString(mu.UTSUSEMI_KEY_HEAD_RUNNUMBER)
    if len(runNo_st)==6:
        runNo = int(runNo_st)
    elif len(runNo_st)==9:
        runNo = int(runNo_st[3:])

    ANE = mu.UtsusemiAnaEnvironReader("environ_ana.xml")
    v_pfiles = ANE.PutParamFiles(runNo, modeNo, True)
    if v_pfiles.size() == 0:
        UserWarning("RunNo is invalid.")

    SDE = ms.SASDetectorInfoEditorRPMT(v_pfiles[1], True);
    b = SDE.PutIncidentGravityParam()
    v0 = dat(0,0).PutHeader().PutDoubleVector(mu.UTSUSEMI_KEY_HEAD_PIXELPOSITION)
    r_ang = v0[2] * math.tan(Angle / 180.0 * math.pi)
    ekey = dat(0,0).PutEKey()
    for i in range(dat.PutSize()):
        eca = dat(i)
        hh = eca.PutHeaderPointer()
        if hh.CheckKey(mu.UTSUSEMI_KEY_HEAD_MASKED) == 0:
            isMasked = False
        elif hh.PutInt4(mu.UTSUSEMI_KEY_HEAD_MASKED) == 1:
            isMasked = True
        else:
            isMasked = False
        if isMasked:
            continue

        cnt_ec = 0
        for j in range(eca.PutSize()):
            ec = eca(j)
            hh_ec = ec.PutHeaderPointer()
            if (hh_ec.CheckKey(mu.UTSUSEMI_KEY_HEAD_MASKED) == 0) or (hh.PutInt4(mu.UTSUSEMI_KEY_HEAD_MASKED) == 0):
                errv = ec.PutP(ekey)
                lamv = ec.Put("Lamb")
                pv = hh_ec.PutDoubleVector(mu.UTSUSEMI_KEY_HEAD_PIXELPOSITION)
                cnt_lam = 0
                for k in range(lamv.size()):
                    setMask = False
                    cy = -1.0 * b * lamv[k] * lamv[k]
                    d = math.sqrt((pv[0] * pv[0]) + (pv[1] - cy) * (pv[1] - cy) )
                    if isOutSide:
                        if d > r_ang:
                            setMask = True
                    else:
                        if d <= r_ang:
                            setMask = True
                    if setMask:
                        errv[k] = -1.0 * errv[k]
                        cnt_lam += 1
                if cnt_lam == lamv.size():
                    hh_ec.OverWrite(mu.UTSUSEMI_KEY_HEAD_MASKED, 1)
                    cnt_ec += 1

        if cnt_ec == eca.PutSize():
            hh.OverWrite(mu.UTSUSEMI_KEY_HEAD_MASKED, 1)
    """
#########################################
def SetRPMTMaskBy2theta(dat=DAT, detId=154, Pixel=140, Angle=0.25, isOutSide=True):
    """
    set masked-status to pixels which 2theta is inside of given angle
    @param dat [Def:DAT]
    @param detId
    @param Pixel
    @param Angle   [deg]
    @param isOutSide (bool)
    @return None
    """
    import Manyo
    import math
    SIH = Manyo.SearchInHeader()
    SIH.SetTarget(dat)
    SIH.SearchArray( "DETID", detId )
    ind_v = SIH.PutResultIndex(0)
    del SIH
    if ind_v.size()==0:
        raise UserWarning("Such detId is not found")

    hh_org=dat(ind_v[0]).Put(Pixel).PutHeader()
    p_org = hh_org.PutDoubleVector("PixelPosition")
    po_x = p_org[0]
    po_y = p_org[1]
    po_z = p_org[2]
    lo = math.sqrt( po_x*po_x + po_y*po_y + po_z*po_z )
    po_x = po_x/lo
    po_y = po_y/lo
    po_z = po_z/lo

    for i in range( dat.PutSize() ):
        eca = dat(i)
        cnt = 0
        for j in range( eca.PutSize() ):
            if i==ind_v[0] and j==Pixel:
                continue
            ec = dat(i,j)
            hh = ec.PutHeaderPointer()
            p_v=hh.PutDoubleVector("PixelPosition")
            p_x = p_v[0]
            p_y = p_v[1]
            p_z = p_v[2]
            lp = math.sqrt( p_x*p_x + p_y*p_y + p_z*p_z )
            p_x = p_x/lp
            p_y = p_y/lp
            p_z = p_z/lp
            theta_rad = math.acos( po_x*p_x + po_y*p_y + po_z*p_z )
            theta_deg = theta_rad*180.0/math.pi
            if isOutSide:
                if theta_deg > Angle:
                    hh.OverWrite("MASKED",1)
                    cnt += 1
            else:
                if theta_deg <= Angle:
                    hh.OverWrite("MASKED",1)
                    cnt += 1
        #print( "Masked count=%d"%cnt)
        if cnt==eca.PutSize():
            eca.PutHeaderPointer().OverWrite("MASKED",1)

#########################################
def IncohCalcFor3HeNSF(DAT1=DAT, DAT2=DAT, A=0.0, PHe=0.0, PolData="BL15_pol_vs_lambda.dat", is2ThetaCorr=True):
    """
    Separate Coherent and Incoherent components from given data set measured with 3He spin flipper.

    Return value is given as list with size of 2. To pick up each component data, use Cmm.ExecFunctionCode like below:
    CohDat = Cmm.ExecFunctionCode(Code="A[0]", A=CohInc, B=CohInc )
    IncDat = Cmm.ExecFunctionCode(Code="A[1]", A=CohInc, B=CohInc )

    @param DAT1 [Def:DAT1] (ElementContainerMatrix) Data for spin flipper on
    @param DAT2 [Def:DAT2] (ElementContainerMatrix) Data for spin flipper off
    @param A    (Double) A(lambda) value
    @param PHe  (Double) the pressure of 3He
    @param PolData (str) file path to text data for the polarization vs lambda
    @param is2ThetaCorr (bool) use A/cos(2theta)*lambda insteed of A*lambda
    @retval CohInc     list of coherent and incoherent components from given data [<Coh>, <Inc>]
    """
    IC=ms.IncohCalcFor3HeSpinFilter( DAT1, DAT2, A, PHe, is2ThetaCorr )
    if not IC.SetPolarizationTable( PolData ):
        raise UserWarning("Failed to load Polorization data.")

    DATc = Manyo.ElementContainerMatrix()
    DATic = Manyo.ElementContainerMatrix()
    if not IC.Execute(DATc, DATic):
        del IC
        raise UserWarning("Failed to execute")
    del IC
    return [DATc, DATic]

#########################################
def IncohCalcFor3HeNSFmul(DAT1=DAT, DAT2=DAT, A=0.0, PHe_p=0.0, PHe_m=0.0, Pmul=0.6, PolData="BL15_pol_vs_lambda.dat", is2ThetaCorr=True):
    """
    Separate Coherent and Incoherent components from given data set measured with 3He spin flipper (with coefficient for multi-scattering)

    Return value is given as list with size of 2. To pick up each component data, use Cmm.ExecFunctionCode like below:
    CohDat = Cmm.ExecFunctionCode(Code="A[0]", A=CohInc, B=CohInc )
    IncDat = Cmm.ExecFunctionCode(Code="A[1]", A=CohInc, B=CohInc )
    NSFDat = Cmm.ExecFunctionCode(Code="A[2]", A=CohInc, B=CohInc )
    SFDat = Cmm.ExecFunctionCode(Code="A[3]", A=CohInc, B=CohInc )

    @param DAT1 [Def:DAT1] (ElementContainerMatrix) Data for spin flipper on
    @param DAT2 [Def:DAT2] (ElementContainerMatrix) Data for spin flipper off
    @param A    (Double) A(lambda) value
    @param PHe_p  (Double) the pressure of 3He
    @param PHe_m  (Double) the pressure of 3He
    @param Pmul   (Double) the coefficient value for multi-scattering
    @param PolData (str) file path to text data for the polarization vs lambda
    @param is2ThetaCorr (bool) use A/cos(2theta)*lambda insteed of A*lambda
    @retval CohInc     list of coherent and incoherent components from given data [<Coh>, <Inc>]
    """
    IC=ms.IncohCalcFor3HeSpinFilter( DAT1, DAT2, A, PHe_p, PHe_m, is2ThetaCorr )
    if not IC.SetPolarizationTable( PolData ):
        raise UserWarning("Failed to load Polorization data.")

    DATc = Manyo.ElementContainerMatrix()
    DATic = Manyo.ElementContainerMatrix()
    DATnsf = Manyo.ElementContainerMatrix() # non-spin-flip
    DATsf = Manyo.ElementContainerMatrix()  # spin-flip

    if IC.SetMultiScatPval(Pmul):
        if not IC.Execute(DATc, DATic, DATnsf, DATsf):
            del IC
            raise UserWarning("Failed to execute")
    del IC
    return [DATc, DATic, DATnsf, DATsf]

#########################################
def IntegPixels(Target=DAT, PSD_min=1, PSD_max=1, Pixel_min=1, Pixel_max=1, isAve=True):
    """
    Put summation of intensity along Pixel
    @param Target [Def:DAT]   (ElementContainerMatrix)
    @param PSD_min   (int) lower limit of PSD-ID range
    @param PSD_max   (int) upper limit of PSD-ID range
    @param Pixel_min (int) lower limit of Pixel range
    @param Pixel_max (int) upper limit of Pixel range
    @param isAve     (bool) averaging or summation
    @retval EC
    """
    return BaseCom.IntegPixels(Target, PSD_min, PSD_max, Pixel_min, Pixel_max, isAve)

#########################################
# Dictionary for entry the name of functions
_functions = {
              "GetNeunetHistSAS":GetNeunetHistSAS,
              "GetNeunetHistSASWitoutCheckPulseId":GetNeunetHistSASWitoutCheckPulseId,
              "DataReductionMulti":DataReductionMulti,
              "SubtractBackMulti":SubtractBackMulti,
              "QzProjectionMulti":QzProjectionMulti,
              "GetAzimuthProfile":GetAzimuthProfile,
              "GetAzimuthProfileMulti":GetAzimuthProfileMulti,
              "IncohCalcFor3HeNSF":IncohCalcFor3HeNSF,
              "IncohCalcFor3HeNSFmul":IncohCalcFor3HeNSFmul,
              "SectorAverageByAnglesMulti":SectorAverageByAnglesMulti,
              "IntegPixels":IntegPixels,
              "Test":Test,
              "NormByBeamCurrent":NormByBeamCurrent,
              "getBeamCurrent":getBeamCurrent,
              "SaveDataToManyoBinary":SaveDataToManyoBinary,
              "LoadDataFromManyoBinary":LoadDataFromManyoBinary,
              "SaveDataToDump":SaveDataToDump,
              "LoadDataFromDump":LoadDataFromDump,
              "SaveDataToNeXus":SaveDataToNeXus,
              "GetDataFromNeXus":GetDataFromNeXus,
              "PrintObject":PrintObject,
              "DoMask":DoMask,
              "RemoveAllMask":RemoveAllMask,
              "MergeDataECM":MergeDataECM,
              "CopyData":CopyData,
              "GetPH":GetPH,
              "DetectorEffi":DetectorEffi,
              "SetRPMTMask2thetaByGrav":SetRPMTMask2thetaByGrav,
              "SetRPMTMaskBy2theta":SetRPMTMaskBy2theta
	      }

_functionsOrder = [
              "GetNeunetHistSAS",
              "DataReductionMulti",
              "SubtractBackMulti",
              "QzProjectionMulti",
              "GetAzimuthProfileMulti",
              "GetAzimuthProfile",
              "SectorAverageByAnglesMulti",
              "IntegPixels",
              "IncohCalcFor3HeNSF",
              "IncohCalcFor3HeNSFmul",
              "Test",
              "NormByBeamCurrent",
              "getBeamCurrent",
              "SaveDataToManyoBinary",
              "LoadDataFromManyoBinary",
              "SaveDataToDump",
              "LoadDataFromDump",
              "SaveDataToNeXus",
              "GetDataFromNeXus",
              "PrintObject",
              "DoMask",
              "RemoveAllMask",
              "MergeDataECM",
              "CopyData",
              "GetPH",
              "DetectorEffi",
              "SetRPMTMask2thetaByGrav",
              "SetRPMTMaskBy2theta"
    ]
