#!/usr/bin/python

from math import *
import numpy as np
import Manyo as m
import MovingAverage

####    linear combination of gaussian    ####
def dist(x, n, a, c, w):
    sum=0.0
    for i in range(n):
        sum = sum + a[i]*exp(-1.0*((x-c[i])/w[i])**2)
    return sum

####    sign function    ####
def sign(r):
    if r > 0.0:
        s = 1.0
    elif r == 0.0:
        s = 0.0
    else:
        s = -1.0
    return s

####    initialize an ElementContainer    ####
def initElementContainer(xmin, xmax, nDiv):

    bin = m.MakeDoubleVector(nDiv+1)
    delta = (xmax - xmin)/nDiv
    for i in range(nDiv+1):
        bin[i] = xmin + delta*i

    xc = m.MakeDoubleVector(nDiv)
    for i in range(nDiv):
        xc[i] = (bin[i] + bin[i+1])/2.0

    nPeak=1
    a=m.MakeDoubleVector(nPeak)
    c=m.MakeDoubleVector(nPeak)
    w=m.MakeDoubleVector(nPeak)
    a[0]=100000.0
    c[0]=7.5
    w[0]=2.5
    y = m.MakeDoubleVector(nDiv)
    e = m.MakeDoubleVector(nDiv)
    for i in range(nDiv):
        p = dist(xc[i], nPeak, a, c, w)
        q = sign(np.random.rand(1)-0.5)*(p/10.0)*sqrt(-1.0*log(np.random.rand(1)))
        y[i] = p + q
        e[i] = p/10.0

    ec = m.ElementContainer()
    ec.AddToHeader("run number", 1)
    ec.AddToHeader("level",      1)
    ec.AddToHeader("Inst.",      "manyo")
    ec.Add("TOF",       bin, "sec." )
    ec.Add("Intensity", y,   "count")
    ec.Add("Error",     e,   "count")
    ec.SetKeys("TOF", "Intensity", "Error")

    return ec

def outputElementContainer(ec):
    bin = ec.Put(ec.PutXKey())
    y   = ec.Put(ec.PutYKey())
    e   = ec.Put(ec.PutEKey())

    print str("No.").rjust(4), str("----------- bin -----------").rjust(27), str("xc").rjust(10), str("Intensity").rjust(23), str("error").rjust(23)
    for i in range(ec.PutSize(ec.PutYKey())):
         print str(i).rjust(4), "[", str(bin[i]).rjust(10), ",", str(bin[i+1]).rjust(10), ")", str((bin[i]+bin[i+1])/2.0).rjust(10), str(y[i]).rjust(23), str(e[i]).rjust(23)

####    plot    ####
def plot(src, dest):
    srcBin  = src.Put(src.PutXKey())
    srcY    = src.Put(src.PutYKey())
    destBin = dest.Put(dest.PutXKey())
    destY   = dest.Put(dest.PutYKey())

    count=0
    g=m.GnuplotInterface()
    g.e("set xrange[0: 15]")
    g.e("set yrange[0: 150000]")
    g.e("plot '-' using 1:2 with lines linewidth 1 title'%d', '-' using 1:3 with lines linewidth 4" %count)
    while 1:
        for i in range(srcY.size()):
            #print str( (srcBin[i]+srcBin[i+1])/2.0 ) + " " + str( srcY[i] )+ " " + str( destY[i] )
            g.e( str( (srcBin[i]+srcBin[i+1])/2.0 ) + " " + str( srcY[i] )+ " " + str( destY[i] ) )
        g.e("e")
        c=raw_input("")
        if c != "":
            break


####    main routine    ####
xmin = 0.0
xmax = 15.0
nDiv = 1500
src = initElementContainer(xmin, xmax, nDiv)
outputElementContainer(src)

domain = MovingAverage.Domain()
domain.setSource(src)
domain.setRange(xmin, xmax)
print "[", str(domain.getLowerBound()).rjust(10), ",", str(domain.getUpperBound()).rjust(10), "]"
print "[", str(domain.getLowerBoundID()).rjust(10), ",", str(domain.getUpperBoundID()).rjust(10), "]"
print
print "type of the domain", domain.getType()
#domain.setType(Domain.OO)
#print "type of the domain", domain.getType()

param = MovingAverage.ParamSet()
param.add(MovingAverage.MovingAverage.WINDOW_WIDTH,         111)
param.add(MovingAverage.MovingAverage.WINDOW_UPPER,          55)
param.add(MovingAverage.MovingAverage.USE_STRICT_DEFINITION,  0)
param.dump()

method = MovingAverage.MovingAverage()
param = method.setDefaultParam(src)
method.setDefaultParam(src).dump()
print "check param: ", method.checkParam(src, domain, param)

if method.checkParam(src, domain, param) :
    method.toInnerForm(src, domain, param)
    method.fit()
    method.eval()
    result = m.ElementContainer(src.PutHeader())
    method.toElementContainer(src, result)
    #result.dump()
    #outputElementContainer(result)
    plot(src, result)

